#24 docs: split the content.fetch issuer contract to the per-doc budget - #26
Merged
Conversation
`### Request options` had no sibling heading after it, so both fact schemas — `BlobAvailableEvent` and `FetchFailedEvent` — were structurally nested under a subsection about `headers` and `timeout_seconds`. A split that reads the heading tree would have relocated the wire schemas into a lookup annex. Adds `### The command`, `### The success fact`, `### The failure fact` under `## The payload`, and moves the `occurred_at` tz blockquote up to the command it constrains. Content verbatim; prove-no-loss reports 0 unaccounted lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The contract was 14,772 tokens against the 10,000 per-doc budget, and it is the doc most likely to be read by an agent working in a sibling repo — the case where an over-budget file does the most damage, since there is no cheaper local surface to fall back on. The path sibling repos link stays the normative core, not a stub: a stub would cost every issuer-side agent a second read to reach the MUSTs, which is the cost the split exists to remove. Core keeps the frame, the payload shapes, the seven MUSTs, and the guarantee/non-guarantee pair — 14,772 -> 9,966. content-fetch-issuer-reference.md (7,349, new, equally normative) takes what an issuer looks up rather than reads through: the request-options refusal list, the reasoning behind the enriched blob_available fields and the #17 conditional-GET trap, the failure taxonomy, the four silent conditions, reading the DLQ, the provenance and trust posture, the co-core version history, what the envelope key is operationally for, and pacing at the deployed defaults. docs/plans/2026-07-31-fetch-failed-fact-settled.md takes the resolved silence-as-failure question. Archival, so out of the measured surface. Moves are verbatim. prove-no-loss --base d4a5e02 accounts for 471 of 475 lines; the four it does not are the intra-document pointers whose referent moved, so "see the taxonomy below" and "the refusal table above" were disproven by the move and are now cross-file links. Every live doc is now under budget; AGENTS.md is 5,896 of 6,000. No dead links, no orphans, every anchor resolves. Manifest updated and re-embedded in the same change, per the #19 CR #17 rule. Refs updated: AGENTS.md (Detail Docs + the Bus Conventions signpost), README.md, docs/ARCHITECTURE.md, docs/COMMANDS.md, docs/contracts/replicator-boundaries.md, src/core/errors.py (its docstring names the file for the taxonomy specifically, which is now the reference). Closes #24 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 fix Restored the "No ordering" non-guarantee to the contract. A slice-based
cut took one line too many and swept it into the reference's pacing
section, where it dangled under an unrelated heading and read as a claim
about pacing. prove-no-loss passed because it verifies a line exists
somewhere, not that it landed in the right place — the one failure mode
the check is structurally blind to.
2 update MUST-6's "FetchFailedEvent note above" now links the reference section
the note moved to.
3 update The moved silent-conditions bullet's "see **The frame**" now links
across to the contract instead of pointing nowhere.
4 update De-indented the moved pacing paragraph, which kept its list-continuation
indent under a heading with no list.
5 update Reordered the reference into reading order: request options, enriched
fields, taxonomy, reading the failure fact, the four silent conditions,
reading the DLQ, provenance and trust, then the three short appendices.
Accretion order had provenance splitting the taxonomy from its own
expansions.
6 update Contract 10,017 -> 9,481, margin 519. Restoring finding 1 had pushed it
back over. Moved to the reference: MUST-4's why-a-duplicate-failure-fact-
differs mechanism, MUST-7's TTL clock mechanism, MUST-6's swallowed-
publish bullet, MUST-2's map-loss consequence, MUST-5's per-occasion
consequence (now adjacent to the blockquote making the same argument from
the other side), and the re-hash note. Each rule stays; each mechanism
moves. Tail index compressed.
7 update "Three behaviours", not "two tokens' worth" — the section covers three
things and one of them is a token.
8 update The relocated Settled doc's "MUST-6 above" now links to MUST-6.
9 drop Dropped its duplicate H2.
10 rewrap README:33.
11 update Linked the bare MUST-6 reference at what-the-envelope-key-is-for.
prove-no-loss --base d4a5e02: 447 of 475 lines verbatim in place, 28 unaccounted —
every one a pointer the move itself disproved ("see the taxonomy below", "the
refusal table above", "see **The frame**"), now a cross-file link, or the dropped
duplicate heading. All under approved directives.
Every live doc under budget; AGENTS.md 5,896/6,000. All links and anchors resolve
under GitHub's slug rule (the first-round checker collapsed whitespace runs and
would have passed two broken anchors). 444 passed, ruff clean, manifest re-embedded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Second-round review finding 13. The header described four things; after finding 6 moved five mechanism blocks in, the file also carries the mechanisms behind several MUSTs — each rule stated in the contract, each explanation here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Closes #24.
docs/contracts/content-fetch-issuer-contract.mdwas 14,772 tokens against the 10,000 per-doc budget — the last live doc over it after #22, and the one most likely to be read by an agent working in a sibling repo, which is where an over-budget file does the most damage.Two commits
1. Promote the fact schemas out of the request-options subsection. There was no heading between
### Request optionsand## What the issuer MUST do, so both wire schemas —BlobAvailableEventandFetchFailedEvent— were structurally nested under a subsection aboutheadersandtimeout_seconds. The issue's split table read that heading tree faithfully; following it would have relocated the schemas into a lookup annex. Fixed first, verbatim, on its own.That also corrects the issue's arithmetic:
### Request optionsproper is 49 lines / ~1,562 tokens (10.6%), not the 168 lines / 29% the heading span suggested.2. The split. Measured per-section, the core as the issue scoped it came to 10,911 — over budget with request options, the taxonomy, provenance and the Settled section all removed. So the cut goes further.
content-fetch-issuer-contract.md(path unchanged)content-fetch-issuer-reference.md(new)docs/plans/2026-07-31-fetch-failed-fact-settled.md(new)Both contract files are normative. A rule did not become advisory by moving.
The linked path stays the core, not a stub. A stub would cost every issuer-side agent a second read to reach the MUSTs, which is the cost the split exists to remove.
Verification
prove-no-loss.sh --base d4a5e02— 471 of 475 lines verbatim. The four exceptions are the intra-document pointers whose referent moved (see the taxonomy below,the refusal table above); the move itself disproved them and they are now cross-file links.AGENTS.md5,896 of 6,000.uv run pytest444 passed ·uv run ruff check .clean.codebase_context_indexre-run in the same change (Consume content.fetch-policy — replace the single env default with Watcher's per-host numbers (cannobserv#285) #19 CR A body-less 304 dead-letters — make "not modified" a first-class outcome before conditional GET is usable #17).Cross-repo
CannObserv/watcher#241 notified, per the contract's own announcement rule — the failure taxonomy moved, so the rule fired. CannObserv/watcher#241 (comment)
Refs updated
AGENTS.md(Detail Docs + the Bus Conventions signpost),README.md,docs/ARCHITECTURE.md,docs/COMMANDS.md,docs/contracts/replicator-boundaries.md,src/core/errors.py— its docstring names the file for the taxonomy specifically, which is now the reference.🤖 Generated with Claude Code