Bind the cached signature verdict to the keyring that produced it - #655
Merged
Conversation
CommitLore — record lintTrailers: clean — 1 commit in Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR. |
The index stores `signature_status` from `%G?`, and `%G?` is not a property of the repository. It is the verdict of whichever process ran `git log`, and it depends on the keys that process could reach. An index warmed where the signing keys were unreachable therefore keeps answering `claim` after they come back, and the same record grades `directive` through `--no-index` at the same moment, from the same build (#653). The cache is not the problem; a cache that cannot say which world it answered about is. Signature mode now records an identifier for the keys the verifier could see, and a reader whose keys differ treats the index as needing a rebuild. ADR-0003 already makes that the ordinary answer: the index is derived, so there is no unrecoverable reason, only rebuild reasons. Only signature mode pays anything. `signatureVerifierGeneration` returns null when the setting is off, and the setting is opt-in — it is also the only place where a `%G?` can decide whether a record directs an agent. Blast: module Undo: easy Certainty: firm Ruled-out: memoize the generation per process | a long-running server would then keep grading against the keyring it started with, which is the shelf-life defect just removed from the MCP capture gate Ruled-out: stop caching signature_status | it is read per graded record, and recomputing it per query costs a git log the index exists to avoid Ruled-out: assert that two routes agree | that is the symptom, and any change making them agree — including one that stops the scan path grading at all — would satisfy it while the stale verdict remained Limit: the generation identifies the keys the verifier can list, not whether git would reach the same verdict for other reasons; a signature that fails for expiry or revocation is outside what this binds Provenance: authored Record-Id: r-keyringgen653 Verified: RED on main at test/index-signature-generation.test.ts:131 with the --no-index guard passing, GREEN after; negative control — disabling the generation check reproduces "expected 'claim' to be 'directive'", restoring it passes; 282 cases across index-db, query, signer-authority, doctor and the new file; cdeb-smoke A/B measured 93.32s with the check against 92.12s without; docker linux/amd64 build and artifact:manifest; artifact:verify bf41f0ff; 280 files in dist
MongLong0214
force-pushed
the
fix-f003-route-grade
branch
from
August 14, 2026 09:56
d19168b to
f85775e
Compare
This was referenced Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the cause behind F-003, recorded as #653. Not a close of #631 — that finding has its own acceptance and is discussed below.
The defect
The index stores
signature_statusfrom%G?, and%G?is not a property of the repository. It is the verdict of whichever process rangit log, and it depends on the keys that process could reach.Steps 2 and 3 are the same repository, the same record, the same moment and the same binary.
What the test asserts, and why not the obvious thing
The regression asserts the cause — a cached verdict does not outlive the keyring that produced it — rather than the symptom that two routes disagree. The symptom version would go green for the wrong reason: any change that happens to make the routes agree, including one that stopped the scan path grading at all, would satisfy it while the stale verdict remained.
RED on
main, at the final assertion, with the--no-indexguard passing first so a broken fixture cannot be mistaken for the defect:Negative control: disabling the generation check reproduces that exact failure; restoring it passes.
The fix
Signature mode records an identifier for the keys the verifier could see, in
meta. A reader whose keys differ gets a rebuild reason — which ADR-0003 already makes the ordinary answer, since the index is derived and has no unrecoverable states. No schema change: the existingmetatable and the existinghealthProblem→ rebuild path carry it.A verifier that cannot list keys at all gets its own generation. It grades differently from one that can, and saying so is the point.
Cost, measured
gpg --list-keysaverages 6.2ms, and it runs once per index open, only in signature mode — which is opt-in.cdeb-smokeA/B: 93.32s with the check, 92.12s without, a 1.3% difference on the heaviest file in the suite.Memoizing per process would remove even that, and is deliberately not done: a long-running server would then keep grading against the keyring it started with, which is the same shelf-life defect just removed from the MCP capture gate in #641.
On #631
#631 was attributed to a stale runtime, and #644 makes the surfaces converge. That is necessary and not sufficient — the reproduction above needs one build. This closes the cache half; #631 should stay open until its own acceptance is met.
Verification
282 cases across
index-db,query,signer-authority,doctorand the new file. Full suite: 3067 passed, withcdeb-smoketiming out under parallel load and passing in 93s when run alone — the A/B above shows the check is not the cause. Canonical rebuildbf41f0ff, 280 files in dist.