Why
#3183 / PR #3203 split the drift allowlist's single reason field into divergence,
divergence_reviewed and fingerprint_refreshed — and then populated the two new fields with the
same blanket date on every pair, which re-creates the exact false assertion the split existed to
remove, now in a machine-readable field.
#3183 §4 stated the problem: one field carried two different events — a mechanical fingerprint refresh
when Renovate moves a pinned SHA, and a judgement that two files SHOULD differ — so "the file asserts
the second whenever the first happens". The remedy was to make a hash refresh unable to touch the
review claim.
Measured at HEAD a377fd30 over config/template-drift-allowlist.txt:
sections: 20
divergence_reviewed: {'2026-08-23': 19, '2026-08-24': 1}
fingerprint_refreshed: {'2026-08-23': 19, '2026-08-24': 1}
The two fields are identical for all twenty pairs, and the coupling has already survived one day of
real traffic: the single pair whose fingerprint moved on 2026-08-24 had its divergence_reviewed
moved with it. Nineteen pairs assert a 2026-08-23 review while their own divergence prose dates the
judgement elsewhere — [pair.3] says "re-reviewed 2026-06-20", [pair.5] "updated 2026-08-05",
[pair.10] "re-baselined 2026-06-30", [pair.15] "re-baselined 2026-07-14".
The gate cannot see any of this. tests/scripts/test_template_drift_allowlist.py:12 asserts only
non-emptiness:
assert divergence and "Existing reviewed baseline drift" not in divergence
assert reviewed
assert refreshed
A blanket divergence_reviewed = <today> on every pair passes it, and so would a value that moves in
lockstep with fingerprint_refreshed forever. The field has no drain: nothing decrements it, nothing
can distinguish a real re-review from a copy of the refresh date, and the reader is told the whole
file was re-reviewed today whenever any one SHA moves.
Also worth folding in: #3183's named live gate
tests/scripts/test_sync_manifest_docs.py::test_manifest_issue_references_are_open is currently
vacuous. It only iterates citations explicitly marked open:, and .github/sync-manifest.yml
contains five resolved: citations and zero open: ones, so the node-id the acceptance criterion
names verifies nothing even with a token present. The strict check that does the work lives under a
different name, test_manifest_issue_citations_are_explicitly_stateful.
Full trace: Code/Audits/Workflows/2026-08-24-implementation-verification.md.
Scope
config/template-drift-allowlist.txt (set each pair's divergence_reviewed to the date its own
divergence prose records), scripts/check_template_drift.py (surface the divergence between the two
dates), and tests/scripts/test_template_drift_allowlist.py (assert the property, not the presence).
Plus the vacuous-gate rename in tests/scripts/test_sync_manifest_docs.py.
Non-Goals
- Do NOT add a human review, approval, sign-off, or recurring owner step. The refresh traffic is
agent-borne and must stay that way; this is about what the file is allowed to CLAIM, not about
adding a reviewer.
- Do NOT rewrite the twenty
divergence rationales. Read the date out of each one; leave the prose.
- Do NOT delete
divergence_reviewed. A field that cannot be trusted is worse than none, but the
answer is making it checkable.
- Do NOT make the drift check fail on a stale
divergence_reviewed. Reporting a stale review date must
never block a fingerprint refresh, or the gate blocks its own drain.
- Do NOT change any
main_sha256 or template_sha256 value, or the drift comparison semantics.
- Do NOT introduce a new config format for the allowlist; it stays a
configparser file.
- A scaffolded stub, a TODO, a renamed file, or a test that passes without exercising the change
does NOT count as done and is a failure of this issue.
Tasks
Acceptance Criteria
Why
#3183 / PR #3203 split the drift allowlist's single
reasonfield intodivergence,divergence_reviewedandfingerprint_refreshed— and then populated the two new fields with thesame blanket date on every pair, which re-creates the exact false assertion the split existed to
remove, now in a machine-readable field.
#3183 §4 stated the problem: one field carried two different events — a mechanical fingerprint refresh
when Renovate moves a pinned SHA, and a judgement that two files SHOULD differ — so "the file asserts
the second whenever the first happens". The remedy was to make a hash refresh unable to touch the
review claim.
Measured at
HEAD a377fd30overconfig/template-drift-allowlist.txt:The two fields are identical for all twenty pairs, and the coupling has already survived one day of
real traffic: the single pair whose fingerprint moved on 2026-08-24 had its
divergence_reviewedmoved with it. Nineteen pairs assert a 2026-08-23 review while their own
divergenceprose dates thejudgement elsewhere —
[pair.3]says "re-reviewed 2026-06-20",[pair.5]"updated 2026-08-05",[pair.10]"re-baselined 2026-06-30",[pair.15]"re-baselined 2026-07-14".The gate cannot see any of this.
tests/scripts/test_template_drift_allowlist.py:12asserts onlynon-emptiness:
A blanket
divergence_reviewed = <today>on every pair passes it, and so would a value that moves inlockstep with
fingerprint_refreshedforever. The field has no drain: nothing decrements it, nothingcan distinguish a real re-review from a copy of the refresh date, and the reader is told the whole
file was re-reviewed today whenever any one SHA moves.
Also worth folding in: #3183's named live gate
tests/scripts/test_sync_manifest_docs.py::test_manifest_issue_references_are_openis currentlyvacuous. It only iterates citations explicitly marked
open:, and.github/sync-manifest.ymlcontains five
resolved:citations and zeroopen:ones, so the node-id the acceptance criterionnames verifies nothing even with a token present. The strict check that does the work lives under a
different name,
test_manifest_issue_citations_are_explicitly_stateful.Full trace:
Code/Audits/Workflows/2026-08-24-implementation-verification.md.Scope
config/template-drift-allowlist.txt(set each pair'sdivergence_reviewedto the date its owndivergenceprose records),scripts/check_template_drift.py(surface the divergence between the twodates), and
tests/scripts/test_template_drift_allowlist.py(assert the property, not the presence).Plus the vacuous-gate rename in
tests/scripts/test_sync_manifest_docs.py.Non-Goals
agent-borne and must stay that way; this is about what the file is allowed to CLAIM, not about
adding a reviewer.
divergencerationales. Read the date out of each one; leave the prose.divergence_reviewed. A field that cannot be trusted is worse than none, but theanswer is making it checkable.
divergence_reviewed. Reporting a stale review date mustnever block a fingerprint refresh, or the gate blocks its own drain.
main_sha256ortemplate_sha256value, or the drift comparison semantics.configparserfile.does NOT count as done and is a failure of this issue.
Tasks
divergence_reviewedinconfig/template-drift-allowlist.txtto the date stated in that pair's owndivergencetext, leavingfingerprint_refreshedat the date the hashes last moved.divergence_reviewedage to the report emitted byscripts/check_template_drift.py, printed beside each allowlisted pair, so a stale review date is visible where the pair is read.scripts/check_template_drift.pycounting pairs whosedivergence_reviewedequals theirfingerprint_refreshed, which is the signature of a coupled bump.tests/scripts/test_template_drift_allowlist.pywith an assertion that fewer than half the pairs share an identicaldivergence_reviewedvalue, so a blanket stamp fails.test_divergence_reviewed_is_not_a_copy_of_fingerprint_refreshedtotests/scripts/test_template_drift_allowlist.pyasserting no pair has the two dates equal unless itsdivergencetext names that same date.tests/scripts/test_template_drift_allowlist.pythat extracts the date from eachdivergencestring and asserts it matches that pair'sdivergence_reviewed.test_manifest_issue_citations_are_explicitly_statefulintests/scripts/test_sync_manifest_docs.pytotest_manifest_issue_references_are_openand give the network-gated live check a name that says it only checksopen:citations.Acceptance Criteria
python3 -m pytest tests/scripts/test_template_drift_allowlist.py::test_divergence_reviewed_is_not_a_copy_of_fingerprint_refreshed -qexits 0.python3 -m pytest tests/scripts/test_template_drift_allowlist.py::test_every_pair_states_its_divergence -qexits 0 and its assertions compare the extracted prose date againstdivergence_reviewedrather than testing for a non-empty string.divergence_reviewedinconfig/template-drift-allowlist.txtto today's date;python3 -m pytest tests/scripts/test_template_drift_allowlist.py -qmust FAIL naming both tests. Revert the file; both must pass. Quote both transcripts as raw pytest output in the PR body.fingerprint_refreshedand itsdivergence_reviewedtogether; the named gate must FAIL. Bump onlyfingerprint_refreshed; it must pass. Quote both transcripts as raw pytest output.python3 scripts/check_template_drift.pyexits 0 and reports 20 pairs with 0 unallowlisted, unchanged by the metadata edits.python3 scripts/check_template_drift.pyoutput states how many pairs havedivergence_reviewedequal tofingerprint_refreshed.python3 -m pytest tests/scripts -qexits 0 and the skipped count does not increase.