#!/usr/bin/env python3 """Repoint decisions/ PATH references to the governance/ DQR tree (pql migration, Phase 1). Operates on the active instruction layer (agent + skill markdown). Ordered, literal string replacements — most-specific first, bare `decisions/` last so per-file paths keep their decisions/ subdir. Does NOT touch command references (tooling/db/decision*, decisions-sync) — those belong to the Phase 4 command cutover. Does NOT touch historical archives (docs/sprints, docs/discussions, docs/workshops) or the separate whatsinagame/ template distribution. Default is a dry run. Pass --apply to write. """ import glob import re import sys APPLY = "--apply" in sys.argv # Ordered: specific globs/files first, per-domain D files next, bare dir LAST. # The bare-dir rule is a regex with a negative lookbehind so it never re-matches # the `decisions/` inside a `governance/decisions/...` path created by an earlier # rule (which would corrupt it to `governance/governance/...`). REPLACEMENTS = [ ("decisions/questions-*.md", "governance/questions/*.md"), ("decisions/*.md", "governance/**/*.md"), ("decisions/README.md", "governance/README.md"), ("decisions/questions.md", "governance/README.md"), ("decisions/rejected.md", "governance/rejected/"), ("decisions/architecture.md", "governance/decisions/architecture.md"), ("decisions/content.md", "governance/decisions/content.md"), ("decisions/economics.md", "governance/decisions/economics.md"), ("decisions/perception.md", "governance/decisions/perception.md"), ("decisions/process.md", "governance/decisions/process.md"), ("decisions/scope.md", "governance/decisions/scope.md"), (re.compile(r"(? governance/). The # absolute paths below are the canonical main checkout where it was run; kept # committed for provenance. TARGETS = sorted(set( glob.glob("/var/mnt/data/projects/settled-reach/main/.claude/agents/*.md") + glob.glob("/var/mnt/data/projects/settled-reach/main/.claude/skills/**/*.md", recursive=True) )) def transform(text): changes = [] for old, new in REPLACEMENTS: if isinstance(old, re.Pattern): n = len(old.findall(text)) if n: text = old.sub(new, text) changes.append((old.pattern, new, n)) elif old in text: n = text.count(old) text = text.replace(old, new) changes.append((old, new, n)) return text, changes def main(): print(f"=== repath_references.py ({'APPLY' if APPLY else 'DRY-RUN'}) ===\n") total = 0 for path in TARGETS: with open(path, encoding="utf-8") as fh: text = fh.read() new_text, changes = transform(text) if not changes: continue rel = path.split("/main/", 1)[-1] print(rel) for old, new, n in changes: print(f" {n}x {old!r} -> {new!r}") total += n if APPLY: with open(path, "w", encoding="utf-8") as fh: fh.write(new_text) print(f"\n{total} replacement(s)." + ("" if APPLY else " (dry run — pass --apply)")) if __name__ == "__main__": main()