Skip to content

Adversarial review: a cached summary still fetched the reader's identifiers - #284

Merged
adamjohnwright merged 1 commit into
mainfrom
011-phase7-review
Sep 20, 2026
Merged

adamjohnwright merged 1 commit into
mainfrom
011-phase7-review

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Follow-up review of #283. Builds on it, so merge that first.

The cache did nothing for the path it should protect most

The lookup happened after the disclosure fetch. So every reload of an already-summarised analysis went to the Analysis Service for the reader's unmatched identifiers and then discarded them.

Not a disclosure beyond what they chose — but a pointless request on the one endpoint where pointless requests are worth avoiding, repeated on every reload.

The fix, and an asymmetry worth understanding

The lookup now precedes the fetch, under the tier the reader asked for, while the write still uses the tier that applied.

That asymmetry is deliberate. A request whose disclosure failed stores an aggregate summary under aggregate — so the next disclosing request misses, and gets another attempt at the identifiers rather than being served the fallback forever. Both directions are tested.

One thing the review confirmed rather than changed

The analysis result is fetched on every request, before the cache is consulted, and that looks like waste. It is what keeps gone correct: a release deletes the analysis, and a reader must be told to re-run rather than handed a confident summary of something that no longer exists.

A cache that skipped the fetch would serve stale summaries of deleted results indefinitely. Now pinned by a test, so nobody optimises it away.

Verified by sabotage, with the sabotage asserted to have applied. All checks gated with set -e.

🤖 Generated with Claude Code

…ifiers

The cache was looked up *after* the disclosure fetch, so every reload of an
already-summarised analysis went to the Analysis Service for the reader's
unmatched identifiers and then discarded them. Not a disclosure beyond what
they chose, but a pointless request on the one endpoint where pointless
requests are worth avoiding -- and it meant the cache did nothing for the
path it should protect most.

The lookup now precedes the fetch, under the tier the reader *asked* for,
while the write still uses the tier that *applied*. The asymmetry is
deliberate and was worth working out rather than assuming: a request whose
disclosure failed stores an aggregate summary under `aggregate`, so the next
disclosing request misses and gets another attempt at the identifiers,
instead of being served the fallback forever. Both directions are now tested.

One thing the review confirmed rather than changed, and it is worth writing
down because it looks like waste. The analysis result is fetched on every
request, before the cache is consulted, and that is what keeps `gone`
correct: a release deletes the analysis, and a reader must be told to re-run
rather than handed a confident summary of something that no longer exists. A
cache that skipped the fetch would serve stale summaries of deleted results
indefinitely. Now pinned by a test.

Verified by sabotage, with the sabotage asserted to have applied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 60c9cca into main Sep 20, 2026
10 checks passed
@adamjohnwright
adamjohnwright deleted the 011-phase7-review branch September 20, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant