parity-governance is red on main, and the refresh paths that exist to fix it both refuse.
Current state
main at 071f432d2 fails two RepositoryBaselineTests:
test_checked_in_inventory_and_baseline_match_current_sources
test_checked_metadata_is_compact_v3_and_expands_losslessly
AssertionError: {'files': {'count': 490, ...}} != {'files': {'count': 493, ...}}
The checked-in authority in Tools/parity_twin_map.json records 490 scanned files. The tree actually has 493. Confirmed independently: parity_ledger._paths returns 263 Swift and 230 Kotlin, and 263 + 230 = 493.
What drifted
4453a089b (Lift Log) added three files that the Swift globs scan, without refreshing the authority:
Packages/StrandAnalytics/Sources/StrandAnalytics/LiftMetrics.swift
Packages/StrandImport/Sources/StrandImport/LiftProgramSheetImporter.swift
Packages/StrandImport/Sources/StrandImport/XlsxSheet.swift
Why nothing caught it
This is the interesting half. parity-governance triggers on:
Tools/issue_ref.py
Tools/parity_*.py
Tools/parity_*.json
Tools/tests/test_parity_*.py
Tools/tests/test_rr_legacy_preservation_contract.py
.github/workflows/parity-governance.yml
The authority is derived from Packages/** and android/**, and neither is in that list. So a pull request can invalidate the authority without ever running the check that guards it, and the next pull request that happens to touch Tools/parity_* inherits a red board it had nothing to do with.
Verified rather than assumed: the check is absent from the check list on the Lift Log pull request head AND from the post-merge push on 4453a089b. It did not run and go green, it never ran.
The daily 17 4 * * * cron is the existing backstop, and its own comment says as much: "so authority staleness is found on a schedule instead of by whoever next edits Tools/". Tonight's cron would have found this. A contributor found it first.
The deadlock
Both documented refresh paths refuse, from a clean main checkout:
$ python3 Tools/parity_ledger.py --refresh-derived
FAIL derived refresh rejected; snapshots restored
ERROR: Tools/parity_twin_map.json: base authority cannot be reproduced with the
current derivation; migration required
$ python3 Tools/parity_ledger.py --refresh-derived --repair-stale-base
FAIL derived refresh rejected; snapshots restored
ERROR: Tools/parity_twin_map.json: stale-base repair rejected because finding
identities differ from the exact base
Both roll back cleanly, which is correct behaviour. --repair-stale-base was added in #2212 for the previous generation of this problem (#2211); it does not cover this one, because Lift Log's three new files changed finding identities relative to the base as well as the file count.
A third attempt pinning --base 3c8bfe659, the last commit where the authority was reproducible, is running as this is filed; I will add the result.
Why I stopped rather than forcing it
The only remaining lever is --bootstrap-map --write-baseline, which rewrites the authority wholesale. The tool's own help says new semantic debt is governed by exact, manually reviewed typed dispositions, so a wholesale rewrite discards reviewed judgement to fix a file count. That is a decision for you, not something to slip quietly into a pull request that claims to repair a file count.
Impact
Correction: the trigger exclusion is deliberate, and my suggestion was wrong
My first version of this issue proposed adding the scanned Packages/** and android/** roots to the workflow trigger. That was wrong, and I am leaving the record rather than quietly deleting it.
The workflow header already documents the decision, and it already documents this exact failure:
Product changes are what invalidates it, and product changes are exactly what both filters exclude, so main could carry stale authority indefinitely with nothing red until some later PR touched Tools/ and inherited the whole accumulated drift.
That happened four times, and three landed on an outside contributor's PR that had caused none of it. The schedule finds it within a day, on main, where re-deriving is a two-minute maintainer action.
Deliberately a schedule rather than an unfiltered push: this suite is pinned NOT to run on product source (see test_core_tools_filter_covers_every_governance_tool_path, which asserts both filters and forbids product globs), and a periodic check keeps that true. See the history in #1534.
test_core_tools_filter_covers_every_governance_tool_path pins the path list exactly, asserts every non-.github path begins with Tools/, and carries explicit assertions against 'Packages/**/*.swift' and 'android/**/*.kt'. The guard exists to stop exactly the change I suggested.
So today is the fifth occurrence of a known, accepted trade, not a new hole. The trigger is not the bug.
What is actually new
The accepted remedy is "a two-minute maintainer action" on main. That action no longer works. Both documented refresh paths refuse, as recorded above, and --repair-stale-base was already the answer to the previous generation of this (#2211 / #2212).
That is the part that needs attention: the schedule can find the drift, and then nothing can clear it without --bootstrap-map --write-baseline, which discards the manually reviewed typed dispositions the tool's own help says govern semantic debt.
Concretely, the gap is a refresh path that can absorb new scanned files whose findings are new identities rather than changed values. Lift Log added three files and therefore three sets of identities that the exact base has never seen; --repair-stale-base is scoped to metadata drift within an otherwise-matching base, so it declines.
Scope of this issue
Narrowed to that: make the documented recovery work. Widening the trigger is out of scope and, per the header, not wanted.
parity-governanceis red onmain, and the refresh paths that exist to fix it both refuse.Current state
mainat071f432d2fails twoRepositoryBaselineTests:The checked-in authority in
Tools/parity_twin_map.jsonrecords 490 scanned files. The tree actually has 493. Confirmed independently:parity_ledger._pathsreturns 263 Swift and 230 Kotlin, and 263 + 230 = 493.What drifted
4453a089b(Lift Log) added three files that the Swift globs scan, without refreshing the authority:Why nothing caught it
This is the interesting half.
parity-governancetriggers on:The authority is derived from
Packages/**andandroid/**, and neither is in that list. So a pull request can invalidate the authority without ever running the check that guards it, and the next pull request that happens to touchTools/parity_*inherits a red board it had nothing to do with.Verified rather than assumed: the check is absent from the check list on the Lift Log pull request head AND from the post-merge push on
4453a089b. It did not run and go green, it never ran.The daily
17 4 * * *cron is the existing backstop, and its own comment says as much: "so authority staleness is found on a schedule instead of by whoever next edits Tools/". Tonight's cron would have found this. A contributor found it first.The deadlock
Both documented refresh paths refuse, from a clean
maincheckout:Both roll back cleanly, which is correct behaviour.
--repair-stale-basewas added in #2212 for the previous generation of this problem (#2211); it does not cover this one, because Lift Log's three new files changed finding identities relative to the base as well as the file count.A third attempt pinning
--base 3c8bfe659, the last commit where the authority was reproducible, is running as this is filed; I will add the result.Why I stopped rather than forcing it
The only remaining lever is
--bootstrap-map --write-baseline, which rewrites the authority wholesale. The tool's own help says new semantic debt is governed by exact, manually reviewed typed dispositions, so a wholesale rewrite discards reviewed judgement to fix a file count. That is a decision for you, not something to slip quietly into a pull request that claims to repair a file count.Impact
Tools/parity_*inherits the red until the authority is refreshed.Correction: the trigger exclusion is deliberate, and my suggestion was wrong
My first version of this issue proposed adding the scanned
Packages/**andandroid/**roots to the workflow trigger. That was wrong, and I am leaving the record rather than quietly deleting it.The workflow header already documents the decision, and it already documents this exact failure:
test_core_tools_filter_covers_every_governance_tool_pathpins the path list exactly, asserts every non-.githubpath begins withTools/, and carries explicit assertions against'Packages/**/*.swift'and'android/**/*.kt'. The guard exists to stop exactly the change I suggested.So today is the fifth occurrence of a known, accepted trade, not a new hole. The trigger is not the bug.
What is actually new
The accepted remedy is "a two-minute maintainer action" on main. That action no longer works. Both documented refresh paths refuse, as recorded above, and
--repair-stale-basewas already the answer to the previous generation of this (#2211 / #2212).That is the part that needs attention: the schedule can find the drift, and then nothing can clear it without
--bootstrap-map --write-baseline, which discards the manually reviewed typed dispositions the tool's own help says govern semantic debt.Concretely, the gap is a refresh path that can absorb new scanned files whose findings are new identities rather than changed values. Lift Log added three files and therefore three sets of identities that the exact base has never seen;
--repair-stale-baseis scoped to metadata drift within an otherwise-matching base, so it declines.Scope of this issue
Narrowed to that: make the documented recovery work. Widening the trigger is out of scope and, per the header, not wanted.