M5 Phase 3: grow the fixture pack to what a boolean decision cannot reach - #61
Merged
Conversation
…each Part 4b(ii)a. I started the four demo suites and stopped at the first one, because test_api splits on a fixture the pack could not supply. Half its tests assert that verdict wording is *pack data* — phrasing blocks, placeholders, tones — and fx:permitted is boolean, so it takes the kernel's Yes/No fallback and never reaches that machinery at all. The whole phrasing path was untestable except through the teaching packs, which is exactly the dependency this phase exists to sever. So the pack grew fx:assessedFee: a money decision with a phrasing block and a default/exception rule pair at differing priorities with an explicit overrides, the shape the IR is built around. The scenario grew a fact marked sensitivity: pii for the report renderer's redaction path — invented, naming nobody, because a fixture carrying real personal data to test PII handling is the joke that writes itself. That is part 5's stated prerequisite, delivered early because part 4b(ii) hit it first. The blocker was one artifact, not two suites' worth of work, which is the argument for measuring before estimating. Growing the pack is a rebuild, not an edit: pack.version is inside every receipt, so this moved all four receipts, the decision-digest vectors and the corpus aggregate. It found two literals that should always have been derived. The "later pack version" vector hardcoded 2026.2.0, which the bump made the *current* version — collapsing that equivalence class into the base one — and a PROV-O test pinned the pack URN. Both derive from the receipt now. The equivalence test caught the first, which is the whole reason it checks a relation rather than a table of constants. Verification: 975 passed, 7 skipped; verify 351 byte-for-byte; spec/validate.py green; all fixture facts conform; every span re-verified against the rendition and the document hash against the PDF; prove proves the grown pack with no uncovered decision attribute; both builders idempotent; golden/ untouched. Docs last, as asked: fixtures/README gains the phrasing rationale and a rule that growing the pack is a rebuild; the plan records why 4b(ii) split and that no remaining conversion is blocked on a missing artifact; the changelog carries what the boolean-decision gap taught. Co-Authored-By: Claude Opus 5 <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.
Part 4b(ii)a. I started the four demo suites and stopped at the first one.
Why
test_apisplits on a fixture the pack could not supply. Half its tests assert that verdict wording is pack data —phrasing:blocks, placeholders, tones — andfx:permittedis boolean, so it takes the kernel's Yes/No fallback and never reaches that machinery at all.So the pack grew
fx:assessedFee: a money decision with a phrasing block and a default/exception pair at differing priorities with an explicitoverrides, the shape the IR is built around. The scenario grew asensitivity: piifact for the report renderer's redaction path — invented, naming nobody, because a fixture carrying real personal data to test PII handling is the joke that writes itself.That is part 5's stated prerequisite, delivered early because 4b(ii) hit it first. The blocker was one artifact, not two suites' worth of work — the argument for measuring before estimating, again.
A rebuild, not an edit
pack.versionis inside every receipt, so this moved all four receipts, the decision-digest vectors and the corpus aggregate. It found two literals that should always have been derived:2026.2.0, which the bump made the current version — collapsing that equivalence class into the base one;Both derive from the receipt now. The equivalence test caught the first, which is the whole reason it checks a relation rather than a table of constants.
Verification
Also:
spec/validate.pygreen; all fixture facts conform to the fixture ontology; every span re-verified against the rendition and the document hash against the PDF; both builders idempotent (re-run, diff unchanged).Docs last, as asked
fixtures/README.mdgains the phrasing rationale and a rule that growing the pack is a rebuild with a re-pinning checklist.docs/m5-plan.mdrecords why 4b(ii) split and — the useful part — that no remaining conversion is blocked on a missing artifact, which was not true of any earlier part. The changelog carries what the boolean-decision gap taught.🤖 Generated with Claude Code