Problem
The Queen issue-proof reader (Corona and Memory) is meant to fail closed: a closed issue is honey only while exact canonical evidence is observed at the current default-branch HEAD. A static review of apps/website found two paths where an old positive verdict survives an explicit reset or a failed refresh. Both paths are in the shared infrastructure that #1371 connects for Memory; the review does not claim #1371 introduced them.
- A failed refresh keeps the old positive row in every layer above the reader.
queenRepositoryWorld.ts loadWorldIssueDetailsCached: fresh=true resets only the repository proof. If the GitHub issue read then fails, the old detailsCache row (coverage t27) stays, and the next non-fresh call inside the 60 s TTL returns it.
QueenCellStage.tsx reports the error locally but never withdraws the row it previously sent through onObserved.
QueenCatalogHive.tsx keeps the previous observed rows when the world reload fails; QueenUniverse.tsx RepositoryWorld keeps the previous snapshot rows. The map keeps painting coverage t27.
- An older in-flight check can repopulate a cleared cache. In
queenIssueProof.ts, request A starts verifying HEAD₁; invalidateIssueProof runs and request B fails (unknown); A then finishes and unconditionally runs cache.set, so later reads get A's proof with a fresh observedAt. Deleting the Map entry does not cancel A, and the abort check runs only after the cache write.
Expected behaviour
- A verdict may be written to a cache or returned as positive only when (verified) ∧ (the request is still the current generation for that repository) ∧ (the caller has not aborted). Anything else is
unknown.
invalidateIssueProof and the start of every new verification advance a per-repository generation; a superseded check ends as unknown. Concurrent callers of the same generation share one in-flight check, so two views of the same world cannot disagree.
- A refresh (explicit or after TTL) first removes the old details row; a failed refresh never leaves a positive row behind. On failure every observed layer (cell stage → hive
observed, universe snapshot) withdraws coverage/proof and keeps only the lifecycle as the last observation.
- Ordinary delay inside the agreed TTL after the last successful observation stays acceptable; the bug is a proof that comes back after an explicit reset or a failed refresh.
Spec first
apps/website/specs/queen/issue_proof_refresh.t27: a sealed truth table for publishing a positive (verified × current generation × live caller) and for keeping an observed positive (refresh succeeded × latest request). Generated TS constants and conformance vectors are consumed by the reader, the details cache and the UI layers.
Done when
Review source: owner-provided static review of head ecc3708; the four affected files are byte-identical at 846ccb3.
Problem
The Queen issue-proof reader (Corona and Memory) is meant to fail closed: a closed issue is honey only while exact canonical evidence is observed at the current default-branch HEAD. A static review of
apps/websitefound two paths where an old positive verdict survives an explicit reset or a failed refresh. Both paths are in the shared infrastructure that #1371 connects for Memory; the review does not claim #1371 introduced them.queenRepositoryWorld.tsloadWorldIssueDetailsCached:fresh=trueresets only the repository proof. If the GitHub issue read then fails, the olddetailsCacherow (coveraget27) stays, and the next non-fresh call inside the 60 s TTL returns it.QueenCellStage.tsxreports the error locally but never withdraws the row it previously sent throughonObserved.QueenCatalogHive.tsxkeeps the previousobservedrows when the world reload fails;QueenUniverse.tsxRepositoryWorldkeeps the previous snapshot rows. The map keeps painting coveraget27.queenIssueProof.ts, request A starts verifying HEAD₁;invalidateIssueProofruns and request B fails (unknown); A then finishes and unconditionally runscache.set, so later reads get A's proof with a freshobservedAt. Deleting the Map entry does not cancel A, and the abort check runs only after the cache write.Expected behaviour
unknown.invalidateIssueProofand the start of every new verification advance a per-repository generation; a superseded check ends asunknown. Concurrent callers of the same generation share one in-flight check, so two views of the same world cannot disagree.observed, universe snapshot) withdraws coverage/proof and keeps only the lifecycle as the last observation.Spec first
apps/website/specs/queen/issue_proof_refresh.t27: a sealed truth table for publishing a positive (verified × current generation × live caller) and for keeping an observed positive (refresh succeeded × latest request). Generated TS constants and conformance vectors are consumed by the reader, the details cache and the UI layers.Done when
scripts/issue-proof-from-spec.mjs; executable consumer tests reproduce both scenarios with deferred promises (fail before the fix, pass after) for Corona and Memory readers and for the details cache.check:queen-issue-proof,check:queen-worlds,check:queen-catalog, typecheck ratchet and the production build pass; CI green on the final SHA.Review source: owner-provided static review of head ecc3708; the four affected files are byte-identical at 846ccb3.