What
Every rule cites an LCI document, and LCI republishes its checklist and common-mistakes PDFs each year under new URLs. make audit-sources checks that links resolve; nothing checks that the content behind a link still says what the corpus retained. scripts/watch_sources.py (maintainer-run, networked, never in make verify or check) re-fetches each corpus/manifest.json document, compares normalized text against the retained text, and classifies each as unchanged, changed, or unverifiable by kind (transport failure versus 404/410). For a changed source it reports which retained passages, and therefore which rules' source and guidelines bindings, no longer occur verbatim, and writes a dated review record. It adopts nothing.
Why it matters
A rule explained from a superseded checklist is the confident staleness this portfolio is built to catch. permit-bearings runs exactly this watch weekly for HCD and statute sources, with converging issues and the transport versus not_found distinction of its ADR 0005; this proposes the same pattern here so the corpus that grounds ai explain cannot silently outlive its source. The default path is untouched: the watch is a maintainer tool whose output is a dated file, not a change to any rule.
Scope
scripts/watch_sources.py with --offline-cache for replay; output docs/audits/source-watch-YYYY-MM-DD.json with per-document status, hash, failure kind, and surviving and lost passage ids.
rules list --source-status FILE shows each rule's source status from a watch file.
- Optional scheduled workflow uploading the watch file as an artifact and commenting on one stable issue (never a new issue per run), modeled on permit-bearings'
currency.yml.
corpus/README.md procedure for adopting a changed source: re-retrieve, rebuild passages, re-run the grounding eval.
Out of scope
- Automatic corpus rebuilds or rule edits.
- Any effect on
check output or exit codes.
Done when
- Against a recorded cache where one document changed, the watch names the document, the passages lost, and the rules bound to them; unchanged documents are listed as unchanged.
- A 404 is recorded as
not_found, a timeout as transport, and neither marks a passage lost.
- The classifier runs offline over fixtures in the test suite; no test opens a socket.
Pointers
Proposed with AI assistance.
What
Every rule cites an LCI document, and LCI republishes its checklist and common-mistakes PDFs each year under new URLs.
make audit-sourceschecks that links resolve; nothing checks that the content behind a link still says what the corpus retained.scripts/watch_sources.py(maintainer-run, networked, never inmake verifyorcheck) re-fetches eachcorpus/manifest.jsondocument, compares normalized text against the retained text, and classifies each as unchanged, changed, or unverifiable by kind (transport failure versus 404/410). For a changed source it reports which retained passages, and therefore which rules'sourceandguidelinesbindings, no longer occur verbatim, and writes a dated review record. It adopts nothing.Why it matters
A rule explained from a superseded checklist is the confident staleness this portfolio is built to catch.
permit-bearingsruns exactly this watch weekly for HCD and statute sources, with converging issues and thetransportversusnot_founddistinction of its ADR 0005; this proposes the same pattern here so the corpus that groundsai explaincannot silently outlive its source. The default path is untouched: the watch is a maintainer tool whose output is a dated file, not a change to any rule.Scope
scripts/watch_sources.pywith--offline-cachefor replay; outputdocs/audits/source-watch-YYYY-MM-DD.jsonwith per-document status, hash, failure kind, and surviving and lost passage ids.rules list --source-status FILEshows each rule's source status from a watch file.currency.yml.corpus/README.mdprocedure for adopting a changed source: re-retrieve, rebuild passages, re-run the grounding eval.Out of scope
checkoutput or exit codes.Done when
not_found, a timeout astransport, and neither marks a passage lost.Pointers
scripts/check_rule_sources.py,scripts/build_corpus.py,corpus/manifest.json,src/ceqa_preflight/ai/corpus.pypermit-bearings:src/permit_pathways/harness/watch.py,.github/workflows/currency.yml,docs/adr/0005-separate-a-withdrawn-citation-from-an-unreachable-source.mdProposed with AI assistance.