Skip to content

Adversarial review: the fixed bug came back down the error path - #279

Merged
adamjohnwright merged 2 commits into
mainfrom
011-phase4-review
Sep 20, 2026
Merged

adamjohnwright merged 2 commits into
mainfrom
011-phase4-review

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

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

The bug Phase 4 fixed was still reachable

Phase 4 fixed a disclosing tier that fetched the reader's identifiers and then produced the aggregate summary, because nothing told the model to use them.

The same outcome was still reachable when the lookup simply failed: no names, no naming instruction, an aggregate summary returned to someone who chose to disclose, and nothing in the stream saying the disclosure had not happened.

Fixing the prompt and leaving the error path is how a bug survives being fixed.

What changed

start now carries disclosure — the tier the summary was actually built from, which is not always the one requested:

event: start
data: {"release": 97, "analysis_type": "OVERREPRESENTATION", "cached": false,
       "disclosure": "aggregate"}

A caller can tell the reader their identifiers could not be retrieved, instead of presenting an aggregate summary as the disclosing one.

Nothing to disclose is deliberately not a failed disclosure. A result where every identifier matched reports identifiers, because the tier was honoured and there was nothing to retrieve — reporting a downgrade there would tell the reader something untrue, which is the failure this is meant to prevent.

Three tests: honoured, not honoured, nothing to honour. Verified by sabotage, with the sabotage asserted to have applied first.

The website needs to know

They are building the proxy route against this field's absence today. I will tell them, and it is additive — a caller ignoring it behaves exactly as before.

603 passed, 1 skipped; mypy over 151 files, ruff clean.

🤖 Generated with Claude Code

adamjohnwright and others added 2 commits September 20, 2026 16:42
Phase 4 fixed a disclosing tier that fetched the reader's identifiers and
then produced the aggregate summary, because nothing told the model to use
them. The same outcome was still reachable when the lookup simply failed: no
names, no naming instruction, an aggregate summary returned to someone who
chose to disclose, and nothing in the stream saying the disclosure had not
happened.

Fixing the prompt and leaving the error path is how a bug survives being
fixed.

`start` now carries `disclosure`: the tier the summary was actually built
from, which is not always the one requested. A caller can tell the reader
their identifiers could not be retrieved instead of presenting an aggregate
summary as the disclosing one.

Nothing to disclose is deliberately not a failed disclosure. A result where
every identifier matched reports `identifiers`, because the tier was honoured
and there was nothing to retrieve -- reporting a downgrade there would tell
the reader something untrue, which is the failure this is meant to prevent.

Three tests: honoured, not honoured, and nothing to honour. Verified by
sabotage, with the sabotage asserted to have applied first.

Contract updated, and the website needs to know -- they are building against
this field's absence today.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 9856a03 into main Sep 20, 2026
10 checks passed
@adamjohnwright
adamjohnwright deleted the 011-phase4-review branch September 20, 2026 16:49
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