diff --git a/dag/gunbc/explicit_witness_admission.dag b/dag/gunbc/explicit_witness_admission.dag index d4defd78453..2926724d433 100644 --- a/dag/gunbc/explicit_witness_admission.dag +++ b/dag/gunbc/explicit_witness_admission.dag @@ -158,14 +158,6 @@ data explicit_witness_admissions: List = [ reason: "NO LONGER THE CLOSING VALIDATION FOR roadmap node v1-test-migration as of 2026-08-11 (gunbc#8146, review 51212) — that node rebound to test_migration_debt_test.dag retained_rust_kernel_wall_holds_against_live_tree when the authority inverted from classifying departures to declaring residents, and gunbc.roadmap_authority is the single authority for that binding. RETAINED as an expecting-red probe only: it still measures a real derived quantity and greening it would still be progress. It was: the discriminating closing validation for roadmap node v1-test-migration, RED BY DESIGN while any independently discovered legacy #[test] function has no typed behavior disposition. Unlike the diff-scoped deletion guard it cannot pass on zero progress; stale, duplicate, unresolved and unclassified identities all refuse.", dissolution: unbound_dissolution(description: "the derived unclassified legacy-behavior set reaches zero with every disposition admitted — this row deletes in the completing change, promoting the unchanged acceptance witness to ordinary DiscoverySelection as the permanent migration regression wall") ), - known_red_probe( - entry: "dag/test/claim/coproduct_payload_soundness_witness_test.dag", - f: "cpp_payload_where_coproduct_required_must_refuse", - kind: CorpusWitnessKind, - budget: FastLaneEvalBudget, - reason: "A COPRODUCT PAYLOAD CAN INHABIT ITS PARENT COPRODUCT FIELD AND NOTHING REFUSES IT -- the general form of the defect #8853 repaired at one site. There, a std.occurrence_identity.OccurrenceId (the payload carried inside MintedOccurrence) was declared as a parameter and assigned into Node.occurrence_id, whose type is the NodeOccurrenceId coproduct; nothing refused it, and the consequence surfaced one pipeline stage away as `non-exhaustive pattern match on: OccurrenceId` in sixteen floor claims. MEASURED GENERALLY, minimal pair, no Node and no compiler internals: CppHolder { subject: cpp_inner() } is ACCEPTED BY TYPING and dies at runtime with PatternMatchFailure, while the correct spelling CppHolder { subject: CppWrapped { inner: cpp_inner() } } compiles and executes -- so the mechanism is neither Node-specific nor occurrence-specific. This is BELOW FLOOR, not a rung: DESIGN section 4b places `values inhabit declared types` in the ordinary compiler floor, and a floor failure is a below-baseline safety regression rather than a class sitting at mitigatable. Red BY DESIGN and not relaxable: the only edit that may green it is making the ill-typed construction refuse. Its positive control (cpp_payload_inside_its_own_arm_still_compiles) is enrolled as an ordinary green claim so the red measures the distinction rather than a blanket refusal. Owner: the compiler type-soundness lane. THIS ROW DOCUMENTS THE RED AND ITS DISSOLUTION; the required floor is gated by the identity's row in v2.workflow.floor_expected_red, per the ruling at floor_expected_red_chunk_13. Both rows delete together when the wall lands.", - dissolution: unbound_dissolution(description: "the construction refuses with a located, blocking type diagnostic -- this row deletes in the change that lands the wall, promoting the witness to ordinary DiscoverySelection as the permanent regression control DESIGN section 4b(4) requires stay enrolled") - ), known_red_probe( entry: "dag/test/claim/observation_raw_print_retirement_acceptance_test.dag", f: "observation_emit_frontier_is_zero", diff --git a/dag/test/claim/coproduct_payload_soundness_witness_test.dag b/dag/test/claim/coproduct_payload_soundness_witness_test.dag index 546040d0eb5..49454c30f27 100644 --- a/dag/test/claim/coproduct_payload_soundness_witness_test.dag +++ b/dag/test/claim/coproduct_payload_soundness_witness_test.dag @@ -35,8 +35,27 @@ module test.claim.coproduct_payload_soundness_witness_test // // WHAT IS ASSERTED. compile_dag_rust_emit_check must REFUSE the fixture below: placing a variant's // payload where the variant's own type is declared must be a located, blocking type diagnostic, not -// a program that compiles and dies at its first match. The witness returns false today, which is why -// it is enrolled as an expecting-red identity rather than asserted green here. +// a program that compiles and dies at its first match. +// +// THE WALL LANDED AND THIS PAIR IS NOW GREEN BY EXECUTION, measured on the remote runner against the +// same two fixtures, one commit apart, with nothing else changed: +// +// BEFORE negative -> `compiled: 9 files emitted, 0 diagnostics` (the hole) +// AFTER negative -> `type mismatch: expected 'Coproduct(CppOuter)', got 'Product(CppInner)'` +// `v2 self-compile produced 1 hard diagnostic(s)` +// BEFORE and AFTER, positive control -> `0 diagnostics` +// +// The refusing authority is `v1.compiler.infer` `coproduct_payload_where_parent_required`, consulted +// at the record-literal field seam. Both this file's expecting-red rows -- the +// gunbc.explicit_witness_admission admission and the v2.workflow.floor_expected_red roster entry -- +// deleted in that same change, and this witness stays enrolled as the permanent regression control +// DESIGN section 4b(4) requires: deleting the evidence on the climb would recreate +// specification-without-execution one rung up. +// +// WHAT THIS PAIR DOES NOT MEASURE, stated rather than implied covered. The wall closes the +// record-literal field seam and only it: a `let` binding, a method argument, and the direct-call +// argument seam are judged by other authorities and are not exercised here. Per gunbc#8868 the seam +// enumeration for this class is unfinished, so this is one seam closed, not the class closed. // // ENROLLED IN TWO PLACES, AND THEY ARE NOT THE SAME FACT -- I got this wrong on the first attempt // and the floor caught it. `v2.workflow.floor_expected_red` is what GATES the required floor: an @@ -63,9 +82,9 @@ fn cpp_soundness_positive_fixture_source() -> String { "module cpp.control\n\nimport std.types { Int }\n\ntype CppInner { value: Int }\n\ntype CppOuter\n = CppWrapped { inner: CppInner }\n\ntype CppHolder {\n subject: CppOuter\n}\n\nfn cpp_inner() -> CppInner {\n CppInner { value: 7 }\n}\n\nfn cpp_wrapped_holder() -> CppHolder {\n CppHolder { subject: CppWrapped { inner: cpp_inner() } }\n}\n" } -// THE DISCRIMINATING RED. `CppInner` is the payload inside `CppWrapped`, not a member of `CppOuter`, -// so this assignment must refuse at typing. It does not: the program compiles and the failure is -// deferred to whatever later match reads the field. +// THE DISCRIMINATING RED, now the regression control. `CppInner` is the payload inside `CppWrapped`, +// not a member of `CppOuter`, so this assignment must refuse at typing. Before the wall it did not: +// the program compiled and the failure was deferred to whatever later match read the field. test fn cpp_payload_where_coproduct_required_must_refuse() -> Bool { !compile_dag_rust_emit_check( cpp_soundness_negative_fixture_source(), @@ -85,3 +104,33 @@ test fn cpp_payload_inside_its_own_arm_still_compiles() -> Bool { [] ) } + +fn cpp_alias_mediated_negative_fixture_source() -> String { + "module cpp.alias\n\nimport std.types { Int }\n\ntype CppInner { value: Int }\n\ntype CppInnerAlias = CppInner\n\ntype CppOuter\n = CppWrapped(CppInner)\n\ntype CppHolder {\n subject: CppOuter\n}\n\nfn cpp_inner_via_alias() -> CppInnerAlias {\n CppInner { value: 7 }\n}\n\nfn cpp_alias_payload_where_coproduct_required() -> CppHolder {\n CppHolder { subject: cpp_inner_via_alias() }\n}\n" +} + +// THE ALIAS-MEDIATED RED, and it is not a restatement of the one above -- it is the arm that made the +// difference between a wall that refuses a demonstration and a wall that reaches production. +// +// A first measured version of this wall refused the direct spelling and stayed SILENT on the live +// specimen it was built against: `v2.std.materialize` storing `content_hash(n)` into a field declared +// `ContentHash`. `content_hash` returns `v2.std.node` `Hash`, a TRANSPARENT ALIAS of the payload type +// `Fnv1a64Structural`, and that fact does not survive `resolve_item_types` -- so the seam could not +// recover it by peeling and the refusal never fired. This fixture is that shape reduced to nothing but +// the mechanism: the producer's declared return type is an alias of the payload rather than the payload +// itself, and the variant carries its payload positionally rather than as a named field, so neither the +// name nor the arm shape is doing the work. +// +// Measured on the pre-relation binary this fixture COMPILED (`0 diagnostics`); with +// `transparent_alias_identity_agrees` consulted it refuses +// (`expected 'Coproduct(COuter)', got 'Primitive(CAlias)'` on the equivalent probe). Deleting the +// alias arm from the wall leaves both witnesses above green and only this one red, which is exactly why +// it is enrolled separately. +test fn cpp_alias_mediated_payload_must_also_refuse() -> Bool { + !compile_dag_rust_emit_check( + cpp_alias_mediated_negative_fixture_source(), + "src/cpp_alias.rs", + [], + [] + ) +} diff --git a/dag/test/claim/heal_revalidation_witness_test.dag b/dag/test/claim/heal_revalidation_witness_test.dag index 47b8b5ee633..0aa2a3cf0c0 100644 --- a/dag/test/claim/heal_revalidation_witness_test.dag +++ b/dag/test/claim/heal_revalidation_witness_test.dag @@ -1,6 +1,6 @@ module test.claim.heal_revalidation_witness -import std.content_hash { Fnv1a64Structural, content_hash_atom } +import std.content_hash { ContentHash, Fnv1a64, content_hash_atom } import std.types { CommitSha } import extdeps.github.checks { Success } import gunbc.merge_admission { @@ -26,8 +26,8 @@ import gunbc.heal_revalidation { data prior_head: CommitSha = "1111111111111111111111111111111111111111" data healed_head: CommitSha = "2222222222222222222222222222222222222222" data other_head: CommitSha = "3333333333333333333333333333333333333333" -data required_roster: Fnv1a64Structural = content_hash_atom(value: "heal-roster") -data required_gate: Fnv1a64Structural = content_hash_atom(value: "heal-gate") +data required_roster: ContentHash = Fnv1a64(content_hash_atom(value: "heal-roster")) +data required_gate: ContentHash = Fnv1a64(content_hash_atom(value: "heal-gate")) fn produced() -> HealOutcome { HealProduced { diff --git a/dag/test/claim/materialization_provider_witness_test.dag b/dag/test/claim/materialization_provider_witness_test.dag index 7f70a02dfbf..feb4945dd50 100644 --- a/dag/test/claim/materialization_provider_witness_test.dag +++ b/dag/test/claim/materialization_provider_witness_test.dag @@ -3,6 +3,7 @@ module test.claim.materialization_provider_witness import std.types { Bool, Int, List, String } import std.content_hash { ContentHash, + Fnv1a64, content_hash_atom, as_content_hash_cryptographic, sha256_hex_digest, @@ -240,7 +241,7 @@ test fn red_wrong_content_refuses_never_hits() -> Bool { req: witness_closure_request(), probe: ProbeFound { artifact: witness_complete_closure_artifact(), - observed_digest: content_hash_atom(value: "closure-payload-corrupt") + observed_digest: Fnv1a64(content_hash_atom(value: "closure-payload-corrupt")) } ) lookup_is_refused_wrong_content(l: poisoned) && (lookup_is_hit(l: poisoned) == false) diff --git a/docs/plans/compiler-guarantee-recovery-gap-analysis.md b/docs/plans/compiler-guarantee-recovery-gap-analysis.md index d7b90db6b5d..e805691e707 100644 --- a/docs/plans/compiler-guarantee-recovery-gap-analysis.md +++ b/docs/plans/compiler-guarantee-recovery-gap-analysis.md @@ -170,7 +170,7 @@ unless the row says otherwise, and `Unknown` is the honest default. | Closed-match exhaustiveness | **Path-split, measured 2026-08-01 — the class is not one rung.** Coproduct-typed scrutinee: **R2** (a missing arm on a declared closed variant refuses `NonExhaustiveMatch`, blocking, naming the absent variant). Type-variable scrutinee: **below floor — silent** (`fn pick(t: T) -> Int { match t { Red => 1 } }` compiles with zero diagnostics — one arm, an unconstrained subject, and a variant belonging to an unrelated type). Class rung is the minimum, so **below floor** | R3 (full arm population at elimination) | the silent arm is `PatternDynamic { span: _ } => []`, **not** `PatternLookupBlocked => []` as this row previously said — `pattern_subject_from_node` reaches `PatternLookupBlocked` only when the scrutinee's inferred type `is_compiler_error`, i.e. where a diagnostic already exists, so that arm is not the silent one and its silence is **not** established by these probes | first measured by a one-off execution 2026-08-01 via `compile_dag_diagnostic_census` on the v1 CompileAccept path (source and result in the §10 eighth-pass ledger), and **AUTHORED AS A PROBE PAIR 2026-08-22 — AUTHORED, NOT EXECUTING, AND THE DISTINCTION IS THE WHOLE POINT** (see §11 item 28): the measurement is now written as `test.claim.guarantee_floor_class_probe_witness` `floor_exhaustiveness_on_a_type_variable_scrutinee_is_still_silent`, against the registry row `gunbc.guarantee_probe_corpus` class `floor-closed-match-exhaustiveness`, with the coproduct-scrutinee arm already enrolled at `test.claim.match_exhaustiveness_coproduct_witness` `w_missing_coproduct_arm_reports_one_non_exhaustive`, on the same harness and the same floor run — not re-authored here, because a second copy would be a second authority for one fact as its probe-adequacy control. **It does not run in CI.** The witness declares `ReadsLiveTree` — truthfully, because `compile_dag_diagnostic_census` resolves its synthetic source against the live checkout — and the required floor DECLINES every `ReadsLiveTree` module before the fold sees it (`v2.workflow.required_floor` `RequiredFloorDisposition` `DeclinedLiveTree`), so the probe is discovered and never executed, exactly like the five guarantee carriers §11 item 28 counts. It is green by execution LOCALLY (`gunbc run --claim-run`, 2026-08-22, this session) and that is a strictly weaker fact. So this cell's rung is unchanged from the day before the probe was authored: it still rests on a measurement nothing re-runs. What the probe pair buys is that on the day the decline arm is deleted the measurement becomes standing evidence with no further authorship. Trigger: the `DeclinedLiveTree` deletion (§11 item 28), NOT this cell (§4b meta-obligation 4; the original gap was codex review 46306, §11 item 10) | `ExhaustivenessUnknown` refuses on the dynamic subject | | Record completeness | **R2 measured 2026-08-01** (a record literal omitting a declared required field refuses `MissingField`, blocking, naming the field and type — the class was carried as `Unknown — unmeasured` and the measurement raises it) | R3 | judgment is per-literal; construction-side and generic-instantiation completeness are separate and the latter measures **below floor** in the row above | first measured by a one-off execution 2026-08-01 via `compile_dag_diagnostic_census` on the v1 CompileAccept path (source and result in the §10 eighth-pass ledger), and **AUTHORED AS A PROBE PAIR 2026-08-22 — AUTHORED, NOT EXECUTING, AND THE DISTINCTION IS THE WHOLE POINT** (see §11 item 28): the measurement is now written as `test.claim.guarantee_floor_class_probe_witness` `floor_record_completeness_missing_field_refuses_blocking`, against the registry row `gunbc.guarantee_probe_corpus` class `floor-record-field-completeness`, with `floor_record_completeness_green_control_is_clean` as its probe-adequacy control. **It does not run in CI.** The witness declares `ReadsLiveTree` — truthfully, because `compile_dag_diagnostic_census` resolves its synthetic source against the live checkout — and the required floor DECLINES every `ReadsLiveTree` module before the fold sees it (`v2.workflow.required_floor` `RequiredFloorDisposition` `DeclinedLiveTree`), so the probe is discovered and never executed, exactly like the five guarantee carriers §11 item 28 counts. It is green by execution LOCALLY (`gunbc run --claim-run`, 2026-08-22, this session) and that is a strictly weaker fact. So this cell's rung is unchanged from the day before the probe was authored: it still rests on a measurement nothing re-runs. What the probe pair buys is that on the day the decline arm is deleted the measurement becomes standing evidence with no further authorship. Trigger: the `DeclinedLiveTree` deletion (§11 item 28), NOT this cell (§4b meta-obligation 4; the original gap was codex review 46306, §11 item 10) | required-field construction at every construction form | | Parse: list separator dropped | **Below floor — silent** (measured: `[ {a}, {b} {c} ]` compiles with zero diagnostics — a dropped comma is a silent semantic change, two- vs three-element list; survived regen, whole-corpus compile, fixed-point verify and a 15-case matrix, caught only by a human diff read) | R3 (decidable grammar fact) | separator omission parses as element juxtaposition | First measured by tidy-deer-730's throwaway probe on gunbc#7484 + review 45347, 2026-07-31. **PROBE PAIR AUTHORED 2026-08-22, NOT EXECUTING** (§11 item 28 — the witness is declined by the floor's `DeclinedLiveTree` arm and runs only under a local `gunbc run --claim-run`): `test.claim.guarantee_floor_class_probe_witness` `floor_parse_list_separator_omission_is_still_silent` re-executes it on every required-floor run against `gunbc.guarantee_probe_corpus` class `floor-parse-list-separator`, with `floor_parse_list_separator_doubled_separator_control_refuses` (a DOUBLED separator in the same position refuses `ParseError`, blocking) and `floor_parse_list_separator_green_control_is_clean` as its probe-adequacy controls, all three green locally and none of them executing in CI — so the omission's silence is measured against a parser that demonstrably refuses malformed separators | the probe pair is now in the corpus and pins the hole; what remains is the refusal in the list production (§11 item 6), on which the enrolled probe flips RED and its row is rewritten as `ExpectBlockingRefusal` | -| A value that does not inhabit its declared type is accepted — **seam-split, enumeration UNFINISHED** (was filed as "Direct-call argument TYPE conformance, v2 corpus"; renamed 2026-08-22, see the trigger cell) | **Below floor — the judgment never runs.** Not a hole a bad value slipped through: `v1.compiler.04_infer` gates `arg_compat_diags` on `module_skips_direct_call_arg_check(module_name: scope.module_name)`, which returns true for every module whose name begins with `v2.`. The key is the CALLER's module, so the entire active v2 corpus — compiler stages, extdeps, std, witnesses — has the direct-call argument-type judgment switched off. Measured consequence, 2026-08-22: `v2.extdeps.languages.dag` `dag_int_literal_node_from_lexeme` / `dag_int_literal_node_from_magnitude` declared `occurrence_id: OccurrenceId` since gunbc#6558 while storing that parameter straight into `Node.occurrence_id`, declared `NodeOccurrenceId`. For two months 15 call sites passed `SyntheticOccurrence` (a NodeOccurrenceId, contradicting the declaration) and nothing complained; gunbc#8833 made one call site OBEY the declaration and nothing complained about that either. The error surfaced only as an interpreter `non-exhaustive pattern match on: OccurrenceId { value: 79 }` across 16 witnesses, reddening main. **The inversion worth naming: a declaration that lies is inert while every caller contradicts it in the same direction, and detonates on the first caller who takes it at its word.** So the at-risk population is not "callers who got it wrong" but callers who might get it right — a genuinely counterintuitive census. Note this is the TYPE judgment only; the SHAPE judgment (`direct_call_shape_diags`, labels/arity) is exemption-free and does fire | R2 (a declared parameter type is a decidable conformance check the seam already computes — `direct_call_arg_mismatch_diags` exists, is written, and is simply not called, so the distance to the next rung is an if-statement plus a triage, not an implementation) | **THIS ROW IS A CORRECTION TO DESIGN §4b, NOT A NEW OBSERVATION BESIDE IT — read them together or the first will look like it already settled this.** DESIGN §4b names this exact symbol and reports that it "was found (code read, not execution) to be scoped entirely to the direct-call argument-type judgment and does not reach `sole_constructor`'s construction check at either call site — a positive finding that retires this axis, not an absence of any exemption anywhere." That finding is correct and is not disputed here. The question it asked was whether the exemption LEAKS into `sole_constructor`; the question it never asked is what the exemption COSTS inside the judgment it is scoped to. "Scoped entirely to the direct-call argument-type judgment" reads as reassuring only until that judgment is measured, and it is the argument-type check for the entire active v2 corpus. **Confinement was measured and then treated as safety, and the axis that got retired was not the one that mattered.** Two facts about why the seam nonetheless reads as covered: the SHAPE judgment (`direct_call_shape_diags` — labels, arity, duplicate binding) is exemption-free and DOES fire over every module including the compiler's own sources, so half-live is more deceptive than dead — every casual check finds something working. And the arm is NOT unreasoned: `direct_call_shape_wall_note` states the TYPE judgment's false-positive classes are representation gaps (brand aliases, optionality's two forms, anonymous literals, expansion depth — the conformance wall's four measured classes), which is a real stated reason and is why this row asks for a measurement rather than a deletion. What is unmeasured is whether those classes still fire in v2 today and at what rate. The neighbouring compiler-module arm of this same exemption was deleted in place after being found never to have been in force; the `v2.` arm was left standing at that moment without separate justification of its own | This incident, measured end to end: CI run 32542017600 (main, 67437fcbe9) 16 FAIL with the raw-`OccurrenceId` match error; caller census of both functions read at call grain (17 sites: 15 `SyntheticOccurrence`, 1 `node.occurrence_id`, 1 internal pass-through, 1 raw `minted.id`); exemption mechanism read at `v1.compiler.04_infer` `module_skips_direct_call_arg_check` and its single call site gating `arg_compat_diags` on `scope.module_name`. **NOT ENROLLED**: no probe pair asserts this exemption's reach, so nothing reds if it changes | **THE TRIGGER THIS ROW SHIPPED WITH WAS INCOMPLETE AND IS CORRECTED HERE (2026-08-22, swift-badger-524 retracting their own ruling).** As merged in gunbc#8854 this cell named ONE closing condition — delete the `v2.` exemption — which is a NECESSARY condition presented as a sufficient one. The class is not "direct-call argument type conformance"; it is **a value that does not inhabit its declared type is accepted**, and it has at least TWO seams: **(1) direct-call arguments** — gated off for `v2.*` by `module_skips_direct_call_arg_check`, the mechanism this row measures; **(2) record-literal fields** — gated by NOTHING, below floor in ORDINARY NON-v2 MODULES, receipt gunbc#8865 (gentle-eagle-360). Its minimal pair, no compiler internals involved: `CppHolder { subject: CppWrapped { inner: cpp_inner() } }` accepted and correct, against `CppHolder { subject: cpp_inner() }` — a coproduct PAYLOAD inhabiting a field declared as its parent COPRODUCT — ACCEPTED BY TYPING and dying at runtime as `PatternMatchFailure`. A record literal is not the direct-call seam, so deleting the exemption would not close it. **SEAM (2) NOW HAS A LIVE PRODUCTION SPECIMEN, WHICH RANKS IT DIFFERENTLY FROM A SYNTHETIC PAIR** (gentle-eagle-360, 2026-08-22, found while checking for a second content-identity authority before building on one): `v2.std.materialize` declares `MaterializedNode.hash` as `ContentHash` — the subject-generic union — and `materialize_fold_step` stores `content_hash(n)` into it, which returns `Fnv1a64Structural`, the PAYLOAD carried inside the union's `Fnv1a64` arm. Receipt, by execution against the module as it stands on main: taking the value materialize ACTUALLY STORED and asking the union's own family authority `content_hash_family` about it yields `PatternMatchFailure { value: "Fnv1a64Structural { digest: 7ac77ab0e29c6bd8 }" }`; the probe's fallback was a correctly wrapped `Fnv1a64(...)`, so an empty result or a well-formed value would have PASSED and only a stored value can produce that red. **The defect is LATENT and that is the instructive part**: peer lookup compares `e.hash == h`, raw payload against raw payload, which agrees with itself — so every current path is green and the error surfaces only when a materialize hash is routed through the union's own machinery (`content_hash_family`, or `compare_content_hash`, which exists precisely to refuse cross-family collapse). That is the same shape as this row's own originating incident: **a declaration that lies is inert while every consumer contradicts it in the same direction, and detonates on the first consumer that takes it at its word** — here the first cross-family artifact to reach the carrier. Disposition ruled ARM A, wrap the construction (`MaterializedNode { hash: Fnv1a64(h), ... }`), NOT narrow the declaration: narrowing would sever `MaterializedNode.hash` from `RealizationPlan.target`, and §2's Realization spans resolve-cost, sccache and OS provisioning on ONE content hash, so a structural-only key could never name a realization of a fetched artifact or a provisioned image (swift-badger-524 ruling, 2026-08-22; handed to silent-bear-842 with the receipt, unfixed here because it is that lane's module). **THE SEAM ITSELF IS THE FINDING, not this one site**: gunbc#7480 corrected the design document for asserting the wrong type at exactly this `Hash`/`ContentHash` boundary, and a production module now carries the mirror-image error — a boundary documentation has to keep re-explaining is a boundary that wants construction. **THE ENUMERATION IS UNFINISHED: two is what has been measured, not the count.** Assume a third seam exists until someone enumerates them; note that this row's own originating incident (#8854) reached its victim through a record literal one hop downstream of the direct call, so the two seams are not even cleanly separable at a site. **SEAM (1) WAS EXECUTED TO A MEASURED, BLOCKED STOP ON 2026-08-22 — the arm is NOT deleted, and this paragraph is the §4b row for that state rather than a plan.** Rung: **below floor, unchanged** — the judgment still does not run for any `v2.*` caller. Ceiling: **R2** (a declared parameter type is a decidable conformance check the seam already computes). Next trigger, stated as §4b(2) requires and with its disposition: *a formal parameter declared as an applied generic carries its applied form through resolution rather than reaching the comparison seam as the bare constructor* — **DECLINED at the owning layer on 2026-08-22**, on the ground that a bounded compiler-floor packet whose completion condition has moved should close and hand its residue forward rather than extend into a type-system project. A declined trigger is a legitimate §4b state; **a blocked class with no row is how this exemption survived years in the first place**, which is the reason this row exists at all. Enrolled evidence, so the class stays countable while blocked: `direct_call_arg_type_v2_module_red_probe` (the discriminating RED, rostered in `v2.workflow.floor_expected_red` — it cannot pass while the arm stands and PASSES on a tree with the arm deleted, so it is a satisfiable assertion held open by a named cause), plus two controls that pass on main today (`direct_call_arg_type_ordinary_module_red_probe`, the paired nonzero the exemption never covered; and `direct_call_arg_type_v2_green_control_probe`). **What was measured before the stop, and how to read it:** deleting the arm produces **285+k** blocking diagnostics and **67+k** with gunbc#8873 merged, for some k ≥ 1 unmeasured — these are ROSTER-RESOLVED counts, not corpus counts, and `src/v2/extdeps/formatters/lean4_format.dag:184` is the proof: a live site, structurally identical to eight that refused, contributing zero to *both* arms and therefore invisible to their difference. **Zero genuine call-site defects were found in the residue** — every diagnostic examined was a deficit in the type judgment, so no call sites were edited, because 67 mechanical edits would have cemented three compiler deficits permanently. The per-mechanism split of that residue is deliberately NOT recorded here: it was published as 48/11/8, and the rule the 48 were attributed to was then found to admit nothing in this corpus, so the attribution was retracted before it was cited. Trigger for the count to be restated: the residue re-measured with its `why` column. **The counterexample that retracted it is worth carrying on its own, because it will bite anyone who reaches for a name-keyed alias relation:** `type Float = Float64` is declared in BOTH `dag/std/float.dag:18` and `src/v2/std/float.dag:33`, spelling the target identically — but `dag/std/float.dag:16` has `type Float64 = Real64` (a transparent alias) while `src/v2/std/float.dag:30` has `Float64` as a **record**. So the two declarations agree on a *spelling* and disagree on a *type*, and a unanimity rule keyed on the target's NAME admits them as the same concept. Requiring the target itself to be census-unique closes it — and once closed, that rule admits nothing in this corpus, which is what falsified the attribution above. Found by still-carp-717 while building the rule, before it shipped. **The original trigger text, kept because the sequence it specifies was followed and the record should show what was attempted:** seam (1) — turn the exemption off for `v2.` behind a measured diagnostic count, triage, then delete the arm, the disposition the compiler-module arm received; the measured prerequisite is ALIAS TRANSPARENCY, because proud-ant-819's report-only shadow on the 03_ingest closure found 115 `WouldDiagnose` relations at 78 sites of which 115 reduce to a transparent `type A = B` (92 via `type Hash = Fnv1a64Structural`, 23 via the `Node` phase carriers), residue ZERO — so on that closure the exemption is currently suppressing false positives, not defects. Seam (2) — its own wall at record-literal field conformance; nothing to turn off, it was never on. **Closing seam (1) MUST NOT be read as closing the class**, which is the specific failure this correction exists to prevent: a class that looks like it has one closing condition gets closed when that condition fires. Two blind spots neither instrument covers, named rather than left to be rediscovered: production itself SKIPS an anonymous record literal standing as an ACTUAL at a direct call, so its argument type is never judged (521 relations, 2.7%, `Unadjudicated` in proud-ant-819's shadow — upstream of the guard, so invisible to a flip-off arm too); and a function storing into a field from its own differently-named parameter is this class at yet another site, which a callee-name-keyed census cannot see. **THAT FIRST BLIND SPOT IS NOT SEAM (2), AND THE TWO WILL BE MERGED BY ANY READER WHO DOES NOT SEE THIS SENTENCE** (caught by proud-ant-819, who put the mirror-image clause in their own row): both descriptions begin "a record literal" and name DIFFERENT POSITIONS. The blind spot is a record literal at an ARGUMENT position whose type goes unjudged at the direct-call seam — seam (1)'s territory, and a population of 521 relations. Seam (2) / gunbc#8865 is a record literal's FIELD whose value does not inhabit the field's declared type — a different seam with a different mechanism and no measured population. Reading them as one would make the 521 look like evidence for gunbc#8865, or gunbc#8865's receipt look like it bounds the 521. Neither is true **A CLAIM ABOUT THIS ROW'S EVIDENCE WAS MADE HERE AND IS RETRACTED, MEASURED WRONG (2026-08-22, the §11 item 28 lane, retracting itself).** The retracted claim was that these probes sit in the declined `ReadsLiveTree` carrier and therefore never execute, so the expected-red enrolment could only be `not_evaluated`. **It is false, and the measurement that refutes it is the run that was supposed to confirm it:** run `32586093086` reports `[expected-red-roster-join] roster=207 still_red=207 now_passes=0 not_evaluated=0` with `known_red_held=207`. The v2-module red EXECUTES and is held still-red exactly as its row intends. The error was reading an IMPORT as a location: `guarantee_probe_corpus_witness` imports the three probe ids for a roster assertion, and I took that for where the probes run; they run in `test.claim.direct_call_argument_type_witness`, a separate file. An import is evidence of visibility, never authority for where a name lives. **What survives is a different and sharper finding.** That file executes because it declares `SubstrateInputsOnly` while calling `compile_dag_diagnostic_census` — the same declaration `gunbc.compile_diagnostic_census`'s own live-tree note already adjudicated as a MIS-declaration when it found `transport_script_wall_compile_red_test` doing it (that census walks `build_module_path_index_from_witness_roots`, i.e. the live checkout). So the specimen population for that mis-declaration is now TWO, the second authored on 2026-08-22 after the first was adjudicated, and both are the only reason any census-compiling probe executes at all. Either these files' declaration is wrong or that authority's note is; they cannot both be right, and which one it is decides the size of §11 item 28's population. That is a question for the arm's owner, not a defect in this row's measurement, which stands. | +| A value that does not inhabit its declared type is accepted — **seam-split, enumeration UNFINISHED** (was filed as "Direct-call argument TYPE conformance, v2 corpus"; renamed 2026-08-22, see the trigger cell) | **Below floor — the judgment never runs.** Not a hole a bad value slipped through: `v1.compiler.04_infer` gates `arg_compat_diags` on `module_skips_direct_call_arg_check(module_name: scope.module_name)`, which returns true for every module whose name begins with `v2.`. The key is the CALLER's module, so the entire active v2 corpus — compiler stages, extdeps, std, witnesses — has the direct-call argument-type judgment switched off. Measured consequence, 2026-08-22: `v2.extdeps.languages.dag` `dag_int_literal_node_from_lexeme` / `dag_int_literal_node_from_magnitude` declared `occurrence_id: OccurrenceId` since gunbc#6558 while storing that parameter straight into `Node.occurrence_id`, declared `NodeOccurrenceId`. For two months 15 call sites passed `SyntheticOccurrence` (a NodeOccurrenceId, contradicting the declaration) and nothing complained; gunbc#8833 made one call site OBEY the declaration and nothing complained about that either. The error surfaced only as an interpreter `non-exhaustive pattern match on: OccurrenceId { value: 79 }` across 16 witnesses, reddening main. **The inversion worth naming: a declaration that lies is inert while every caller contradicts it in the same direction, and detonates on the first caller who takes it at its word.** So the at-risk population is not "callers who got it wrong" but callers who might get it right — a genuinely counterintuitive census. Note this is the TYPE judgment only; the SHAPE judgment (`direct_call_shape_diags`, labels/arity) is exemption-free and does fire | R2 (a declared parameter type is a decidable conformance check the seam already computes — `direct_call_arg_mismatch_diags` exists, is written, and is simply not called, so the distance to the next rung is an if-statement plus a triage, not an implementation) | **THIS ROW IS A CORRECTION TO DESIGN §4b, NOT A NEW OBSERVATION BESIDE IT — read them together or the first will look like it already settled this.** DESIGN §4b names this exact symbol and reports that it "was found (code read, not execution) to be scoped entirely to the direct-call argument-type judgment and does not reach `sole_constructor`'s construction check at either call site — a positive finding that retires this axis, not an absence of any exemption anywhere." That finding is correct and is not disputed here. The question it asked was whether the exemption LEAKS into `sole_constructor`; the question it never asked is what the exemption COSTS inside the judgment it is scoped to. "Scoped entirely to the direct-call argument-type judgment" reads as reassuring only until that judgment is measured, and it is the argument-type check for the entire active v2 corpus. **Confinement was measured and then treated as safety, and the axis that got retired was not the one that mattered.** Two facts about why the seam nonetheless reads as covered: the SHAPE judgment (`direct_call_shape_diags` — labels, arity, duplicate binding) is exemption-free and DOES fire over every module including the compiler's own sources, so half-live is more deceptive than dead — every casual check finds something working. And the arm is NOT unreasoned: `direct_call_shape_wall_note` states the TYPE judgment's false-positive classes are representation gaps (brand aliases, optionality's two forms, anonymous literals, expansion depth — the conformance wall's four measured classes), which is a real stated reason and is why this row asks for a measurement rather than a deletion. What is unmeasured is whether those classes still fire in v2 today and at what rate. The neighbouring compiler-module arm of this same exemption was deleted in place after being found never to have been in force; the `v2.` arm was left standing at that moment without separate justification of its own | This incident, measured end to end: CI run 32542017600 (main, 67437fcbe9) 16 FAIL with the raw-`OccurrenceId` match error; caller census of both functions read at call grain (17 sites: 15 `SyntheticOccurrence`, 1 `node.occurrence_id`, 1 internal pass-through, 1 raw `minted.id`); exemption mechanism read at `v1.compiler.04_infer` `module_skips_direct_call_arg_check` and its single call site gating `arg_compat_diags` on `scope.module_name`. **NOT ENROLLED**: no probe pair asserts this exemption's reach, so nothing reds if it changes | **THE TRIGGER THIS ROW SHIPPED WITH WAS INCOMPLETE AND IS CORRECTED HERE (2026-08-22, swift-badger-524 retracting their own ruling).** As merged in gunbc#8854 this cell named ONE closing condition — delete the `v2.` exemption — which is a NECESSARY condition presented as a sufficient one. The class is not "direct-call argument type conformance"; it is **a value that does not inhabit its declared type is accepted**, and it has at least TWO seams: **(1) direct-call arguments** — gated off for `v2.*` by `module_skips_direct_call_arg_check`, the mechanism this row measures; **(2) record-literal fields** — gated by NOTHING, below floor in ORDINARY NON-v2 MODULES, receipt gunbc#8865 (gentle-eagle-360). Its minimal pair, no compiler internals involved: `CppHolder { subject: CppWrapped { inner: cpp_inner() } }` accepted and correct, against `CppHolder { subject: cpp_inner() }` — a coproduct PAYLOAD inhabiting a field declared as its parent COPRODUCT — ACCEPTED BY TYPING and dying at runtime as `PatternMatchFailure`. A record literal is not the direct-call seam, so deleting the exemption would not close it. **SEAM (2) NOW HAS A LIVE PRODUCTION SPECIMEN, WHICH RANKS IT DIFFERENTLY FROM A SYNTHETIC PAIR** (gentle-eagle-360, 2026-08-22, found while checking for a second content-identity authority before building on one): `v2.std.materialize` declares `MaterializedNode.hash` as `ContentHash` — the subject-generic union — and `materialize_fold_step` stores `content_hash(n)` into it, which returns `Fnv1a64Structural`, the PAYLOAD carried inside the union's `Fnv1a64` arm. Receipt, by execution against the module as it stands on main: taking the value materialize ACTUALLY STORED and asking the union's own family authority `content_hash_family` about it yields `PatternMatchFailure { value: "Fnv1a64Structural { digest: 7ac77ab0e29c6bd8 }" }`; the probe's fallback was a correctly wrapped `Fnv1a64(...)`, so an empty result or a well-formed value would have PASSED and only a stored value can produce that red. **The defect is LATENT and that is the instructive part**: peer lookup compares `e.hash == h`, raw payload against raw payload, which agrees with itself — so every current path is green and the error surfaces only when a materialize hash is routed through the union's own machinery (`content_hash_family`, or `compare_content_hash`, which exists precisely to refuse cross-family collapse). That is the same shape as this row's own originating incident: **a declaration that lies is inert while every consumer contradicts it in the same direction, and detonates on the first consumer that takes it at its word** — here the first cross-family artifact to reach the carrier. Disposition ruled ARM A, wrap the construction (`MaterializedNode { hash: Fnv1a64(h), ... }`), NOT narrow the declaration: narrowing would sever `MaterializedNode.hash` from `RealizationPlan.target`, and §2's Realization spans resolve-cost, sccache and OS provisioning on ONE content hash, so a structural-only key could never name a realization of a fetched artifact or a provisioned image (swift-badger-524 ruling, 2026-08-22; handed to silent-bear-842 with the receipt, unfixed here because it is that lane's module). **THE SEAM ITSELF IS THE FINDING, not this one site**: gunbc#7480 corrected the design document for asserting the wrong type at exactly this `Hash`/`ContentHash` boundary, and a production module now carries the mirror-image error — a boundary documentation has to keep re-explaining is a boundary that wants construction. ****THAT HAND-OFF IS SUPERSEDED AND THE SPECIMEN IS REPAIRED — corrected in place rather than left standing, because the sentence above says a live production defect is UNFIXED and awaiting another lane, which is the present-tense claim a reader would plan against (gunbc#8876, 2026-08-22).** The wrap landed in the wall's own change by operator ruling: a wall and the repair it forces must land together, since with the wall on and the wrap absent main is red, so only one PR can contain both. `v2.std.materialize` `materialize_fold_step` and `distinct_hashes` now build `Fnv1a64(content_hash(n))`, and the same construction was repaired at four further sites the wall refused for the identical reason — `v2.workflow.operand_flow`, `materialize_witness_test`, `materialization_provider_witness_test` and `heal_revalidation_witness_test`. The receipt above stays as the historical demonstration that the defect was real and reachable; it is no longer a description of the tree. THE ENUMERATION IS UNFINISHED: two is what has been measured, not the count.** Assume a third seam exists until someone enumerates them; note that this row's own originating incident (#8854) reached its victim through a record literal one hop downstream of the direct call, so the two seams are not even cleanly separable at a site. **SEAM (1) WAS EXECUTED TO A MEASURED, BLOCKED STOP ON 2026-08-22 — the arm is NOT deleted, and this paragraph is the §4b row for that state rather than a plan.** Rung: **below floor, unchanged** — the judgment still does not run for any `v2.*` caller. Ceiling: **R2** (a declared parameter type is a decidable conformance check the seam already computes). Next trigger, stated as §4b(2) requires and with its disposition: *a formal parameter declared as an applied generic carries its applied form through resolution rather than reaching the comparison seam as the bare constructor* — **DECLINED at the owning layer on 2026-08-22**, on the ground that a bounded compiler-floor packet whose completion condition has moved should close and hand its residue forward rather than extend into a type-system project. A declined trigger is a legitimate §4b state; **a blocked class with no row is how this exemption survived years in the first place**, which is the reason this row exists at all. Enrolled evidence, so the class stays countable while blocked: `direct_call_arg_type_v2_module_red_probe` (the discriminating RED, rostered in `v2.workflow.floor_expected_red` — it cannot pass while the arm stands and PASSES on a tree with the arm deleted, so it is a satisfiable assertion held open by a named cause), plus two controls that pass on main today (`direct_call_arg_type_ordinary_module_red_probe`, the paired nonzero the exemption never covered; and `direct_call_arg_type_v2_green_control_probe`). **What was measured before the stop, and how to read it:** deleting the arm produces **285+k** blocking diagnostics and **67+k** with gunbc#8873 merged, for some k ≥ 1 unmeasured — these are ROSTER-RESOLVED counts, not corpus counts, and `src/v2/extdeps/formatters/lean4_format.dag:184` is the proof: a live site, structurally identical to eight that refused, contributing zero to *both* arms and therefore invisible to their difference. **Zero genuine call-site defects were found in the residue** — every diagnostic examined was a deficit in the type judgment, so no call sites were edited, because 67 mechanical edits would have cemented three compiler deficits permanently. The per-mechanism split of that residue is deliberately NOT recorded here: it was published as 48/11/8, and the rule the 48 were attributed to was then found to admit nothing in this corpus, so the attribution was retracted before it was cited. Trigger for the count to be restated: the residue re-measured with its `why` column. **The counterexample that retracted it is worth carrying on its own, because it will bite anyone who reaches for a name-keyed alias relation:** `type Float = Float64` is declared in BOTH `dag/std/float.dag:18` and `src/v2/std/float.dag:33`, spelling the target identically — but `dag/std/float.dag:16` has `type Float64 = Real64` (a transparent alias) while `src/v2/std/float.dag:30` has `Float64` as a **record**. So the two declarations agree on a *spelling* and disagree on a *type*, and a unanimity rule keyed on the target's NAME admits them as the same concept. Requiring the target itself to be census-unique closes it — and once closed, that rule admits nothing in this corpus, which is what falsified the attribution above. Found by still-carp-717 while building the rule, before it shipped. **The original trigger text, kept because the sequence it specifies was followed and the record should show what was attempted:** seam (1) — turn the exemption off for `v2.` behind a measured diagnostic count, triage, then delete the arm, the disposition the compiler-module arm received; the measured prerequisite is ALIAS TRANSPARENCY, because proud-ant-819's report-only shadow on the 03_ingest closure found 115 `WouldDiagnose` relations at 78 sites of which 115 reduce to a transparent `type A = B` (92 via `type Hash = Fnv1a64Structural`, 23 via the `Node` phase carriers), residue ZERO — so on that closure the exemption is currently suppressing false positives, not defects. Seam (2) — its own wall at record-literal field conformance; nothing to turn off, it was never on. **Closing seam (1) MUST NOT be read as closing the class**, which is the specific failure this correction exists to prevent: a class that looks like it has one closing condition gets closed when that condition fires. Two blind spots neither instrument covers, named rather than left to be rediscovered: production itself SKIPS an anonymous record literal standing as an ACTUAL at a direct call, so its argument type is never judged (521 relations, 2.7%, `Unadjudicated` in proud-ant-819's shadow — upstream of the guard, so invisible to a flip-off arm too); and a function storing into a field from its own differently-named parameter is this class at yet another site, which a callee-name-keyed census cannot see. **THAT FIRST BLIND SPOT IS NOT SEAM (2), AND THE TWO WILL BE MERGED BY ANY READER WHO DOES NOT SEE THIS SENTENCE** (caught by proud-ant-819, who put the mirror-image clause in their own row): both descriptions begin "a record literal" and name DIFFERENT POSITIONS. The blind spot is a record literal at an ARGUMENT position whose type goes unjudged at the direct-call seam — seam (1)'s territory, and a population of 521 relations. Seam (2) / gunbc#8865 is a record literal's FIELD whose value does not inhabit the field's declared type — a different seam with a different mechanism and no measured population. Reading them as one would make the 521 look like evidence for gunbc#8865, or gunbc#8865's receipt look like it bounds the 521. Neither is true. **A CLAIM ABOUT THIS ROW'S EVIDENCE WAS MADE HERE AND IS RETRACTED, MEASURED WRONG (2026-08-22, the §11 item 28 lane, retracting itself).** The retracted claim was that these probes sit in the declined `ReadsLiveTree` carrier and therefore never execute, so the expected-red enrolment could only be `not_evaluated`. **It is false, and the measurement that refutes it is the run that was supposed to confirm it:** run `32586093086` reports `[expected-red-roster-join] roster=207 still_red=207 now_passes=0 not_evaluated=0` with `known_red_held=207`. The v2-module red EXECUTES and is held still-red exactly as its row intends. The error was reading an IMPORT as a location: `guarantee_probe_corpus_witness` imports the three probe ids for a roster assertion, and I took that for where the probes run; they run in `test.claim.direct_call_argument_type_witness`, a separate file. An import is evidence of visibility, never authority for where a name lives. **What survives is a different and sharper finding.** That file executes because it declares `SubstrateInputsOnly` while calling `compile_dag_diagnostic_census` — the same declaration `gunbc.compile_diagnostic_census`'s own live-tree note already adjudicated as a MIS-declaration when it found `transport_script_wall_compile_red_test` doing it (that census walks `build_module_path_index_from_witness_roots`, i.e. the live checkout). So the specimen population for that mis-declaration is now TWO, the second authored on 2026-08-22 after the first was adjudicated, and both are the only reason any census-compiling probe executes at all. Either these files' declaration is wrong or that authority's note is; they cannot both be right, and which one it is decides the size of §11 item 28's population. That is a question for the arm's owner, not a defect in this row's measurement, which stands. **SEAM (2) IS NOW CLOSED, AND CLOSING IT ENUMERATED TWO MORE — the count is FIVE measured, still not the total (gunbc#8876, 2026-08-22).** **OWNERSHIP, STATED PER SEAM BECAUSE THE CLASS NOW SPANS TWO LANES AND NEITHER CAN CLOSE IT ALONE:** seam (1) is the exemption-gated direct-call seam owned by the paragraph immediately preceding this one, whose next trigger is recorded there as DECLINED rather than pending; seams (2) through (5) belong to the field-inhabitance lane (snappy-tern-856). A lane that lands its last seam will be tempted to close this row. NEITHER MAY: 'my seams are done' is not 'the class is closed', and the row closes only when every seam does — including any seam not yet enumerated. The record-literal FIELD seam is walled: `v1.compiler.infer` `coproduct_payload_where_parent_required` refuses a value whose type is one of the declared coproduct's own variant payload types, consulting `transparent_alias_identity_agrees` over the `SymbolIndex` so an alias-mediated producer is caught too. Rung at that seam: **structurally guaranteed** — no `Accepted` program contains the state there. NOT structurally impossible, because the bad literal is still writable and the compiler refuses it; and NOT the class, which is why the two rows below exist. Evidence, enrolled permanently per §4b(4): `test.claim.coproduct_payload_soundness_witness_test` — the direct RED, the alias-mediated RED, and the positive control that stops a refuse-everything compiler from satisfying either. Turning the wall on WAS the census: EIGHT live sites, none previously known, all repaired in the same change — `ContentHash` from `Fnv1a64Structural` at `materialization_provider_witness_test`, `heal_revalidation_witness_test`, `materialize_witness_test`, `v2.std.materialize` and `v2.workflow.operand_flow`; `LexRules` from `LexRuleSet` at two `src/v2/test/claim/manual` fold tests. **SEAM (3), UNWALLED AND DECLARED, owner the field-inhabitance lane: the module-scope `data` initializer.** `data X: ContentHash = content_hash(...)` stores the payload into a `ContentHash`-declared row and is NOT refused, because a `data` initializer is not a record-literal field. Rung: **below floor**, exactly as seam (2) was. Unguarded: every module-scope `data` row in the corpus. Trigger: the same conformance judgment applied at the data-initializer seam, which needs no new relation — the declared type and the initializer's inferred type are both already in hand there. **SEAM (4), UNWALLED AND DECLARED, owner the field-inhabitance lane, AND IT IS RANKED FIRST OF THE TWO: the list element.** `v2.workflow.locality_affinity` built consumer identities as `list_add_distinct_hash(xs: cs, v: content_hash(n: e.dependent))` — a raw payload into a `List`. Rung: **below floor**, and it does not fail loudly. Measured: repairing the comparands while that producer stayed raw turned FOUR `locality_affinity` witnesses to `Bool(false)` with NOTHING refused at compile time — a wrong answer discovered later, not a diagnostic. That is what makes it rank above seam (3), and the ranking is fixed by a RULE rather than by judgment (operator ratification, 2026-08-22): seam (3) admits a wrong value a correctly-built peer can still catch by comparison — harmful, detectable, recoverable — while seam (4) admits a wrong value AND DISABLES THE COMPARISON THAT WOULD HAVE CAUGHT IT. That is a silent wrong answer, which DESIGN places OUTSIDE the guarantee ladder and forbids outright rather than ranking low, so the two are in different categories and no population argument reaches across the line: a larger set of loud failures does not outrank a smaller set of silent ones. The ranking is a priority order for collisions, NOT a serial queue — seam (3) needs no new relation and may land whenever it is ready. Unguarded: every list, map and collection element position whose element type is a coproduct. Trigger: element-position conformance against the container's declared element type. **SEAM (5), UNWALLED AND DECLARED, owner the field-inhabitance lane: the declared RETURN type.** `fn f(x: Node) -> ContentHash { content_hash(n: x) }` returns the payload where the parent coproduct is declared and is NOT refused. Rung: **below floor**. Measured 2026-08-22 on the gunbc#8876 merge commit, with a liveness control in the SAME compile that produced exactly one diagnostic (the record-literal RED), so the silence is a measurement and not an untested assumption. HOW IT WAS FOUND IS WORTH RECORDING, because it says something about the enumeration itself: it was found by a MIS-WRITTEN PROBE — the author intended an alias-mediated FIELD case and wrote a return position by mistake. Four of the five seams in this row were discovered by accident or by a downstream red rather than by anyone enumerating positions, which is the standing evidence for #8868's instruction to assume a further seam. Unguarded: every declared return type whose type is a coproduct. Trigger: `declared_type_conformance_diags` already runs at this seam and already holds both the declared and the inferred type, so the distance is a payload-membership arm on an existing judgment, not a new walk. **DO NOT READ SEAM (2)'s CLOSURE AS THE CLASS'S.** One seam of four measured is walled; a reader who sees only 'declared-field inhabitance wall landed' will conclude the class is closed, and the next lane would then build on a guarantee covering a quarter of it. Neither seam (3) nor seam (4) nor seam (5) is closed by gunbc#8876, which deliberately did not widen to chase them | | Direct-call argument TYPE conformance — **transparent-alias identity**, v2 corpus | **R2 built and approved for the alias-identity class (gunbc#8873 — OPEN, approved, mergeable as of 2026-08-22; NOT merged, and this row must not be read as landed until it is).** A precomputed transparent-alias identity relation, derived once at census build and consumed as a `String -> String` map lookup per comparison, admits two names that alias the same declaration and refuses everything else. It peels ONLY `type A = B` with zero params, no connective, no children, no properties and no type annotation, and a target with zero children/params/annotation and `return_cardinality == Required` — so brands, `sole_constructor` carriers, refinements, coproduct arms and applied generics are all excluded BY THE ADMISSION TEST rather than by a later filter. Cost bar was declared before implementation and measured after: four crossed A/B pairs, +2.0s on a 454s regen (+0.4%) against per-arm spreads of 29.9s and 40.9s — a measured null. **What it does NOT do is create substitutability: it makes an existing fact visible.** A pre-relation binary already accepts `CommitSha` at an `AttemptKey` formal and already refuses `IntKey` there | R2 for this class. R3 is not reachable at this seam and that is a property of the seam, not of the relation | **The residual population is a DIFFERENT class and the distinction is load-bearing.** Measured 2026-08-22 against the exemption-deleted corpus: 67 refusals, silent-badger-817's CI run 32562740527 at commit `d42bb3eb57c`. **Provenance caveat, stated because it changes what the 48 means:** that tree merged this relation at `9bfd5388c03`, TWO COMMITS behind head `c40ab2d8248`, and the intervening `b0f72158c80` ("Qualify alias targets at census-build time") is exactly the commit that decides the `CoreNode` group — those refusals turn on `Node` being ambiguous by BARE name. So the 67 is a measurement of an OLDER revision of this relation, not of a broken copy of it. Classification of those 67, derived from declarations and independent of any binary: 48 are this alias class; 8 are applied generics (row below); 11 are `Optional` against `String`/`Bool`/`Int` in `v2.extdeps.github.gha_fold_pilot_emit` and are NOT an alias class at all. **The 48-cleared half is verified on 5 specimens, not 48:** at head, with the exemption deleted in the mirror and `exempt=judged` on all 20352 ledger rows, the five comparisons that CI reports as errors in `00_compile.dag` (lines 319, 342, 408, 446, 497) are all present in the ledger and all read `Compatible`. The remaining 43 sit outside that entry's import closure and a whole-corpus re-run against head was in flight when this row landed — treat 48 as classified-and-partially-verified, never as measured. **Also NOT the alias class: the 11** — the diagnostic reads got `Primitive(String)`, so the optional marker is already gone upstream at pattern destructuring and no comparison-seam mechanism can reach them. That 11 was carried as alias residue by two independent sessions and by this lane's own framing; it is recorded here so it is not handed forward under a label that guarantees the next attempt fails. **Open question for whoever takes it, to be CHECKED rather than inherited from this row:** an optionality marker erased at destructuring means a value reaches a position whose declared type it does not inhabit, which is the same floor rule as the direct-call seam census (record-literal walled; data-initializer and list-element open). If Group C is a FIFTH seam of that class it belongs on that row and not on a new one — decide that before minting a class for it. **A second mechanism, `unanimity`, was designed, measured and ABANDONED as unsound, not deferred.** Its specimen and refutation are carried on the seam-split row above and are deliberately NOT restated here — one fact, one authority | gunbc#8873, 9 enrolled floor witnesses in `dag/test/claim/transparent_alias_identity_witness_test.dag` including the over-peel boundary (`IntHandle` at a `String` formal), a coproduct-projection climb, and a blast-radius pair whose Int-alias discriminator refuses. Shadow ledger re-run before the exemption was touched: 20527 rows, all 115 `WouldDiagnose` rows one mechanism. Receipt: `docs/probes/transparent_alias_identity_2026-08-22/README.md` — **FORWARD REFERENCE, NOT A PRESENT FACT:** that receipt lands with gunbc#8873, which is open at the time this row merges. Do not cite it as evidence until that PR is in | the `v2.` exemption arm cannot be deleted while the applied-generic class below still refuses 8 live sites; the exemption is NOT narrowed to those modules (a narrowing would be a shape test correlating with the distinction rather than naming it) | | Direct-call argument TYPE conformance — **applied-generic alias**, v2 corpus | **Below floor — 8 live false refusals, structurally unreachable from the comparison seam.** An alias whose right-hand side is a generic application (`type BlackConfigPatch = ConfigPatchRecord`) refuses at every call site passing it to the matching formal. Specimen, measured by execution 2026-08-22 on a fixture diffed byte-for-byte against the live `v2.std.patch` declaration, with the exemption deleted in the Rust MIRROR and `exempt=judged` on all 20352 ledger rows as the control: `formal_type = Primitive(ConfigPatchRecord)`, `actual_type = Node(BlackConfigPatch)`, `nominal=true container=false kernel=false`, `fname=ConfigPatchRecord aname=BlackConfigPatch`. Population: 9 declarations, all under `src/v2/extdeps/formatters/` (`black`, `clang_format`, `gofmt`, `google_java_format`, `ktfmt`, `lean4_format`, `prettier`, `rustfmt`, `swift_format`), of which 8 produced diagnostics in the CI arm — `lean4_format` is structurally identical and produced none in EITHER arm, so the population is 9 and the measured count is 8+k | R2, and it is decidable — the same equality already accepts the applied form when it is written directly at the formal | **THE FORMAL SIDE IS WHERE THE INFORMATION DIES, and that is the sentence that should stop the next attempt from this direction.** The formal is DECLARED `ConfigPatchRecord` and REACHES the comparison as the bare constructor, with the type argument already discarded. So the equality has one side that structurally cannot hold an argument, and the case split over any representative is EXHAUSTIVE: (a) representative = the applied form with every argument retained never equals the bare constructor, so it admits nothing and all 9 sites keep refusing; (b) representative = the bare constructor admits `ConfigPatchRecord` at `ConfigPatchRecord` for any X and Y, which is exactly the over-peel that erases the distinction. There is no third representative, and widening the carrier does not help — a node-valued map fails identically, because the missing information is not on the relation's side of the map. **Not to be confused with gunbc#8879**, the withdrawn repair that widened transparency AT RESOLVE and was refused by CI in three classes at once (20 direct-call comparisons, 18 variant projections, 3 files of regen drift). What that established is that resolve is the wrong place for a transparency JUDGMENT; preserving an applied form is resolve DISCARDING LESS, which hands the same consumers MORE structure, and is a different claim that has not been measured | executed fixture + shadow ledger with a positive control (`black.dag` must refuse; a zero there is decidably wrong). **NOT ENROLLED**: no probe pair asserts this class, so nothing reds if it changes. Three false zeros were produced while measuring it — twice from patching the `.dag` authority while the binary is built from the emitted Rust mirror, once from a run that PANICKED and reported zero diagnostics — each caught only by a positive control or by another session's raw per-line export, never by an aggregate | **RESOLVE CARRIES APPLIED FORMS AT THE FORMAL POSITION.** Explicitly NOT scoped as of 2026-08-22 (operator-lane ruling, swift-badger-524): a bounded floor-recovery lane whose completion condition has moved is closed honestly rather than extended, and nothing in that ruling says the change is wrong. Until it lands, the `v2.` exemption stays whole and gunbc#8886 stays blocked | | Producer/consumer cardinality | **UnknownUnmeasured** (typed-rejection vs silent-degeneration split unmeasured) | R3 (seam unwritable) | forgeable carrier; no signature propagation (`sole_constructor` audit pending) | §4b | Stage-3 vertical slice | diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index c9c573e04b8..b70b0458aba 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -1985,6 +1985,142 @@ fn type_name_transparently_aliases_to( } } +// THE DECLARED-FIELD INHABITANCE WALL (DESIGN 4b floor: "values inhabit declared types"). +// +// The state this refuses: a record-literal field declared as a COPRODUCT is initialised with a +// value whose type is one of that coproduct's own VARIANT PAYLOAD types. The payload is not a +// member of the parent, so the assignment is unsound -- but until this wall the seam judged only +// kernel scalars (kernel_value_declared_type_mismatch bails unless the ACTUAL is a kernel type) +// and record literals (structured_application_site_type_mismatch bails unless the actual EXPR is +// an ExprRecordLit). An actual that is a CALL -- the overwhelmingly common spelling -- was judged +// by nothing, so the program compiled and died at the first total match over the field. +// +// The receipt is #8865's minimal pair, and the class is not synthetic: it is the mechanism that +// permitted the 2026-08-22 outage. v2.extdeps.languages.dag built `Node { occurrence_id: }` where the field is declared `NodeOccurrenceId` and `OccurrenceId` is the +// payload of its `MintedOccurrence` arm; the value entered the bad state at that record literal, +// stayed latent two months, and surfaced 2,000 lines and one pipeline stage away as +// `non-exhaustive pattern match on: OccurrenceId { value: 79 }` in sixteen floor claims. +// +// THE SCOPE IS THE RECORD-LITERAL FIELD SEAM, AND ONLY IT. This wall does not judge `let` +// bindings, method arguments, or the direct-call argument seam (whose TYPE judgment is separately +// switched off for `v2.*` by module_skips_direct_call_arg_check). Per gunbc#8868, the seam +// enumeration for this class is UNFINISHED -- assume a further seam until someone enumerates +// them -- so this closes one seam and says so rather than closing the class. +// +// WHY THE PREDICATE IS KEYED ON PAYLOAD MEMBERSHIP RATHER THAN ON MISMATCH IN GENERAL. Once the +// two names are established incompatible and the formal is a non-generic coproduct, ANY actual is +// arguably wrong; refusing all of them would make this a general field-type wall, whose +// false-positive classes are exactly the four representation gaps the conformance wall measured +// (brand aliases, optionality's two forms, anonymous literals, expansion depth). Requiring the +// actual to be a DECLARED PAYLOAD TYPE OF ONE OF THE FORMAL'S OWN VARIANTS positively identifies +// the confusion instead of inferring it from an absence, so a refusal here always names a +// spelling the author can point at: the wrapping arm is in the same declaration. +// +// NAME IDENTITY IS BORROWED, NOT REBUILT. A first measured version of this wall refused the direct +// shape (`CppHolder { subject: cpp_inner() }`) and stayed SILENT on the production specimen this +// lane was given as its acceptance target -- `v2.std.materialize` storing `content_hash(n)` into a +// field declared `ContentHash` -- and the isolating pair says why: an otherwise identical fixture +// whose producer returns a TRANSPARENT ALIAS of the payload type was not refused, while the same +// fixture returning the payload type outright was. `content_hash` returns `v2.std.node` `Hash`, +// which is exactly such an alias of `Fnv1a64Structural`. The fact needed -- what a declaration +// aliases -- does not survive `resolve_item_types`, so no amount of peeling at this seam can +// recover it, which is gunbc#8873's finding and the reason its relation is computed ONCE during +// census construction. This wall therefore consumes `transparent_alias_identity_agrees` over the +// `SymbolIndex` the judgment already carries rather than minting a second identity relation, per +// the coordination ruling recorded on that lane. +// +// COST. Every guard ahead of the declaration walk is a string compare or a cardinality read, and +// the walk itself is bounded by the formal declaration's own variant/field count -- never by the +// corpus. Nothing is re-derived from normalized structure: the judgment reads the same resolved +// formal node the seam already holds, and the alias relation is a map lookup on a census built once. +fn coproduct_variant_payload_admits_type_name( + decl: Node, + actual_name: String, + type_env: TypeEnv, + module_name: String, + source_indices: Map +) -> Bool { + decl.children |> any(variant => + variant.children |> any(payload => + let payload_type = match payload.inferred { + Present { value: Resolved { node: rt } } => rt + _ => field_node_type_expr(n: payload) + } + let payload_name = authored_name_at(source_indices: source_indices, node: payload_type) + let names_agree = application_type_names_compatible( + formal_name: payload_name, + lit_name: actual_name, + type_env: type_env, + module_name: module_name, + source_indices: source_indices) || transparent_alias_identity_agrees( + index: type_env.symbol_index, left: payload_name, right: actual_name) + payload_name != "" && names_agree + ) + ) +} + +// The wall's decision procedure, over the record-literal field seam's own formal/actual pair. +// +// TWO EXCLUSIONS ARE LOAD-BEARING AND NEITHER IS INCIDENTAL. `Optional` is the language's own +// cardinality carrier rather than an ordinary coproduct -- a `T` standing in an `Optional` +// position is the declared spelling, not a payload escape -- so both the CardOptional cardinality +// and a formal or actual literally named `Optional` are excluded before any declaration is walked. +// And a GENERIC coproduct is excluded because its payload positions can be type variables, which +// makes "the actual is one of this coproduct's payload types" undecidable from the declaration +// alone; refusing there would be a fabricated refusal, which DESIGN section 5 forbids exactly as it +// forbids a fabricated success. +fn coproduct_payload_where_parent_required( + formal: Node, + actual: Node, + scope: InferScope +) -> Bool { + let source_indices = scope.type_env.source_indices + let either_optional = formal.return_cardinality == CardOptional || actual.return_cardinality == CardOptional + if either_optional || type_node_is_callable(n: formal) || type_node_is_callable(n: actual) { + false + } else { + let formal_name = authored_name_at(source_indices: source_indices, node: formal) + let actual_name = authored_name_at(source_indices: source_indices, node: actual) + let either_is_optional_carrier = qualified_last_segment(name: formal_name) == "Optional" || + qualified_last_segment(name: actual_name) == "Optional" + if formal_name == "" || actual_name == "" || either_is_optional_carrier { + false + } else if application_type_names_compatible( + formal_name: formal_name, + lit_name: actual_name, + type_env: scope.type_env, + module_name: scope.module_name, + source_indices: source_indices) { + false + } else if transparent_alias_identity_agrees( + index: scope.type_env.symbol_index, left: formal_name, right: actual_name) { + false + } else { + let actual_rep = transparent_alias_representative(index: scope.type_env.symbol_index, name: actual_name) + match lookup_type_by_name(env: scope.type_env, name: formal_name) { + Present { value: decl } => + let decl_is_concrete_coproduct = decl.connective == Disj && (decl.params |> count) == 0 && (decl.children |> count) > 0 + let names_a_variant = has_child_named(n: decl, name: qualified_last_segment(name: actual_name), source_indices: source_indices) || + has_child_named(n: decl, name: qualified_last_segment(name: actual_rep), source_indices: source_indices) + if decl_is_concrete_coproduct == false { + false + } else if names_a_variant { + false + } else { + coproduct_variant_payload_admits_type_name( + decl: decl, + actual_name: actual_name, + type_env: scope.type_env, + module_name: scope.module_name, + source_indices: source_indices) + } + Absent => false + } + } + } +} + // The peeling entry point, retained for the record-literal FIELD site, which has // no prepared call plan to carry a peeled formal. It peels inside the ExprRecordLit // arm exactly as before, so a non-record-literal actual still pays nothing. @@ -5457,6 +5593,15 @@ fn infer_record_lit_structural(type_name: String?, field_inits: List, span span: ar_typed.span, module_name: scope.module_name )] + } else if expected_node.return_cardinality != CardOptional + && coproduct_payload_where_parent_required( + formal: formal_peeled, actual: actual_peeled, scope: scope) { + [type_mismatch_error( + expected: node_type_shape(n: formal_peeled, source_indices: scope.type_env.source_indices), + got: node_type_shape(n: actual_peeled, source_indices: scope.type_env.source_indices), + span: ar_typed.span, + module_name: scope.module_name + )] } else { [] } diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 00f07036bf9..250b7fafdc1 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -2985,6 +2985,145 @@ pub fn type_name_transparently_aliases_to( } } +pub fn coproduct_variant_payload_admits_type_name( + decl: Rc, + actual_name: String, + type_env: Rc, + module_name: String, + source_indices: Rc>>, +) -> bool { + { + let mut __found = false; + for variant in decl.children.clone().iter().cloned() { + if { + let mut __found = false; + for payload in variant.children.clone().iter().cloned() { + if { + let payload_type = match payload.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => rt.clone(), + _ => field_node_type_expr(payload.clone()), + }; + let payload_name = + authored_name_at(source_indices.clone(), payload_type.clone()); + let names_agree = (application_type_names_compatible( + payload_name.clone(), + actual_name.clone(), + type_env.clone(), + module_name.clone(), + source_indices.clone(), + ) || transparent_alias_identity_agrees( + type_env.symbol_index.clone(), + payload_name.clone(), + actual_name.clone(), + )); + ((payload_name.clone() != "".to_string()) && names_agree.clone()) + } { + __found = true; + break; + } + } + __found + } { + __found = true; + break; + } + } + __found + } +} + +pub fn coproduct_payload_where_parent_required( + formal: Rc, + actual: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let either_optional = ((formal.return_cardinality.clone() == Cardinality::CardOptional) + || (actual.return_cardinality.clone() == Cardinality::CardOptional)); + if ((either_optional.clone() || type_node_is_callable(formal.clone())) + || type_node_is_callable(actual.clone())) + { + false + } else { + { + let formal_name = authored_name_at(source_indices.clone(), formal.clone()); + let actual_name = authored_name_at(source_indices.clone(), actual.clone()); + let either_is_optional_carrier = ((qualified_last_segment(formal_name.clone()) + == "Optional".to_string()) + || (qualified_last_segment(actual_name.clone()) == "Optional".to_string())); + if (((formal_name.clone() == "".to_string()) + || (actual_name.clone() == "".to_string())) + || either_is_optional_carrier.clone()) + { + false + } else { + if application_type_names_compatible( + formal_name.clone(), + actual_name.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + source_indices.clone(), + ) { + false + } else { + if transparent_alias_identity_agrees( + scope.type_env.clone().symbol_index.clone(), + formal_name.clone(), + actual_name.clone(), + ) { + false + } else { + { + let actual_rep = transparent_alias_representative( + scope.type_env.clone().symbol_index.clone(), + actual_name.clone(), + ); + match lookup_type_by_name( + scope.type_env.clone(), + formal_name.clone(), + ) { + Some(decl) => { + let decl_is_concrete_coproduct = + (((decl.connective.clone() == Connective::Disj) + && ((decl.params.clone().len() as i64) == 0)) + && ((decl.children.clone().len() as i64) > 0)); + let names_a_variant = (has_child_named( + decl.clone(), + qualified_last_segment(actual_name.clone()), + source_indices.clone(), + ) || has_child_named( + decl.clone(), + qualified_last_segment(actual_rep.clone()), + source_indices.clone(), + )); + if (decl_is_concrete_coproduct.clone() == false) { + false + } else { + if names_a_variant.clone() { + false + } else { + coproduct_variant_payload_admits_type_name( + decl.clone(), + actual_name.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + source_indices.clone(), + ) + } + } + } + None => false, + } + } + } + } + } + } + } + } +} + pub fn structured_application_site_type_mismatch( formal: Rc, actual_expr: Rc, @@ -9988,7 +10127,37 @@ pub fn infer_record_lit_structural( scope.module_name.clone(), )]) } else { - Rc::new(vec![]) + if ((expected_node.return_cardinality.clone() + != Cardinality::CardOptional) + && coproduct_payload_where_parent_required( + formal_peeled.clone(), + actual_peeled.clone(), + scope.clone(), + )) + { + Rc::new(vec![type_mismatch_error( + node_type_shape( + formal_peeled.clone(), + scope + .type_env + .clone() + .source_indices + .clone(), + ), + node_type_shape( + actual_peeled.clone(), + scope + .type_env + .clone() + .source_indices + .clone(), + ), + ar_typed.span.clone(), + scope.module_name.clone(), + )]) + } else { + Rc::new(vec![]) + } } } } diff --git a/src/v2/std/materialize.dag b/src/v2/std/materialize.dag index 0bb081c34e5..269338f0ba4 100644 --- a/src/v2/std/materialize.dag +++ b/src/v2/std/materialize.dag @@ -1,6 +1,6 @@ module v2.std.materialize -import std.content_hash { ContentHash } +import std.content_hash { ContentHash, Fnv1a64 } import v2.std.node { Node, content_hash, node_subtree_nodes } import std.realization { Materialization, Recompute, Memoize, Share } import std.computation_identity { ComputationIdentity, StructurallyIdentical, IdentityUnknown, MissingConcept, identity_permits_share } @@ -38,7 +38,7 @@ fn materialized_has_peer(acc: List, h: ContentHash) -> Bool { } fn materialize_fold_step(acc: List, n: Node) -> List { - let h = content_hash(n: n) + let h = Fnv1a64(content_hash(n: n)) if materialized_has_peer(acc: acc, h: h) { list_snoc_item( xs: materialized_mark_peers_share(acc: acc, h: h), @@ -74,7 +74,7 @@ fn distinct_hashes(root: Node) -> List { xs: node_subtree_nodes(root: root), empty: empty_hashes, cons: fn(acc, n) { - let h = content_hash(n: n) + let h = Fnv1a64(content_hash(n: n)) if hashes_contain(hs: acc, h: h) { acc } else { list_snoc_item(xs: acc, item: h) } } ) diff --git a/src/v2/test/claim/locality_affinity_witness_test.dag b/src/v2/test/claim/locality_affinity_witness_test.dag index 2b05721cc42..89881282646 100644 --- a/src/v2/test/claim/locality_affinity_witness_test.dag +++ b/src/v2/test/claim/locality_affinity_witness_test.dag @@ -8,7 +8,7 @@ import std.machine_shape { execution_shape_independent_lanes, } import std.measure { ByteSize, byte_size, byte_size_count, hardware_thread_count } -import std.content_hash { ContentHash } +import std.content_hash { ContentHash, Fnv1a64 } import v2.std.algebra { length } import v2.std.collection { List } import v2.std.dependency { BarrierBefore, DataDependsOn, DependencyView } @@ -54,7 +54,7 @@ data locality_consumer_b_node: Node = Node { occurrence_id: SyntheticOccurrence } -data locality_shared_hash: ContentHash = content_hash(n: locality_shared_node) +data locality_shared_hash: ContentHash = Fnv1a64(content_hash(n: locality_shared_node)) data locality_edge_a: DependencyView = DependencyView { source: locality_shared_node, @@ -70,8 +70,8 @@ data locality_edge_b: DependencyView = DependencyView { usage_site: locality_consumer_b_node } -data locality_consumer_a_hash: ContentHash = content_hash(n: locality_consumer_a_node) -data locality_consumer_b_hash: ContentHash = content_hash(n: locality_consumer_b_node) +data locality_consumer_a_hash: ContentHash = Fnv1a64(content_hash(n: locality_consumer_a_node)) +data locality_consumer_b_hash: ContentHash = Fnv1a64(content_hash(n: locality_consumer_b_node)) data locality_footprint: ByteSize = byte_size(count: 64) @@ -109,7 +109,7 @@ data locality_other_shared_node: Node = Node { occurrence_id: SyntheticOccurrence } -data locality_other_shared_hash: ContentHash = content_hash(n: locality_other_shared_node) +data locality_other_shared_hash: ContentHash = Fnv1a64(content_hash(n: locality_other_shared_node)) data locality_flow_mismatched: OperandFlowRow = OperandFlow { edge: locality_edge_a, diff --git a/src/v2/test/claim/manual/add_body_value_expression_fold_typescript_test.dag b/src/v2/test/claim/manual/add_body_value_expression_fold_typescript_test.dag index 74da1cf7ea2..887250ce648 100644 --- a/src/v2/test/claim/manual/add_body_value_expression_fold_typescript_test.dag +++ b/src/v2/test/claim/manual/add_body_value_expression_fold_typescript_test.dag @@ -64,6 +64,7 @@ import v2.std.verification { BoolWitnessClaim, UnifiedTestClaim } +import v2.std.compilers.lexing { ModeledLexRules } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly @@ -127,7 +128,7 @@ fn add_body_fold_target_model_minus_catalog() -> TargetModel { bundle: add_body_fold_target_model_bundle( operator_catalog: add_body_fold_operator_catalog_minus() ), - lex: ts_fn_add_lex_rules(), + lex: ModeledLexRules { root: ts_fn_add_lex_rules() }, binding_spellings: ts_binding_spellings(), token_class_emit_transforms: target_model_emit_transforms_empty, authority_source_text: ts_source_text_authority(), @@ -141,7 +142,7 @@ fn add_body_fold_target_model_missing_operator_catalog() -> TargetModel { bundle: add_body_fold_target_model_bundle( operator_catalog: add_body_fold_operator_catalog_empty() ), - lex: ts_fn_add_lex_rules(), + lex: ModeledLexRules { root: ts_fn_add_lex_rules() }, binding_spellings: ts_binding_spellings(), token_class_emit_transforms: target_model_emit_transforms_empty, authority_source_text: ts_source_text_authority(), diff --git a/src/v2/test/claim/manual/fold_call_closure_emit_test.dag b/src/v2/test/claim/manual/fold_call_closure_emit_test.dag index 67acaf917b1..8ce53ae0a20 100644 --- a/src/v2/test/claim/manual/fold_call_closure_emit_test.dag +++ b/src/v2/test/claim/manual/fold_call_closure_emit_test.dag @@ -49,6 +49,7 @@ import v2.std.compilers.target_model { target_value_expression_tokens_from_target, value_expr_projection_bundle_node } +import v2.std.compilers.lexing { ModeledLexRules } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import v2.std.host_transport { target_emit_host_runtime_row_unconfigured } @@ -186,7 +187,7 @@ fn fold_call_target_model() -> TargetModel { ) ] ), - lex: ts_fn_add_lex_rules(), + lex: ModeledLexRules { root: ts_fn_add_lex_rules() }, binding_spellings: ts_binding_spellings(), token_class_emit_transforms: target_model_emit_transforms_empty, authority_source_text: ts_source_text_authority(), diff --git a/src/v2/test/claim/materialize/materialize_witness_test.dag b/src/v2/test/claim/materialize/materialize_witness_test.dag index dedb1216bc9..b7bc36aedc9 100644 --- a/src/v2/test/claim/materialize/materialize_witness_test.dag +++ b/src/v2/test/claim/materialize/materialize_witness_test.dag @@ -17,6 +17,7 @@ import std.realization_schedule { cost_account_predicted_zero, runnable_resource_profile_negligible } +import std.content_hash { Fnv1a64 } import v2.std.collection { List } import v2.std.logic { Bool } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } @@ -80,7 +81,7 @@ test fn node_content_hash_is_realization_plan_target() -> Bool { let root = dup_fixture() let other = distinct_fixture() let plan = RealizationPlan { - target: content_hash(n: root) + target: Fnv1a64(content_hash(n: root)) objective: RealizationObjective { goals: [] } schedule: witness_plan_schedule() total: cost_account_predicted_zero() diff --git a/src/v2/test/claim/operand_flow_witness_test.dag b/src/v2/test/claim/operand_flow_witness_test.dag index 1a473181508..a661b62fc52 100644 --- a/src/v2/test/claim/operand_flow_witness_test.dag +++ b/src/v2/test/claim/operand_flow_witness_test.dag @@ -1,7 +1,7 @@ module v2.test.claim.operand_flow_witness import std.measure { byte_size, byte_size_count } -import std.content_hash { ContentHash } +import std.content_hash { ContentHash, Fnv1a64 } import v2.std.algebra { length } import v2.std.dependency { BarrierBefore, DataDependsOn, DependencyView } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } @@ -42,7 +42,7 @@ data operand_flow_consumer_b_node: Node = Node { occurrence_id: SyntheticOccurrence } -data operand_flow_shared_hash: ContentHash = content_hash(n: operand_flow_shared_node) +data operand_flow_shared_hash: ContentHash = Fnv1a64(content_hash(n: operand_flow_shared_node)) data operand_flow_edge_a: DependencyView = DependencyView { source: operand_flow_shared_node, diff --git a/src/v2/workflow/floor_expected_red.dag b/src/v2/workflow/floor_expected_red.dag index 02ecedb0d40..26960bc65ef 100644 --- a/src/v2/workflow/floor_expected_red.dag +++ b/src/v2/workflow/floor_expected_red.dag @@ -389,19 +389,8 @@ fn floor_expected_red_chunk_13() -> List { Cons { head: "test.claim.method_arg_declared_contract_witness_test.w_method_arg_infers_against_declared_contract_not_element_type_test", tail: Empty {} } } -// The record-literal seam of the payload-as-coproduct soundness class (gunbc#8865). ELIGIBLE under -// this roster's own rule: it reaches its subject and answers -- compile_dag_rust_emit_check runs the -// fixture and returns, so the red is a real verdict, not a route gap. Its positive control -// (cpp_payload_inside_its_own_arm_still_compiles) is deliberately NOT enrolled: it must stay an -// ordinary green, or the pair stops discriminating. -// -// This row deletes in the change that lands the wall. The roster's passing-row arm is what makes -// that self-announcing rather than something anyone has to remember. fn floor_expected_red_chunk_14() -> List { - Cons { - head: "test.claim.coproduct_payload_soundness_witness_test.cpp_payload_where_coproduct_required_must_refuse", - tail: Empty {} - } + Empty {} } fn floor_expected_red_chunk_15() -> List { diff --git a/src/v2/workflow/locality_affinity.dag b/src/v2/workflow/locality_affinity.dag index 29f9a861806..d1d35b20f9d 100644 --- a/src/v2/workflow/locality_affinity.dag +++ b/src/v2/workflow/locality_affinity.dag @@ -3,7 +3,7 @@ module v2.workflow.locality_affinity import std.machine_shape { ExecutionDomain, LevelId, MemoryLevel } import std.measure { ByteSize, byte_size, measure_add, measure_le } import std.types { Int } -import std.content_hash { ContentHash } +import std.content_hash { ContentHash, Fnv1a64 } import v2.std.algebra { any, length } import v2.std.collection { List @@ -54,7 +54,7 @@ fn affinity_collect_step(expected: ContentHash, acc: AffinityCollectAcc, row: Op if measure_le(a: prior, b: f) && measure_le(a: f, b: prior) { AffinityCollectOk { footprint: fp, - consumers: list_add_distinct_hash(xs: cs, v: content_hash(n: e.dependent)) + consumers: list_add_distinct_hash(xs: cs, v: Fnv1a64(content_hash(n: e.dependent))) } } else { AffinityCollectRefused { @@ -64,7 +64,7 @@ fn affinity_collect_step(expected: ContentHash, acc: AffinityCollectAcc, row: Op Absent => AffinityCollectOk { footprint: optional_present(value: f), - consumers: list_add_distinct_hash(xs: cs, v: content_hash(n: e.dependent)) + consumers: list_add_distinct_hash(xs: cs, v: Fnv1a64(content_hash(n: e.dependent))) } } } else { diff --git a/src/v2/workflow/operand_flow.dag b/src/v2/workflow/operand_flow.dag index 425cef0b776..4458f8b56e9 100644 --- a/src/v2/workflow/operand_flow.dag +++ b/src/v2/workflow/operand_flow.dag @@ -11,7 +11,7 @@ import v2.std.dependency { import v2.std.logic { Bool } import v2.std.node { Node, content_hash } import std.measure { ByteSize } -import std.content_hash { ContentHash } +import std.content_hash { ContentHash, Fnv1a64 } import v2.workflow.realization_runner { NodeKeyedGraphArtifact, NodeKeyedGraphTransitiveBytesMissingRow, @@ -75,7 +75,7 @@ fn operand_flow_for_edge(artifact: NodeKeyedGraphArtifact, edge: DependencyView) cause: OperandFlowNoOperand { edge: unresolved_edge } } OperandRoot { root: root } => - let operand = content_hash(n: root) + let operand = Fnv1a64(content_hash(n: root)) match node_keyed_graph_transitive_bytes(artifact: artifact, root: operand) { NodeKeyedGraphTransitiveBytesSettled { bytes: bytes } => OperandFlow { edge: edge, operand: operand, footprint: bytes } diff --git a/src/v2/workflow/required_regen.dag b/src/v2/workflow/required_regen.dag index 7d043205fe0..6151d5201e9 100644 --- a/src/v2/workflow/required_regen.dag +++ b/src/v2/workflow/required_regen.dag @@ -113,6 +113,34 @@ type RequiredRegenRefusal // The emitter's product, named by where the author finds it. `produced_paths` are the // generated surfaces actually written under `root`, which is the population a first // mirror is drawn from — including the surface the committed tree does not yet have. +// +// `produced_paths` IS NOT THE DIRECTORY LISTING, AND CONFLATING THEM MAKES THE RECEIPT +// COMPARE A FILE TO ITSELF. The host populates the candidate directory twice over: it +// writes the emitted surfaces, and it then COPIES the hand-maintained support files in +// beside them, because the tree has to be a usable crate and not just a diff. So the +// directory holds strictly more than was emitted — measured 2026-08-22 on the merge at +// 69f62c897e6: 168 `.rs` files present, `planned=132 executed=132` compared. +// +// The consequence is a reading trap in the receipt, not a defect in it. A reader who +// wants to know whether some particular mirror is a true regen of its authority — the +// exact question after any auto-merge that touched a `.dag` and its mirror together — +// reaches for one of three facts, and ALL THREE ARE VACUOUS FOR A COPIED FILE. `planned` +// equals `executed` answers "did every planned file run", never "was the file I care +// about planned": a count cannot carry an identity join. Presence in the candidate +// directory is satisfied by the copy. And byte-equality against the committed tree is +// satisfied BY THE COPY HAVING COME FROM THERE — the file is compared to itself. The +// `// Generated by v1 compiler` header is one notch weaker still: a claim the file makes +// about itself, an inspection rather than a measurement. +// +// THE DISCRIMINATOR IS A PLANTED PERTURBATION, and it is the only one of these that goes +// red when the property fails: change one byte in the mirror under suspicion and re-run. +// A file inside the compared set is named in `changed_paths` and flips +// `first_generation_equal` to false; a file outside it passes unnoticed, which is the +// whole finding. Receipt for the shape, 2026-08-22: a one-line comment planted in +// `v1_compiler_infer.rs` and `v1_compiler_compile.rs` produced +// `FAIL generated surface drift: v1_compiler_compile.rs, v1_compiler_infer.rs` and +// `changed_paths ['v1_compiler_compile.rs', 'v1_compiler_infer.rs']`, establishing both +// as emitted rather than copied. Revert the perturbation; it is an instrument, not a fixture. type CandidateTree { root: String produced_paths: List