mirror of
https://github.com/Imbad0202/academic-research-skills.git
synced 2026-09-14 13:51:17 +08:00
edee5d5694
Reviewers flagged 3 must-fix + 3 minor items on commits365826d+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.
85 lines
2.6 KiB
Python
Executable File
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())
|