Files
imbad0202__academic-researc…/scripts/check_prisma_trAIce_freshness.py
Imbad0202 edee5d5694 fix(task11-12): simplify review findings — 5 fixes + 1 new test
Reviewers flagged 3 must-fix + 3 minor items on commits 365826d + 7124342.

Important:
- check_prisma_trAIce_freshness.py: catch yaml.YAMLError (previously
  unhandled — malformed YAML would surface as a traceback rather than a
  clean ERROR: line). Added test_malformed_yaml_fails_cleanly covering
  this path (26 tests total, all green).
- Script's upstream_source fallback string was the repo slug
  'cqh4046/PRISMA-trAIce'; the real frontmatter stores the full URL, and
  the fallback should match that shape for user clarity.
- PERFORMANCE.md attribution was imprecise: "ARS does not persist session
  state inside Claude Code" conflates ARS with Claude Code's own session
  mechanism. Rewrite as "ARS does not maintain its own orchestrator state
  between sessions."

Minor:
- Remove dead 'import subprocess' in test file (unused; run_script
  handles subprocess).
- Remove opaque '# Non-blocking: exit 0 per E6 in spec' comment; the
  module docstring already states non-blocking semantics.
- PERFORMANCE.md v3.4.0 cost table: align column headers with the main
  cost table above (Skill / Mode, Input Tokens, Output Tokens, Estimated
  Cost — title-case) and add the "+" prefix to deltas + cross-reference
  the 15K-word / 60-ref estimate basis.
2026-04-20 17:33:01 +08:00

85 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""Warn when shared/prisma_trAIce_protocol.md is older than 180 days.
Non-blocking: exit 0 even on stale, but print warning to stderr.
Exit 1 only on parse error (missing or malformed snapshot_date).
Usage:
python scripts/check_prisma_trAIce_freshness.py [path]
Default path: shared/prisma_trAIce_protocol.md (relative to repo root).
"""
from __future__ import annotations
import argparse
import sys
from datetime import date, datetime
from pathlib import Path
import yaml
DEFAULT_PATH = Path(__file__).resolve().parent.parent / "shared" / "prisma_trAIce_protocol.md"
STALE_THRESHOLD_DAYS = 180
def extract_frontmatter(text: str) -> dict:
"""Extract YAML frontmatter between opening and closing '---' fences."""
if not text.startswith("---"):
raise ValueError("No opening '---' fence")
lines = text.splitlines()
end_idx = None
for i in range(1, len(lines)):
if lines[i].strip() == "---":
end_idx = i
break
if end_idx is None:
raise ValueError("No closing '---' fence")
fm_text = "\n".join(lines[1:end_idx])
data = yaml.safe_load(fm_text)
if not isinstance(data, dict):
raise ValueError("Frontmatter is not a mapping")
return data
def parse_snapshot_date(fm: dict) -> date:
raw = fm.get("snapshot_date")
if not raw:
raise ValueError("snapshot_date missing")
if isinstance(raw, date):
return raw
try:
return datetime.strptime(str(raw), "%Y-%m-%d").date()
except ValueError as exc:
raise ValueError(f"snapshot_date malformed: {raw}") from exc
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("path", type=Path, nargs="?", default=DEFAULT_PATH)
args = parser.parse_args()
try:
text = args.path.read_text(encoding="utf-8")
fm = extract_frontmatter(text)
snapshot = parse_snapshot_date(fm)
except (FileNotFoundError, ValueError, yaml.YAMLError) as exc:
print(f"ERROR: {exc}", file=sys.stderr)
return 1
age_days = (date.today() - snapshot).days
if age_days > STALE_THRESHOLD_DAYS:
print(
f"WARNING: prisma_trAIce_protocol.md snapshot is {age_days} days old "
f"(threshold {STALE_THRESHOLD_DAYS}). Upstream may have updated — "
f"please review {fm.get('upstream_source', 'https://github.com/cqh4046/PRISMA-trAIce')} "
f"and re-sync if needed. (STALE status surfaced; non-blocking.)",
file=sys.stderr,
)
else:
print(f"OK: snapshot is {age_days} days old (current)")
return 0
if __name__ == "__main__":
sys.exit(main())