Omission candidates: classify the fields of single objects and entries of nested lists, not only top-level list entries (#3934) - #4395
Open
realmarcin wants to merge 4 commits into
Open
realmarcin wants to merge 4 commits into
realmarcin wants to merge 4 commits into
Conversation
…ies of nested lists (#3934) `entry_omission_candidates` (#3880) classified only the keyed entries of top-level lists of class-ranged slots, and skipped any slot holding one object. `nested_omission_candidates` applies the same receipt-backed reading below that: from the class-ranged slots every replicate fills, single objects included, it follows only single-object steps (a field of an object every replicate holds) and keyed-list steps (an entry every replicate holds, identified as the first level identifies one), and classifies the fields some replicates fill and others do not and the object entries of nested lists some replicates carry and others do not. A row is a candidate only where a holder's verified receipt path, resolved into its final record, is on the node or below it at that node's own path in that replicate: the same chain of entries. A receipt on the object or entry above a node, or on the list holding it (#721), does not credit it. Keyless objects and the string items of nested lists are counted, never classified: a string item's only identity is its exact text, and below the first level most are prose items of lists of values, where a rewording would read as an omission (775 of 871 nested entry rows before this rule). Commentary fields are counted as such; `source_caveats` is skipped at any depth. `entry_omission_candidates` now shares its keyed join and status with the new reading (`_keyed`, `_status`, `_key_label`, `_held_in_all`). A test pins its full output, as origin/main produced it, on a fixture with structure below the first level; on the corpus, main's module and this one give identical output on all 24 arm x project groups (2,854 rows). `scripts/arm_comparison.py` adds the section, a `_replicate_resolved` helper both entry sections use, and rewords the top-level-only caveat. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…3934) Written by `scripts/arm_comparison.py --no-figures` at 30a2ded (the figures do not read the omission sections and are left as they are). A render of the note from unmodified origin/main equals the committed note byte for byte, so nothing here comes from main having moved; against it, this changes one line (the first-level entry table's top-level-only caveat, now pointing at the new table) and adds the section "Receipt- backed omission candidates below the first level (#3934)". No existing row moves. A second, independent render of the same commit matches the script's output byte for byte. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 5, 2026
Open
…#4434-#4439) Review round 1 of PR #4395. - #4434: the nested section's legend called every `conforms_to_*` field commentary, but the walk classifies `conforms_to` and `conforms_to_standard`, which the receipts instrument does not exempt. The legend now builds both key lists from the code: `EXCLUDED_SLOTS` is skipped, and the rest of `COMMENTARY_KEYS` is commentary. The same shorthand is corrected in the script docstring and in the `COMMENTARY_KEYS` comment. New tests: a nested `conforms_to_standard` is a candidate beside a commentary `conforms_to_class`, and the legend names the computed keys. - #4435: new tests for a node held at different indices, where each holder's receipt sits at the other holder's path. It credits nothing, both nested and at the first level, which shares `_status`. - #4436: in the shape-disagreement test, the list/object pair now differs below the shared identity, and a list/string pair is added. `_deep_group`'s `m` gets the same change. A walk that reads through the disagreement now fails. - #4437: `_deep_group` gains a string entry in a class-ranged top-level list. That is the one input the shared `_keyed`'s `objects_only` switch reads differently. The first-level pin is retaken from origin/main's module (bc1f41d). - #4438: the docstring now says receipt paths are followed by identity only where a phase-1 snapshot exists. Where none exists, they are read as written (an index join). - #4439: the legend now says a keyed identity is the key's value as `receipts._entry_key` reads it (stripped, with a resolver URL read as its CURIE), not its exact value. A new test pins the URL/CURIE join. No reading changes. In replicate_structure.py only a comment and a docstring change. In arm_comparison.py only the module docstring and the nested section's legend change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rendered by `scripts/arm_comparison.py --no-figures` at 0f31845. Only one line changes: the legend of "Receipt-backed omission candidates below the first level (#3934)". It now names the commentary keys from the code (#4434) and says how a keyed identity is read (#4439). No row or number moves. Against origin/main the note still differs in one changed line (the #3880 caveat) and the added section. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
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.
Fixes #3934
What changes
replicate_structure.entry_omission_candidates(#3880) classified only the keyed entries of top-level lists of class-ranged slots. It skipped any slot holding one object. This PR addsnested_omission_candidates, the same receipt-backed reading one level further down:human_subject_research.irb_approval) and objects reached further down.creators[*].affiliations[*]).The walk goes down only by two kinds of step:
receipts._entry_keyand its occurrence, the join the first level already uses._entry_keystrips the key's value and reads a resolver URL of a declared prefix as its CURIE. Nothing else is normalised, so a name in other words is another entry.Nothing is read below a keyless entry, a node some replicate lacks, a value that is a list in one replicate and not in another (a list/object or list/scalar disagreement), or a commentary field.
A row is a candidate only when a holder's verified receipt path, resolved into its final record (
resolve_verified), sits on the node or below it. Resolution follows the path by identity where the run left a phase-1 snapshot. Where it left none, the path is read as written (an index join). The path must be the node's own path in that replicate, so a receipt only counts through the same chain of entries. A receipt at another holder's path for the node credits nothing when its own replicate holds something else there.scripts/arm_comparison.pyadds the section "Receipt-backed omission candidates below the first level (#3934)". It also adds a_replicate_resolvedhelper that both entry sections now use, and rewords the top-level-only caveat.notes/arm_comparison.mdis regenerated by the script (--no-figures).Decisions the brief left open
basis(single/key, as incompare_nested) so the two kinds can be told apart.values), never classified. Their only identity is their exact text, and below the first level they are mostly prose. For example,version_access.versions_availableholds "v1.1, published 2025-01-17, DOI …" in one v6 VOICE replicate and "1.1 (17 January 2025), doi:…" in another. By exact text, 775 of the 871 nested entry rows were such items, as were 47 of the 71 nested-entry candidates on the receipted arms. This mirrors the first level, which leaves the items of top-level lists of values unclassified. Whether such a list is filled at all is still a field row.source_caveats:conforms_to_class,conforms_to_schemaandnotes. They are rows with statuscommentary.source_caveatsis skipped at any depth.conforms_toandconforms_to_standardare not exempt, because they carry facts from the bundle (receipts.py). They are classified like any other field. On v5 agentic CM4AI, twoconforms_toand twoconforms_to_standardrows are such fields, held by rep3 only and unmeasured.The top-level results did not move
entry_omission_candidates' full output on a fixture that has structure below its first level. The pinned literal was produced by origin/main's module (bc1f41d). Since review round 1, the fixture also holds a string entry in a class-ranged top-level list, with a receipt on it (The first-level pin test omits the one input where the shared_keyedswitch changes the first-level reading #4437). Main keys such an entry by its text and classifies it, and the branch still does.New rows per arm
Fields are shown as candidates / not / unmeasured / commentary; nested entries as candidates / not / unmeasured.
Every v6 agentic group reads its receipt paths as written, because the agentic path leaves no phase-1 snapshot. Its verified snippets are all
no_snapshot: 1,282 (AI_READI), 316 (CHORUS), 967 (CM4AI) and 727 (VOICE). So 50 of the 75 field candidates and 21 of the 24 nested-entry candidates rest on that index join. The v7 and v8 groups have nono_snapshotpath: their paths were followed through the phase-1 snapshot (receipts.remap_path), as the #3880 table's basis column shows.Both of the issue's examples are rows:
human_subject_research.irb_approval(v4 CM4AI, unmeasured) andcreators[*].affiliations[*](v6 VOICE, a candidate that rep3 lacks). A corpus test pins both.Tests
tests/test_replicate_structure.py: 10 new unit tests, 2 new section tests and 1 new corpus test. Round 1 added 4 of the unit tests and 1 section test. It also changed_deep_group,DEEP_RESOLVED, the first-level pin and the shape-disagreement test. 64 non-corpus and 4 corpus tests pass.All eight test files that load the changed code: 420 passed in the non-corpus lane and 30 in the corpus lane.
test_committed_comparison_matches_current_records: passes on the regenerated note.Mutation checks: Round 0 ran 12 mutations in an archive copy, and all 12 were caught. Round 1 ran 12 more in a git-archive copy of the round-1 commit, restoring each file from a pristine copy. All 12 were caught, each by exactly the tests expected:
_statuscredits any holder's path (The chain test cannot fail for the case it names: "the node's index in another replicate" when that replicate also holds the node #4435): both new other-holder tests.objects_only=True, The first-level pin test omits the one input where the shared_keyedswitch changes the first-level reading #4437): the first-level pin.conforms_to*field is commentary (The new section's note says everyconforms_to_*field is commentary, butconforms_to_standardandconforms_torows are classified as ordinary fields #4434): the exempt-keys test.source_caveatsis not skipped below the first level (The new section's note says everyconforms_to_*field is commentary, butconforms_to_standardandconforms_torows are classified as ordinary fields #4434): the exempt-keys, nested-rows and no-receipt tests.conforms_to_*field is commentary, butconforms_to_standardandconforms_torows are classified as ordinary fields #4434): the legend test.COMMENTARY_KEYSunfiltered (The new section's note says everyconforms_to_*field is commentary, butconforms_to_standardandconforms_torows are classified as ordinary fields #4434): the legend test._entry_keyreads a resolver URL as its CURIE and strips whitespace #4439): the identity test._entry_keyreads a resolver URL as its CURIE and strips whitespace #4439): the legend test.The round-0 mutations were not rerun. Round 1 removed no assertion, and its fixture changes only add content.
No canary or model call was made.
Review round 1
All six findings are fixed in this PR. Commit 0f31845 has the code, docstring and test changes, and 293cdbe regenerates the note. Against the round-0 note, only the new section's legend line changed. No number moved.
conforms_to_*field is commentary, butconforms_to_standardandconforms_torows are classified as ordinary fields #4434 (nit), fixed. The legend called everyconforms_to_*field commentary, but the walk classifiesconforms_toandconforms_to_standard. The legend now builds its skipped and commentary key lists fromEXCLUDED_SLOTSandCOMMENTARY_KEYS. Decision 4 above is corrected. The same shorthand predated this PR in the script's module docstring and theCOMMENTARY_KEYScomment, and is corrected there too. Two new tests: a nestedconforms_to_standardis a candidate beside a commentaryconforms_to_class; and the legend names the computed keys and no wildcard.creators[6]in rep1 andcreators[8]in rep2._deep_group'smgets the same change. A walk that reads through the disagreement now fails a test, whether it wraps an object, unwraps a one-entry list, iterates an object as a list or wraps a scalar (mutations 2 to 5)._keyedswitch changes the first-level reading #4437 (nit), fixed._deep_groupgains the string entryS1in a class-ranged top-level list, and the first-level pin was retaken from origin/main's module. Both main and the branch givevalue=S1as a candidate._entry_keyreads a resolver URL as its CURIE and strips whitespace #4439 (nit), fixed. The legend and the docstring now say a keyed identity is the key's value asreceipts._entry_keyreads it: stripped, and a resolver URL of a declared prefix read as its CURIE. A new test pins it.https://doi.org/…,doi:…, a padded value and an upper-case host are all one entry, but a DOI suffix in another case is a different entry.Follow-ups filed
idin one replicate and bynamein another reads as two missing entries #4396: one entity keyed byidin one replicate and bynamein another reads as two missing entries.Round 1 filed nothing new. #4435's verification noted that CLAUDE.md's "Two CI lanes" section is out of date, since every PR runs the corpus lane. #3863 already tracks that.
🤖 Generated with Claude Code