diff --git a/scripts/friction-scan.py b/scripts/friction-scan.py index 69481c6..c1a8ae6 100644 --- a/scripts/friction-scan.py +++ b/scripts/friction-scan.py @@ -16,6 +16,9 @@ import re REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) FRICTION = os.path.join(REPO_ROOT, "docs", "FRICTION.md") +TAG_RE = re.compile(r"`\[(friction|gotcha|recurring|unused)\]`") +DATE_RE = re.compile(r"(\d{4})-(\d{2})-(\d{2})") + def extract_open_section(text): """Return the body between '## Open signals' and the next '## ' heading.""" @@ -59,5 +62,27 @@ def split_signals(section): return [s for s in signals if s] +def parse_signal(raw, today): + """Turn one raw signal block into a structured dict.""" + tag_m = TAG_RE.search(raw) + date_m = DATE_RE.search(raw) + if date_m: + first_seen = date_m.group(0) + seen = datetime.date(int(date_m.group(1)), int(date_m.group(2)), int(date_m.group(3))) + age_days = (today - seen).days + else: + first_seen = None + age_days = None + return { + "tag": tag_m.group(1) if tag_m else None, + "first_seen": first_seen, + "age_days": age_days, + "recurrence_count": 1, # refined in Task 3 + "referenced_paths": [], # filled in Task 3 + "still_exists": True, # filled in Task 3 + "text": " ".join(raw.split()), + } + + if __name__ == "__main__": # pragma: no cover (filled in Task 4) pass diff --git a/tests/test_friction_scan.py b/tests/test_friction_scan.py index 3fcc4d8..2f995d7 100644 --- a/tests/test_friction_scan.py +++ b/tests/test_friction_scan.py @@ -38,3 +38,24 @@ def test_split_signals_finds_two_items_and_joins_continuations(): assert len(signals) == 2 assert "continuation line two" in signals[0] assert signals[1].startswith("`[friction]`") + + +import datetime + +TODAY = datetime.date(2026, 6, 15) + + +def test_parse_signal_extracts_tag_and_date_and_age(): + raw = fs.split_signals(fs.extract_open_section(SAMPLE))[0] + sig = fs.parse_signal(raw, TODAY) + assert sig["tag"] == "gotcha" + assert sig["first_seen"] == "2026-06-01" + assert sig["age_days"] == 14 + assert "First thing" in sig["text"] + + +def test_parse_signal_handles_missing_date(): + sig = fs.parse_signal("`[unused]` **No date here** something", TODAY) + assert sig["tag"] == "unused" + assert sig["first_seen"] is None + assert sig["age_days"] is None