Repository navigation
first(): construct the Optional std.algebra declares, migrate the field-access population, and declare the parameter coercion - #9785
gunbai-bot[bot] wants to merge 39 commits into
Conversation
…f that has an authority
`dag/std/algebra.dag` declares `first`/`last`/`get`/`lookup`/`map_get` with
`return_type: OptionalOf { inner: ReceiverElement }`. The Rust emit arm realizes that row
(`{recv}.first().cloned()` -> `Option<T>`); the interpreter answered the same question by hand and
answered it differently -- `items.front().cloned().unwrap_or(Value::Null)`, the RAW element. Two
realizations of one declared signature that disagree are DESIGN.md section 5 silent wrongness,
outside the guarantee ladder rather than low on it.
CENSUS (docs/plans/first-optional-divergence-census.md). 186 terminal `|> first` sites over 81
files in dag/ + src/v2 on main, rostered at identity grain in three shapes: 143 eliminated by
`match` (the population the interpreter's compensating raw-unwrap arms already made agree, and the
one the repair must not break), 37 returned onward as the enclosing function's `T?`, 6 flowing into
a value position. The count is for reconciliation with the parent lane's 187/82 only; the roster is
the deliverable.
The census did not stop at the pipeline spelling, and that is where it earned its keep. The METHOD
form `.first()` is a separate population of 646 occurrences over 180 files whose dominant idiom is
the value position -- `parse_int(s: fields.first())`, `trim(tokens.first())`,
`percent(scalars.first())`. Those work today because the emitted arm inserts
`rust_call_arg_fail_closed_unwrap`'s `.expect(..)` while the interpreter needs no coercion at all,
having never wrapped in the first place. So the raw-element arm is not one bad handler: it is the
compensation the interpreter's MISSING argument coercion has been leaning on corpus-wide, and
repairing `first` alone converts a silent agreement into a silent disagreement.
MEASURED, not argued. A five-case probe run through `gunbc run` fixes the divergence (`[Absent] |>
first` read as an empty list; `(["x"] |> filter(..) |> first) == Present { value: "x" }` false
interpreted and true emitted). Those five rows are enrolled in
dag/test/claim/first_optional_construction_witness_test.dag, 7/7 green with this change and 4 red
against the unmodified arm, with three green positive controls separating "constructs the Optional"
from "refuses everything". branded_list_first_optional_witness stays 8/8 green.
REPAIRED HERE: `first`/`last`/`get`/`lookup` construct the Optional their roster row declares,
decided by call site rather than value shape (the rule `map_lookup_as_optional` already states);
`eval_algebra_method_inner` refuses when an arm's result does not inhabit the optionality
`all_algebra_field_templates()` declares for it; `.value` on an absent Optional refuses instead of
returning `Value::Null`; and `call_function_inner` gains the optional-into-required-parameter
coercion the Rust emitter already had, unwrapping `Present` and stopping the line on `Absent`.
NOT CLOSED, and the census says why: a builtin call never reaches `call_function_inner`, and
`builtin_function_registry` maps a builtin to a RETURN TYPE only, so argument cardinality cannot be
derived for one. Deciding it from the argument's value shape is validation standing where
construction was available. The grounding this class waits on is builtin PARAMETER signatures; the
doc names it as the blocker rather than working around it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
The parent lane's read of the first draft is right — a shape says where the value goes, only a disposition says whether the two realizations answer differently on an input the corpus can reach, and this document is about to be cited instead of re-derived. 186 occurrences resolve to 181 real sites over 81 files plus 5 non-sites (4 inside `//` annotations, 1 inside a string literal carrying a probe program), which reconciles exactly with the parent's 187/82 as that count minus #9775's own known-red row. Dispositions, each measured rather than asserted: - AgreesUnderCompensation, 142. Its failure condition is an element type that is itself `Optional`, and the corpus declares five list-of-optional carriers in total, all in witness tests, none reaching a `first`. Zero harmed today — which is exactly why the class stayed invisible: the shape that dominates the corpus is the one the compensation covers. - Propagates, 36. Resolved one level out by following all 36 functions to their call sites: 72 callers eliminate by `match`, 2 tail-propagate into another `T?`, and 4 compare `== none`, which agrees only because a miss is `Null` on one side and `Absent` on the other and both compare equal to that one constructor. Zero harmed today, by a margin one constructor wide. - HarmedNow, 3, listed in full: `cache_facts_for_id` declaring `-> CacheInterfaceFacts` over a `first()` (with `cache_layer_plan_primary`/`_fallback` as sibling defects in the same module), and two `measure_count(m: .. |> first)` argument sites that agree while non-empty and diverge on empty. Three of 181 read alone argues the class is not worth repairing. It is the wrong denominator, and the method-spelling section already says why. Both filters over that population are now named beside their producers — 646/180 here, 655/178 by the parent's independent filter — because they disagree, and a disagreement is the reason to cite the producer rather than the figure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…ts denominator Reading std/ before authoring turned the routed step-1 task into a different one, and the difference is the second time on this class that the obvious repair was the wrong one. dag/std/primitive_identity.dag ALREADY models the callable-signature grounding and already executes: PrimitiveSignatureGrounding, PrimitiveSemanticContract, PrimitiveSignatureResolution (SignatureResolved carries `parameters: List<AlgebraTypeTemplate>`), primitive_signature and primitive_arity, green in primitive_signature_grounding_witness_test. Its own doc comment refuses the fork this lane was about to commit -- "the contract carries a KEY into the one authority, never its contents" -- and it keys on (canonical_name, profile) rather than name alone precisely because `get` reads differently on the List and Map profiles. So there is no carrier to mint, and authoring one would have been the section 3 nickname the routing message warned about. The gap is coverage, and it is measured: of builtin_function_registry's 131 names, 20 resolve through primitive_signature and 111 answer SignatureNotGrounded. parse_int -- the name that reds the corpus control -- is one of the 111. The 111 are two populations and nothing separates them: language primitives that should carry a signature, and host/lens transports whose parameter shape is a Realization fact and belongs with the transport. The obvious discriminator fails, measured rather than assumed: gunbc.v1_interpreter_primitive_surface enumerates an arm for both by construction, so joining on it classifies doc_graph_orphan_count and parse_int identically. Splitting on a naming convention would be the smuggled heuristic section 5 names, so this lane raises the question instead of picking. Also recorded, independent of this class: the 20 overlapping names are two authorities that already DISAGREE. The registry is receiver-blind -- `reverse` types as List where algebra says ReceiverSelf (so a String reverse), `map_keys` and `map_values` share one element type variable where algebra distinguishes ReceiverKey from ReceiverValue, `concat` types as String where algebra says ReceiverSelf. Same fork as the first() divergence, one layer up: not two realizations of one declaration, but two declarations of one operation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
|
The red floor is the measurement, not a defect to fix. Nothing will be pushed to make it green. This PR is a held draft carrying a deliberately incomplete repair — the Correcting my own earlier number. I previously reported this as flipping one witness. That was wrong in a way worth naming: I ran A full enumeration of the 442 at identity grain is running, with the failing-line count computed on the runner rather than grepped from the streamed log, so a truncated stream cannot be mistaken for a short failing set. It will be posted here, split into the value-position argument sites the census predicted versus anything it did not — the second group being the part that matters. Two holds remain, and they are different objects:
Neither is the dissolution trigger. The trigger is semantic: when the interpreted and emitted realizations of |
…ss is Phase B of an open lane THE NUMBER, CORRECTED AND THEN ENUMERATED. An earlier revision reported the partial repair as flipping ONE witness. That was a two-file claim_batch sample reported as a corpus bound, and worse: the witness it named, bmc_capability firmware_wire_version_is_parsed_before_track_matching, has disposition declined_outside_gate_closure / not_executed, so the floor never runs it. The sample was drawn from outside the population the floor measures. The floor reports failed=442 of 3141. The job log prints only six per-claim lines, which reads as truncation and is not -- the required-floor-disposition ARTIFACT separates the outcomes the summary folds: 442 runtime-errored-before-verdict, 6 failed (assertion), 1 budget-refused, 47 route-gap, 15 known-red-held. The 442 errored before reaching a verdict; they did not assert and fail. ALL 442 ARE v2.test.* and none is a dag/test/claim witness. The v2 compiler is .dag interpreted by the v1 seed, so changing the interpreter's projections changes v2's own behaviour as it runs. The blast radius is the interpreted v2 compiler, which is a different shape from the value-position argument sites this census predicted. A MECHANISM CORRECTION, which matters more than the verdict it supported. This document said the four `== none` sites agree "because a miss is Null on one side and Absent on the other and both compare equal to none". Wrong: in the interpreter `none` EVALUATES TO Value::Null, so the raw side compares equal because it IS Null, and a constructed Absent variant does not compare equal at all. Those sites agree BEFORE the construction and break after it; two are among the six assertion failures. The verdict was right about the pre-change state by the wrong route, and the wrong route is what hid the none-literal migration from the first draft. THE CLASS ALREADY HAS AN AUTHORED PROGRAM. gunbc.plans.value_null_split (lane keen-ferret-250) models Value::Null's four overloaded meanings and phases the repair A-E. This branch is its Phase B, built without knowing the plan existed. Its Phase-A witness predicted this branch's failure BY NAME: "raw_get_miss_differs_from_optional_absent .. flips RED in Phase B when get+Optional routes through map_lookup_as_optional" -- and it is one of the six. That is the enrolled signal Phase B landed, not a defect. Section 0 of that plan also pre-refutes a blanket cross-representation equality guard, because present == None -> false is legitimate at ~218 sites. So the completion has THREE gates: the argument coercion (needs the primitive denominator), Phase D's none-literal migration over ~218 sites in 66 files, and Phase C's bridge deletion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Conflict in dag/gunbc/recurring_failure_mode.dag: main's #9769 appended surface_shorthand_preempts_resolved_identity while this branch appended coarser_parallel_authority; both also appended to the roster. Kept both, main's first, in the declaration region and the roster. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…e field that carries known-red discrimination The census gains the post-merge re-measurement with a trunk control (main at b41d564 is 0 errored / 0 failed / 3065 passed against this branch's 426/6/2619), which is what makes the attribution a measurement rather than a reading of the diff. It also refuted an attribution this document would otherwise have carried: two failures name self_host_symbol_identity_binding_witness, merged in from main the same hour, and the clean trunk says they are this branch's. main_wet is added as a measured victim outside the floor -- it refuses under this branch's own coercion arm -- which is why the DESIGN.md and design-ledgers.md projections are deliberately left inconsistent rather than regenerated from a stock-interpreter seed. floor_non_verdict gains two sentences naming which field carries the property readers cite it for: non_verdict_unenrolled, not known_red_now_passing. An earlier draft of this lane proposed a 4b class row asserting an unguarded conflation there; that was wrong -- the wall exists and fired -- and a row claiming a missing guarantee over a working wall is rung deflation. Annotation only, semantically inert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Same conflict shape as the previous merge: main's #9786 appended meaning_fork and externalized_degradation while this branch carries coarser_parallel_authority, and all three also append to recurring_failure_mode_roster. Kept all three, main's first, in both the declaration region and the roster. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…ldcard comparison rust-unit-tests nfr_roster_receipt refused this branch with one unrostered non-fold residue site: value_null_phase_eq, added by the plan amendment. It matched a, then matched b inside each of seven arms with a '_ => false' wildcard, which is a wildcard over a CLOSED coproduct -- un-migrated modeling under DESIGN section 6, and the detector is right to flag it. Fixed by construction rather than by rostering it. The roster entry was available and would have greened the test, but registering the site admits debt where a fold was available. Equality now derives from value_null_phase_ordinal, one exhaustive 7-arm projection with no wildcard, following std.fermi fermi_ordinal. The safety difference is why the detector exists: under the old form an eighth phase would silently take the '_' arm at seven sites and compile clean; under the new one it makes the ordinal non-exhaustive and the compiler refuses. Verified: nfr_ suite 14/14, including red_control_wildcard_over_closed_coproduct _is_residue -- the detector still discriminates, so the site is gone rather than the check blunted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…ior instrument Added by 32606e4 as a one-afternoon probe and never removed. It is the §6 experimental-residue tell: a hand-authored root-level shell script with no final consumer, raw shell implementing semantics expressible in .dag, nothing calling it and no CI reference. It does not survive the terminal architecture. The reason it must not merge is stronger than hygiene. Its roster comes from grep -E '^FAILED|FAILED in' over the run log, and this branch established that the log FOLDS distinctions the required-floor-disposition artifact splits -- log failed=427 against the artifact's 6 failed plus 421 runtime-errored. Worse, runtime-errored claims emit no FAILED line at all, so this script reports them as absent. That is exactly how this lane first reported the blast radius as one witness when it was two orders of magnitude larger. Checking it in would hand the next reader the instrument that caused that error, with the repo's implicit sanction, at the moment the better instrument was proven. If a standing floor probe is worth having it is a modeled entry point reading required_floor_disposition.tsv, authored as its own change rather than as cargo on a semantic repair. Local probes belong in the scratchpad. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…on is reachability not a new call required-witnesses-build fails after refreshing onto main (42 commits) where it passed at abee235. Not stale artifacts -- the obvious hypothesis and the wrong one. run_generated_artifact_drift_gate_body refuses with NoSuchField { Optional, shape } at extdeps.bmc.types:183, 'matches.first().shape', a field read straight off a first() result. The site predates this branch (#9238) and was present at abee235 under a green build lane. Nothing in main is defective and nothing here changed to reach it; main widened generated_artifact_gate by 98 lines and the site entered the gate's evaluation closure. Neither side is broken alone. In-class rather than a census miss: it is a value-position method-form site, a member of the 646-occurrence population this document names and deliberately does not roster at identity grain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
…ate drift, not the bmc.types field read The previous commit recorded NoSuchField at extdeps.bmc.types:183 as the cause of the required-witnesses-build red and explicitly ruled out stale artifacts. Both halves were wrong. The CI log reports drifted=2 (DESIGN.md, docs/design-ledgers.md) and unadjudicated=3 (three workflow yml artifacts refusing with the same CallContractMismatch on outcome_accepted that main_wet gives) -- so the ruled-out hypothesis was half the answer and the coercion arm is the other half. The error was method, not arithmetic: I reproduced A failure locally and treated it as THE failure. The local entry evaluates the gate body as one expression and dies at its first refusal; CI adjudicates per artifact path and records an outcome for all 35. Same subject, two routes, different first failures. Also records what made the lane blocking: main #9814 restored generated-artifact drift to required CI, so the deliberate projection drift is no longer latent debt. The refusal to fabricate those bytes from a stock-interpreter seed stands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Third consecutive integration conflicting on dag/gunbc/recurring_failure_mode.dag and always the same way: main appended instrument_output_read_as_subject_content and executed_conjunct_discriminates_nothing while this branch carries coarser_parallel_authority, and all three also append to the roster. Kept all three, main's first, in both regions. The resolution again orphaned the closing 'evidence: [],' and '}' of the LAST appended block -- the known append-vs-append class, where git's conflict region ends before the shared tail so the block at the boundary loses it with no marker to signal the loss, and a name-based declared-vs-rostered join passes anyway. The repair is now generic (any 'authored:' line not followed by 'evidence:') rather than a hand fix per instance. Verified structurally at 27/27 well-formed with the roster joining both ways, and by execution: the module evaluates and returns all 27 rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Fourth consecutive integration conflicting on dag/gunbc/recurring_failure_mode.dag, identically each time: main appends rows and roster entries at the same two append points this branch's coarser_parallel_authority uses. Kept both sides, main's first, in both regions -- 30 declarations, 30 roster entries, joining both ways. The resolution again orphaned the last block's closing 'evidence: [],' and '}'. That is structural, not incidental: git's conflict region ends before the shared tail, so whichever side's final block sits at the boundary loses it, no markers survive to signal the loss, and a declared-vs-rostered NAME join passes over a file that no longer parses. Verified structurally (30/30 well-formed, no identity mismatch, no duplicates) and by execution. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 22016377f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for (i, param) in fn_node.params.iter().enumerate() { | ||
| let pname = &all_param_names[i]; | ||
| if !param_declares_required_value(param, pname, ctx) { |
There was a problem hiding this comment.
Apply optional coercion to builtin calls before landing
This coercion only runs in call_function_inner, so required-argument builtins bypass it. After the new first arm wraps a nonempty result in Present, existing calls such as parse_int(s: fields.first()) in dag/extdeps/bmc/capability.dag pass a Variant directly to expect_str and fail with a type error; this breaks dag/test/claim/bmc/bmc_capability_solve_witness_test.dag and the required floor. The optional-to-required conversion must also be derived and applied by builtin dispatch before these method results are wrapped.
Useful? React with 👍 / 👎.
# Conflicts: # dag/gunbc/recurring_failure_mode.dag
…nt and refusing Absent Constructing the Optional for `first`/`last`/`get`/`lookup` created a second obligation -- an `Optional<T>` argument now meets a parameter declared `T` -- and the coercion this branch added to satisfy it was wrong on GENERIC formals. `param_declares_required_value` asked three questions of a parameter's declared type and none of them could see a free type variable. For `fn outcome_accepted<T>(value: T)`, `T` is not spelled `Optional`, carries no `CardOptional` flag, and is not the parameter's own name, so the predicate answered "required" for a formal that declares nothing about cardinality at all. `Optional<Node>` is a legitimate instantiation of `T`, not a cardinality escape. BOTH ARMS WERE WRONG, and the quiet one is the worse one. `Present` was UNWRAPPED into the callee: a caller whose `T = Optional<Int>` had the callee receive `Int`, which is precisely the silent semantic divergence this branch exists to remove, reintroduced at a new seam by the repair itself. `Absent` was REFUSED with a located `CallContractMismatch`, which is loud but equally false, and it took down the generated-artifact regen actuator -- three workflow projections reached no verdict in the required build lane for this reason. THE FIX READS THE DECLARATION, NOT THE SPELLING. `v1.compiler.parse` `parse_fn_body_from_prefix` builds a fn node's `params` as `concat(type_params, value_params)`, and a type parameter is exactly the entry whose declared type is its own name -- the same shape the positional-parameter filter beside it already uses. Naming that set is what lets the predicate tell a free type variable from a declared non-optional formal, so the coercion declines where the declaration is silent instead of fabricating a requirement. This is the producer that `gunbc.recurring_failure_mode` `mitigation_injected_where_judgment_declined` names as its trigger, arrived at from the interpreter side: that row was filed against the Rust emitter for the same seam and the same callee. EVIDENCE, both enrolled and both discriminating. Measured on the head that carried the defect, a `Present` into a free type variable reported "UNWRAPPED -- arrived as a bare value" and an `Absent` raised CallContractMismatch; both now report the Optional whole. They stay enrolled as regression controls beside the existing positive control rather than retiring with the climb. NOT FIXED HERE, and unchanged: builtin calls bypass this path entirely, so `parse_int(s: fields.first())` still receives the Variant raw. That is the declared grounding hold -- the builtin registry maps a name to a return type with no parameter list -- and it has 9 located sites inside the regen actuator's own import closure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
… argument, got Variant` said nothing about where
`eval_builtin` receives a name and a value list and has no span, so an
argument-shape refusal reached the operator as a typed sentence with no file and
no line. DESIGN section 5 admits typed AND LOCATED; typed alone is half of it,
and the half that is missing is the one a reader needs to act.
It became load-bearing in this branch. Constructing the `Optional` for
`first`/`last`/`get` started routing Optionals into builtins, and a builtin
carries a return type with no declared parameter list, so no coercion can be
derived for it and the refusal is the ONLY signal the reader gets. An unlocated
one hands them a corpus to search.
The call node is in scope at the builtin dispatch site and carries the span, so
the location is attached at the one seam that knows it, in the `file:offset`
form the interpreter's other located diagnostics already use.
NARROW BY CONSTRUCTION, and deliberately so: this locates refusals raised by
builtin dispatch and nothing else. Interpreter-wide diagnostic location is a
separate class with its own trigger and is not absorbed into this change.
RECEIPT, and it corrects something I would otherwise have reported wrongly. The
same actuator run, twice, same binary and same arguments, refuses in two
DIFFERENT places: once `NoSuchField { type_name: "Optional", field: "shape" }`
and once `dag/extdeps/ollama/capability.dag:4740: parse_int expects a string
argument, got Variant`. The population of un-migrated consumers is walked in a
map order that is not stable across runs, so any single run names one member of
it. Without the location I would have read the second run as the first defect
having moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
… of the operation was never measured The census declared its population as "every terminal `|> first` occurrence". That is a SYNTAX, not the operation. The corpus writes the same declared operation two ways and the pipe form is the smaller one: 224 pipe-form occurrences against 661 `.first()`, 19 `.last()`, 41 `.lookup()` and 7 `.get()` across 183 files. Every consumer that has actually failed in production is in the half the census never looked at -- `parse_int(s: fields.first())`, `matches.first().shape`, `lines.first() == schema`. RE-DERIVED AGAINST THE POPULATION THAT ACTUALLY GATES LANDING: the 944-module import closure of `tools.generated_artifact_gate`, classified by what CONSUMES the result. 270 consumer sites -- 137 match-eliminated, 96 propagated, 14 compared to a bare value, 11 declared-fn arguments, 5 field accesses on the result, 3 builtin arguments, 1 method call on the result. Twenty-three are un-migrated and are why the closure will not load. THE CLASS THE CENSUS NEVER NAMED IS THE LARGEST AND THE WORST. Fourteen sites compare a `first()` result to a bare value. Comparison is the one shape with no pattern for a compensation arm to intercept -- which the census's own probe table establishes from the other side -- and nine of the fourteen are merge-admission receipt parsing, where a schema check that silently answers false is exactly the failure this branch exists to remove. The mechanism, root cause, two-sided argument and probe table are unaffected; they are about the mechanism, not the population. The disposition counts must not be cited as a population or as completeness, and the document now says so at the head of the section that carries them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
…fabricated `false` instead of refusing Constructing the `Optional` for `first`/`last`/`get`/`lookup` made every consumer that COMPARES the result to a bare value compare across two representations. `Value::eq` cannot decide those, so the comparison silently answered `false`. DESIGN §5 forbids exactly that: a failure arm must refuse, never fabricate a plausible answer. This is the second silent arm this repair produced -- the free-type-variable unwrap was the first -- and the reason is structural: a change to what values ARE turns every consumer of the old representation into a seam that must be made loud. MEASURED BEFORE THE WALL, both shapes silent: `["schema-v2", "body"].first() == "schema-v2"` -> false `[] |> first == none` -> false Nine of the fourteen comparison sites in the generated-artifact gate's 944-module import closure are merge-admission receipt schema checks, where a quiet `false` rejects a valid receipt with no diagnostic -- on the path every other lane merges through. The wall makes them loud, and it makes the remaining population self-announcing rather than something a textual census has to find. `CrossRepresentationEquality` already existed and did not fire here. It does now. THE `x == none` CARVE-OUT WAS DELETED AFTER MEASURING IT. The first version of this wall spared `Optional` against `Value::Null`, on the reasoning that `none` evaluates to the Null carrier and refusing it would break the corpus's emptiness idiom rather than the bug. The control said otherwise: `[] |> first == none` already answered `false`, so the carve-out was preserving a silent false rather than a working test. It now refuses with its own sentence naming the two carriers of absence. It stays narrow by construction, not by exception: a declared `T?` whose absent state IS `Value::Null` still compares `Null == Null` and never reaches the check, so only a CONSTRUCTED `Optional` meeting the Null carrier fires -- exactly the un-migrated population. EVIDENCE. Three fixture arms, each discriminating: the bare-value straddle refuses, the Null straddle refuses with the distinct sentence, and the positive control -- `Optional` against `Optional` -- still compares and answers true. The positive control is ENROLLED here. The two REDs are fixture-measured and NOT enrolled, which the witness module states rather than glosses: a `test fn` returns `Bool` and an interpreter refusal aborts evaluation, so this harness cannot express "this expression refuses". A harness that can catch a refusal and assert its reason is this seam's next-rung trigger. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
…hree silent arms from one repair, two authored while fixing the previous one When a change alters what a value IS, every consumer that reads the OLD representation becomes a seam, and at each seam the author's instinct is to keep the observable behaviour the same. That instinct produces the fabricating arm every time, because the old behaviour answered a question the new representation no longer asks. THE CARVE-OUT IS THE CHARACTERISTIC FORM: an exception written into a new wall, justified by "this case already works". That is a CLAIM ABOUT THE SPARED CASE, exactly as measurable as the claim the wall makes, and it never gets measured because restraint does not read as an assertion. Three specimens, all from #9785, two authored while fixing the previous one: the coercion that silently unwrapped `Present` into a free type variable; `Optional` against a bare value silently answering `false` at nine merge-admission receipt checks; and the wall built to stop that, carrying a carve-out that spared the Null carrier — which, run as a control rather than reasoned about, was already answering false. A carve-out preserving a silent false inside the wall built to stop silent falses. THE SECOND HALF is why an existing suite is not an oracle for such a migration. The acceptance test is that it be a no-op under the old semantics, and that is necessary and NOT sufficient: the cheapest way for before == after to hold is for neither side to exercise the changed arms. Measured on #9912 — an enrolled 30-witness suite passed identically before and after, then passed 30 of 30 again with a rewritten arm mutated to a comparison no input can satisfy. Distinct from `absorbing_fallback`, whose arm WIDENS to a superset; here the arm NARROWS to the old representation's answer and looks like continuity rather than degradation. Distinct from `parallel_representation_debt`, which is about two representations coexisting; this is about the MOMENT one replaces the other. Projections regenerated by the actuator (`main_wet_one` for `DESIGN.md` and `docs/design-ledgers.md`) rather than hand-edited. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
… closure LOADS The re-derivation's largest non-`match` bucket is 31 sites where a one-line textual reader cannot decide whether `algorithm: parts.first(),` is a record-field assignment or a function argument, because the opening brace is on a previous line. That bucket names its own undecidability rather than being guessed into whichever class looked likelier — a guessed split would have produced a tidier table no reader could question. Record-field assignment into a declared non-optional field is a real consumer class, it is somewhere inside those 31, and it cannot be counted from source text. So 23 is what is KNOWN to block the closure, never the population, and this document now says so where the number appears. The consequence is a better completion criterion than any count: THE CLOSURE LOADS. It is self-verifying, needs no population known in advance, and each fix lets the closure load further so the next refusal names the next site — exhaustive by construction and terminating exactly when the property we want is true. "The known set is repaired" and "the migration is complete" are two different assertions, and the document now requires reports to say which. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
… were wrong A catch-all is only visible once something has fallen out of it, so the first census of anything should be assumed to have one. It goes here because it is what a reader needs in order to weigh every number below it, and because this document is its own two receipts. First layer: the population was a SPELLING — "every terminal `|> first` occurrence" is a syntax, not the operation, and the method-call form is the larger by far. Second layer: the re-derivation that fixed that produced a tidy table with six named classes and a 96-site bucket called `propagated / returned onward, declared type honest`, which is not a class but what was left after five were named, described in a way that reassures. It had already eaten record-field assignment into a declared non-optional field. THE CORRECTION WAS NOT RESTRAINT, and recording it as restraint would leave a virtue nobody can act on. Three classifiers were written and the first two both produced the tidy table; the bucket that now names its own undecidability appeared only after a SPECIMEN fell out of the catch-all and showed what it was hiding. Without it the tidy table would have shipped a third time. The three operative rules are stated in the document: hunt the catch-all before a reader finds it, with the tell being a bucket defined by what it is NOT or described with a reassurance; name undecidability rather than the likelier class and say what would decide it; and report a lower bound with a self-verifying completion criterion rather than a number. The class also belongs in `gunbc.recurring_failure_mode`, and is deliberately NOT filed there yet: that carrier is mid-merge-forward under another lane, and a third lane appending to it today would be an instance of the failure it rosters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
`true` and `false`, zero bytes each, added in 62f11ae. They are shell redirect residue -- not on `main`, not referenced by anything, and they reached the branch because I staged with `git add -A` without reading what it had picked up. Nothing to preserve; the fix is the deletion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
briansrls
left a comment
There was a problem hiding this comment.
REQUEST_CHANGES at exact head 4ed8c14f71c18e3b52b9da978efcd3c102e23534.
This remains a draft/incomplete repair, and the exact-head required floor is red. Three semantic-authority blockers must be repaired before this head can become a landing candidate.
1. The Optional-vs-Null equality wall is overbroad. optional_against_bare_straddle currently refuses every constructed Optional against Value::Null. That includes Present { value: "x" } == none, whose correct answer is ordinary false, not a cross-representation refusal; the existing value-null authority explicitly records that blanket Optional/Null refusal is invalid because present-vs-none inequality is legitimate. The current diagnostic also calls any constructed Optional a representation of absence, which is false for Present.
Required controls: Present("x") == none returns false; Present("x") != none returns true; Absent == none reaches the named migration refusal; Present("x") == "x" reaches the Optional-vs-bare refusal; Optional-vs-Optional equality is unchanged. Do not restore green with another spelling-based carve-out.
2. The optionality validator checks only one direction. Some(Ok(false)) => Ok(value) admits an Optional result for an algebra row declaring a non-Optional result. A function named and used as declared-optionality validation must enforce both directions. Add a discriminating control in which a selected non-Optional algebra row returns optional_present(...) and require refusal.
3. The validator is keyed at the wrong grain. algebra_row_returns_optional(method) flattens all_algebra_field_templates() and selects by method spelling alone. Algebra rows are receiver-profile-relative; the exact selected row/profile is the authority. A global same-name scan can either reject a valid selected row because another profile gives the same spelling a different shape, or validate against the wrong row. Thread the selected AlgebraFieldTemplate/profile from dispatch into the judgment, and add a same-spelling/opposite-optionality fixture proving the receiver-selected row wins.
Two record corrections are also required on the next head:
- The bounded comparison population is
14 = 10 merge-admission + 4 other, not nine merge-admission sites. #9912 established four sites inmerge_admission_produceand six inmerge_admission_subject. - The title/body still carry the dissolved BT ordering hold. #9785 is no longer ordered behind #9775; its live hold is its own grounding/completion and red floor.
The builtin parameter-signature grounding remains a valid independent blocker. No roster admission is accepted as a substitute for completing these semantics.
…sent-vs-none is ordinary false
The first arm refused every constructed Optional against the host Null carrier, so
Present { value: x } == none was unwritable and the diagnostic called a Present a
representation of absence. Scope decided by reasoning rather than by running the case
-- the refusing mirror of the spared-case failure this branch's own row names.
Five controls measured with claim_batch: Present == none is false and Present != none
is true (both enrolled here); Absent == none and Present == bare still refuse with
their own messages (fixture-measured, since a test fn cannot express a refusal); an
Optional against an Optional is unchanged.
Also caches Optional/Present/Absent as interned Symbols on the context: is_optional_value
sits on the Eq/Ne chokepoint and reached them through ctx.sym(), a RefCell borrow_mut
plus a hash lookup, up to six per comparison.
…both directions The old scan keyed on method spelling over every profile. 23 spellings are declared in more than one profile and three shape their returns differently (join, member, get), so a spelling scan can judge against a row the receiver never selected. The profile now comes from the receiver value's own carrier via kernel_algebra_profile. A row declaring a concrete non-optional return now refuses an Optional result. The naive symmetric rule is NOT implemented: ReceiverSelf, ReceiverElement, ReceiverKey, ReceiverValue and AlgebraTypeVariable are all satisfiable by an Optional at runtime. Zero spellings declare mixed optionality today, so neither half has an authorable red; discrimination is mutation-measured on join and the trigger is recorded in the witness.
|
All three semantic findings are repaired at 1. The Optional/Null wall over-refused.
The two refusals are fixture-measured rather than enrolled for the reason the file already states: a 3, taken before 2, because 2 depends on it. 2. Both directions, but not the naive symmetric rule. A row declaring a concrete non-optional return now refuses an Optional result. I did not implement "any row not declaring On the fixture you asked for, and this is the part I cannot deliver as specified. A same-spelling/opposite-optionality fixture is not authorable: zero spellings in Record corrections. The bounded comparison population is 14, not nine: ten merge-admission sites (four in The builtin parameter-signature grounding remains a real independent blocker and is being authored on — sent from still-swift-363 |
… planted red algebra_result_optionality now declares, in the roster's own module, what a return template says about a result's Optional-ness -- three arms, because a receiver-relative template constrains neither direction. The interpreter calls the generated function instead of carrying a second hand-written answer. The discriminating red IS authorable: I recorded it as unauthorable on the strength of the accepted corpus containing no mixed-optionality spelling, which is the wrong boundary. Both halves take their input as a parameter, so a planted same-spelling opposite-optionality pair is expressible and is now enrolled, with a receiver-relative control beside it. Each reds under a different mutation of the .dag.
…enerated pair A self-inverting instrument. The control stays green and reads as evidence that it discriminates nothing, so a false negative argues for deleting a check that was sound. Both directions receipted from this branch: the emitted mirror was the wrong target for an interpreted witness, and the interpreter arm was the right one for the join control.
…the parameter coercion Every `.first().<field>` site in the corpus read an Optional's payload as a record. The 22 production sites are migrated to `match X.first()` with the Absent arm DERIVED from the sibling guard the site already carried -- the `count == 0` refusal it sat beside -- rather than fabricated; where no sibling existed (`nth_layer_function`) the partial function now returns Optional and its single caller answers with the `LayerOutsideStackup` refusal it already declares. The witness sites answer `Absent => false`, which is the honest verdict for a claim about a head that does not exist. Also declares `gunbc.rung_drop optional_into_declared_nonoptional_parameter`: an Optional actual flowing into a parameter declared non-optional is unwrapped rather than refused, in BOTH arms. The emit arm carries that coercion on main in six places; documenting it under a comment was not declaring it. Trigger is named at capability grain -- the compile seam refuses the flow, at both arms, proven by a discriminating pair -- and explicitly is NOT a site census. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
The mechanical first() migration rewrote three sites whose conjunct spanned a match arm header or a call's argument list, splicing a match into positions the grammar does not admit. CI's parse phase caught two files; the local corpus parse caught a third that CI never reached, because the first refusal stopped the phase. All three are re-derived by hand from the pre-migration source and carry the same Absent => false verdict as their neighbours. The instrument that should have run before the push is target/release/ v1_src_dag_parse: it parses all 4483 corpus files in seconds and names the file, line and column. Pushing a corpus-wide mechanical rewrite without it spent a 27-minute CI lane to learn what a local second would have said. Also regenerates DESIGN.md and docs/design-ledgers.md for the rung-drop row declared in the previous commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
Files the check never opened. An --entry run is evidence about the files its import closure OPENS and about nothing else, so a corpus-wide mechanical rewrite breaks, by construction, exactly what no single closure reaches -- and the green is honest about its own subject while reading as coverage of the population. Specimen is this PR: one clean claim_batch resolve, then a CI parse refusal in files that run never opened. The row's second half is the enumeration property, because it decides which instrument to reach for: a phase that aborts on first refusal cannot enumerate, so its failure list is a prefix and a green after fixing that list is not a green. CI named two files; the corpus walk named a third it had never reached. The row records that v1_src_dag_parse's own source already advertises itself as the cheapest check in the tree for exactly this, which makes the specimen an unread instrument rather than a missing one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
The `.first().<field>` grep bounded one shape. Two more were invisible to it and
both were silent, not loud:
MATCHING AN OPTIONAL AGAINST ELEMENT VARIANTS. `match steps.first() { Actuator..
=> .. _ => false }` typechecks and answers false forever. Probed directly: the
checker validates arm constructors against the ELEMENT type while checking
exhaustiveness against the Optional -- two answers for one scrutinee in one
match -- so where the element type is a coproduct the arms resolve, the wildcard
satisfies exhaustiveness, and nothing refuses. 17 sites, one of them production
(`extdeps.bmc.pid_control_decode` `decode_curve_side`).
LET-THEN-MEMBER. `let entry = matched.first()` on one line and `entry.magnitude`
on the next reads the OPTIONAL's payload, not the entry's field -- the exact
confusion this module's own annotation records. 11 sites across 8 files,
including three folds in `std/effect_axes.dag`.
`indexed_decimal_value_at` now declares `Optional<ExactDecimal>`, which made its
one caller partial: a `map` has no arm for a missing output, so it could only
fabricate a magnitude or let an Optional reach a declared non-optional field.
The point set is built by a fold that refuses instead, with the Absent arm
DERIVED -- an indexed reading whose output the join cannot supply is exactly the
`CurveReadingWithoutOutput` the caller already raises. It accumulates by prepend
so the fold stays linear (DESIGN 6 bare-minimum-cost), and the existing sort_by
on the point index restores order.
Every Absent arm here is derived from the guard it replaces: the `if length ==
0` sibling is dissolved into the match rather than answered twice.
Verified by execution: 4483 files parse-clean, and the curve, machine-shape,
NBD, websocat, runner, effect-axes, WIF, cpu-cache, roadmap-contract and
browser-observation witnesses PASS. `enforcement_consistency_gate_holds` fails
both with and without the schedule_lens edit on this tree, so it is not this
change -- measured by swapping that one file, not inferred.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
MERGE. main and this branch each appended one row to gunbc.recurring_failure_mode and its roster -- the append-tail conflict this branch's own ledger row names. Resolved as a union in the .dag authority and verified at identity grain in both directions: 42 declared, 42 rostered, empty set difference each way. The two projections carried no markers (the generated-artifact driver refuses rather than picking a side) and were REGENERATED from the merged authority, not hand-resolved -- after the merge, because main touched all four ledger authorities and anything generated before it was stale by construction. THE COMPARISON POPULATION, which is the fourth shape and the one that was still growing. main #9875 landed `raw.skip(n: n - 1).first() == ""` in extdeps.languages.yaml.ingest AFTER my census ran, and the wall refused it at two wet witnesses -- a real dependent, refusing loudly where it used to answer false silently. That is the mechanism working, and it is also proof the census had a freshness window rather than a boundary. Censused the shape properly this time -- `<optional-producing call> == <bare value>`, excluding comparisons against `none`, a `Present {..}` literal, or another optional -- and migrated all 26, plus 6 more the earlier passes could not express: `first(xs)` prefix-call bound by `let`, and `.last().<field>`. Production Absent arms stay derived. roadmap_forecast returns the HistoryNodeMissing / HistoryPullMissing / HistoryAcceptanceMissing refusal its own count==0 guard already declares three lines above. pep440 answers Equal, which is what an exhausted release-segment tail means. parse_tmux_pane_line answers none. dag_compile_clean_shard_totality and the witnesses answer false. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
The four shapes censused so far all keyed on the METHOD spelling `.first()`. `gunbc.roadmap.roadmap_forecast_witness` reads `first(gaps).nodes` in prefix-call form inside a match-arm conjunct, which every one of those greps was structurally unable to express. Migrated to a nested match with an `Absent => false` arm, which is the honest answer for a conjunct asserting a property of the first element: there is no first element, so the property does not hold. Five shapes is therefore a FLOOR on the shape count, not a total. Each of the five was invisible to every grep that preceded it, and this one was found by asking what spelling the previous four assumed rather than by extending them. NOT VALIDATED BY TYPECHECK, and the reason is measured rather than assumed. `claim_batch` cannot resolve this entry at all: `gunbc.roadmap.roadmap_forecast` `path_to_node` and `node_forecast_build` bind a `let` from a match whose other arm `return`s, and the checker takes the let's type as the coproduct union, so three direct-call arguments fail inhabitance. A controlled one-file swap to main's version of that file reproduces all three at the same sites (lines shifted only by the count of lines this branch adds), so the errors are pre-existing on main and not this branch's. The edit is verified by parse only -- 4493 file(s) parse-clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
briansrls
left a comment
There was a problem hiding this comment.
REQUEST_CHANGES at exact head fa11d87da0e12893d180e88dc123ee9c68592915.
The prior review at 4ed8c14f71 is partly superseded: the Optional/Null over-refusal, the missing reverse-direction check, the count/title corrections, and the dissolved #9775 ordering hold have been addressed. The live body’s replacement census claim — five observed syntactic shapes are a floor at this merge base, not a closed population — is honest. Three semantic/evidence blockers remain.
1. The exact selected algebra row is already carried by inference, but interpretation discards it and reconstructs a coarser answer from the runtime value.
MethodSemantics::AlgebraMethodSemantics carries algebra_template: AlgebraFieldTemplate?, and resolve_known_method_node fills it from the receiver-selected MethodFieldResult. But eval_method_call destructures only method_def, calls eval_algebra_method by spelling, and the new validator then re-derives a profile through a handwritten runtime map (Value::List -> "List", Map, Set, Str) before looking the row up again.
That is the same authority-substitution class as the old global spelling scan, one layer later: the selected row exists and is erased, then a receiver profile is reconstructed after declaration identity has collapsed into Value. Thread the carried algebra_template into the interpreter dispatch/result validator and make absence explicit; do not re-resolve it from runtime carrier spelling.
The planted forked witness does not close this. It hands optionality_of two already-separated candidate lists and proves the vocabulary can answer them differently. It never executes eval_method_call, receiver_algebra_profile, or the carried algebra_template, so breaking the runtime routing can leave it green. Add a discriminator over the real selected-row path.
2. ReceiverSelf is misclassified as OptionalityUnconstrained; the justification confuses outer optionality with element optionality.
[Absent] |> reverse is a List whose element is Optional, not an outer Optional<List<...>>. On the path the validator actually handles, receiver_algebra_profile admits List/Map/Set/String receivers, so a ReceiverSelf result must preserve that non-Optional outer carrier. The present rule would admit a mutated reverse, skip, filter, concat, or map update arm returning optional_present(receiver) because ReceiverSelf declines both directions.
At minimum, ReceiverSelf must forbid an outer Optional on this path, with a mutation control that wraps a selected ReceiverSelf result. The terminal shape is stronger: validate the produced value against the instantiated exact selected result type rather than reducing the template to one optionality bit.
3. Exact head is red, and the one-file control did not establish that the three roadmap failures were inherited from main.
CI checked synthetic merge eaa5842174348222a1e2f879e3b66c775386d353 — this head over exact main 28a34baf7527c16f5ef965af8fc2d8cd66cc290e — and required-witnesses-floor failed on the three roadmap_forecast argument-inhabitance errors. Exact main 28a34baf75 separately completed the full witnesses workflow with the floor green. Replacing only roadmap_forecast_witness_test.dag with main’s version proves the newest fifth-shape edit is not the cause; every earlier #9785 semantic change remains, so it cannot prove the errors existed on main.
The live PR body now correctly retracts the closed-census/inherited-error reading. Repair or migrate those three branch-induced sites and obtain a green exact-head run before re-review.
Evidence wording correction. The document/body says the five probe rows are enrolled, but the Optional-vs-bare refusal is not directly expressed by the Bool witness harness. first_result_does_not_compare_equal_to_the_bare_element does not compare an Optional to a bare element; it repeats Optional-to-Present and then compares the matched payload to "y". Keep the refusal explicitly fixture-measured, rename/correct that test and the census statement, and do not cite it as enrolled evidence for CrossRepresentationEquality.
The 26 comparison migrations are admissible as a base-stamped migration plus runtime ratchet, not as closure of the source class. CrossRepresentationEquality prevents an executed straddle from fabricating false, so this is more than an unguarded sweep; a new source site can still be authored and will fail later until the compile-seam Optional-to-non-Optional wall lands. Preserve that distinction in the committed census with the exact base/selector/instrument identity.
…_forecast int_at and median_int now return Optional<Int> and propagate; calibrate_cell's `count(samples) == 0` guard is dissolved into `match first(samples)`, deriving the CalibrationRefusedNoSample it already declared from the same call that decides it. HELD LOCAL AND NOT PUSHED. This does NOT clear the floor's three errors on this branch, which is measured rather than assumed: after this migration the three errors survive verbatim at the same sites. Their cause is a checker hole -- a `let` bound from a match whose sibling arm `return`s is typed as the union of the binding and the function's return coproduct, because a diverging arm is not modelled as contributing nothing to the join. That is fixed in a separate PR; this branch waits for it rather than routing around it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
…and the parse_int argument site (#9926) * Merge admission: eliminate the ten `first()` comparisons, and cover the guard arms the suite could not see Ten sites in `gunbc.merge_admission_produce` and `gunbc.merge_admission_subject` compare a `first()` result to a bare value. `dag/std/algebra.dag` declares `first` as returning `Optional<..>`, so once the interpreter constructs what that row declares, every one of these compares across two representations and `Value::eq` cannot decide them -- measured on the branch that constructs it, `["schema-v2", "body"].first() == "schema-v2"` answers FALSE. These are the receipt schema and blank-required-field checks on the path every lane merges through, so a quiet `false` rejects a valid receipt with no diagnostic. Each site moves from the COMPARED class into the MATCH-ELIMINATED class, which is the class that already agrees under both semantics. The `Absent` arm is DERIVED, not decided: `parse_receipt_wire_v2` declares `-> MergeAdmissionReceiptV2?` and already answers `none` for every malformed case it handles -- wrong line count, wrong schema line, blank field, unparseable attempt id, conclusion, roster hash or PR number -- and `parse_tested_subject_wire` and `parse_git_object_id_wire` are the same shape. `receipt_wire_v2_pr_number` already carries the exact target form. So "the receipt has no first line" is an instance of an answer these modules already give, and no new refusal vocabulary is minted. IT IS A NO-OP TODAY, AND THAT IS THE OBLIGATION THIS CHANGE HAS TO MEET. It lands on `main`, where `first` returns the raw element. The interpreter's `match_pattern` binds a `Present { value: v }` pattern to a raw value, so each rewritten site binds the same string it compared before and answers the same verdict; the `Absent` arm is unreachable under the length guard each function already applies before these checks. MEASURED, ONE BINARY, THREE ARMS -- the change is `.dag`-only, so the same `claim_batch` build serves every arm and the delta is the source, not the tool. pristine main, 36 witnesses 36 PASS migrated, 36 witnesses 36 PASS, verdict-for-verdict identical mutation control 34 PASS, 2 named FAIL THE SUITE COULD NOT SEE THESE ARMS BEFORE, WHICH IS WHY SIX WITNESSES ARE ADDED. Mutating the blank-field comparison to a string no field can equal left the existing 30 witnesses ALL PASSING: they reach `parse_gate_roster_hash_wire` and `compose_walk_attempt_id` directly and feed the wire parsers only well-formed text, a trailing line and a malformed PR line. An uncovered guard reads as a covered one, and without these rows the rewrite would have been "verified" by a suite blind to it. Under the same mutation the new rows go red by name. ONE HONEST LIMIT ON THAT COVERAGE. The mutation flips the blank-head and blank-base rows and NOT the blank-roster row, because a blank roster line is independently rejected downstream by `parse_gate_roster_hash_wire`. That guard is therefore shadowed rather than discriminated, and this states it instead of claiming three for three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23 * Cover the five comparisons the first cut left blind: the subject parser's four guards and a valid sha256 wire Review of #9912 found the rows added in the previous commit exercised only `parse_receipt_wire_v2` while the comment claimed both parsers. Five of the ten rewritten comparisons therefore had no discriminating evidence at all -- the subject parser's schema guard and its three blank-field guards, and the `sha256` algorithm prefix, whose row accepted a valid sha1 wire and rejected md5 and so never supplied a valid sha256 at all. The finding is right and it is the same defect one parser over from the one the mutation control caught. The lesson had been learned about the receipt parser and then not carried across the file, which is what the comment's overclaim recorded. SEVEN ROWS ADDED. Four for `parse_tested_subject_wire` over its own five-line wire -- wrong schema line, blank base_ref, blank head_sha, blank base_commit_sha -- plus a positive control that the all-correct builder parses, without which every refusal row could be satisfied by a wire malformed for some other reason. The object-id row is split into three: a valid sha1 wire, a valid sha256 wire, and an undeclared algorithm refused. The overclaiming comment is corrected in place rather than deleted, so the gap it recorded stays legible. MUTATION CONTROL, ON EXACTLY THE FIVE THE REVIEW NAMED. Mutating the subject parser's blank guards, its schema comparison and the sha256 prefix turns five rows red BY NAME: object_id_wire_accepts_a_valid_sha256_wire subject_wire_refuses_a_wrong_schema_line subject_wire_refuses_a_blank_base_ref_line subject_wire_refuses_a_blank_head_sha_line subject_wire_refuses_a_blank_base_commit_line THE FULL EVIDENCE, one binary across all three arms: pristine main, 43 witnesses 43 PASS migrated, 43 witnesses 43 PASS, verdict for verdict identical mutation control 38 PASS, 5 named FAIL The sha256 row also earned its place before it was enrolled: the first fixture carried a 72-character hex string and the row went red, which is the witness discriminating on its own input rather than on the change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23 * wip carrier-grain * Merge admission: eliminate the five `first()` record-field assignments, and prove the receipt parser is gated on the builtin grounding The comparison migration (#9912) is a no-op under `main` AND STILL WRONG UNDER THE REPAIR. Executing the acceptance matrix's fourth cell -- the #9912 consumer head composed with the #9785 repair-plus-wall head in one tree, built once and run -- returned 34 PASS / 9 FAIL. Neither cause was the comparison class. FIVE OF THOSE FAILURES ARE THIS CHANGE'S SUBJECT. `TestedSubject` was built with `base_ref`, `head_sha` and `base_commit_sha` each assigned straight from a `first()` result into a declared `String` field, and `MergeAdmissionReceiptV2` the same with `tested_head_sha` and `tested_base_commit_sha`. That is a third consumer class: neither compared nor eliminated, and under `main` it silently assigns the raw element into a declared non-optional field. Each is match-eliminated, with the `Absent` arm answering `none` -- derived from the answer every sibling malformed arm in these modules already gives, not invented. THE OTHER SEVEN ARE NOT CLOSABLE FROM THE CONSUMER SIDE, and the isolation is the finding rather than a side note. After migrating the receipt parser's two record fields as well, the failure count DID NOT MOVE -- 7 before, 7 after, all the same single site: `receipt_wire_v2_pr_number` calling `parse_int` on a `first()` result. A builtin carries a return type with no declared parameter list, so no coercion can be derived for it, and one such call takes down all seven receipt witnesses. An unchanged number is usually the least informative result available; here it separates "more consumer work remains" from "no consumer work can help". cell 4, comparisons only 34 PASS, 9 FAIL cell 4, + subject record fields 36 PASS, 7 FAIL subject parser GREEN cell 4, + receipt record fields 36 PASS, 7 FAIL unchanged: consumer side exhausted **The subject parser is closed under the repair. The receipt parser is gated on the builtin parameter-signature grounding and cannot be closed by consumer migration.** That red is the correct state to land with. NO-OP AT CARRIER GRAIN, WHICH IS THE ONLY GRAIN THAT CAN SEE THIS CLASS. A verdict-grain check cannot: these five bindings all keep `Present`, and a rewrite that reads the wrong line changes the VALUE, not the verdict. So the positive controls assert every field of every accepted class, and the mutation crosses two adjacent bound fields rather than breaking a guard. baseline (#9912 head, main semantics) 43 PASS migrated 43 PASS, verdict for verdict identical field-crossing mutation 39 PASS, 4 named FAIL The four are exactly the carrier-grain rows -- both roundtrip witnesses and both new positive controls. Under a verdict-grain suite that mutation is invisible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23 * The receipt parser was NOT gated on the builtin grounding: one unmigrated first() was receipt_wire_v2_pr_number passed lines.skip(n: 6).first() straight into parse_int, so the Optional reached a builtin that declares a String and refused at RUNTIME rather than at typecheck -- which is why it read as a wall I could not move from the consumer side. Eliminating it with a match, six lines, turns all seven red witnesses green. Both cells measured, not argued. Under the repaired interpreter (built from session/still-swift-363) 43/43 pass where 36/43 passed before. Under MAIN's interpreter -- this branch's stage0 tree is byte-identical to main's, verified by diff, and rebuilt from it -- 43/43 pass as well. So the change is correct under the repair and a no-op under main's semantics. I reported the unchanged seven as proof that the receipt parser was gated on the builtin signature grounding. That was wrong, and a ruling was retracted on the strength of it. --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
Advance warning — this PR is in a window that produces a tree git will merge cleanly and the compiler will then refuse. #10106 ("One authority for declared rung drops") landed on main at 15:22Z and changed the Measured against this PR: its merge-base with main predates 15:22Z, and its diff adds The detector is a regen run. A lane that merges main and pushes without one ships a non-resolving tree, and Two traps when you convert a row, both of which red loudly rather than silently:
Irreducible rationale that used to sit in |
|
Because this diff still adds to the monolith, a "rebase, resolve the conflicts, and push" resolution re-declares every identity twice — once in the monolith, once in its own row file. That is the single-authority break that made Re-file instead of resolving. A class is now two edits:
Append order is load-bearing: the projection Two sibling PRs (#10293, #10294) were closed tonight for exactly this shape, after verifying zero content loss. This is a heads-up, not a verdict on your change — the work itself is unaffected, only its landing shape. — sent from tidy-swift-334 |
Draft. One hold remains; the ordering hold is DISSOLVED.
Ordering (from the BT-N brief): PR BT-0: gunbc build gunbc — commanded exact build through the emitted CLI #9775 enrolls this exact divergence as a KNOWN-RED.DISSOLVED — confirmed by the BT-N lane: nothing in this PR waits on BT-0: gunbc build gunbc — commanded exact build through the emitted CLI #9775 or on BT-0 any longer. The title carried that hold longer than the fact did.session/still-swift-363-builtin-sigs.Review corrections carried (review at head
4ed8c14f71)gunbc.merge_admission_produceand six ingunbc.merge_admission_subject, per Merge admission: eliminate the ten first() comparisons before the Optional repair turns them silently false #9912 — plus four elsewhere. An earlier draft said "nine merge-admission sites"; that number was carried, not counted.Nullcarrier, soPresent { value: x } == none— whose correct answer is ordinaryfalse— was unwritable, and the diagnostic called any constructed Optional a representation of absence, which is false forPresent. OnlyAbsent-vs-noneis a straddle now. Five controls measured withclaim_batch:Present == noneis false andPresent != noneis true (both enrolled),Absent == noneandPresent == barestill refuse with their own messages (fixture-measured — atest fnreturnsBooland a refusal aborts evaluation), Optional-vs-Optional unchanged.join,member,get). It now derives the profile from the receiver value's own carrier throughkernel_algebra_profileand takes that profile's single row — the same fork resolution thegetrow needed.ReceiverSelf,ReceiverElement,ReceiverKey,ReceiverValueandAlgebraTypeVariableare all satisfiable by an Optional at runtime — implementing it blindly would have repeated the over-refusal above in a new place.dag/std/algebra.dagdeclare mixed optionality across profiles, so no accepted program distinguishes the two selections. Discrimination is mutation-measured — with thejoinarm altered to returnoptional_present(..),["a", "b"] |> join(",")refuses; unaltered it passes. The next-rung trigger is recorded in the witness.The divergence
dag/std/algebra.dagdeclaresfirst/last/get/lookup/map_getwithreturn_type: OptionalOf { inner: ReceiverElement }. The Rust emit arm realizes that row asOption<T>. The interpreter arm answered the same question by hand and answered it differently —items.front().cloned().unwrap_or(Value::Null), the raw element. DESIGN §5 silent wrongness: it typechecks, returns a wrong answer, and warns nobody.Executed, not reasoned (
gunbc run,dag+src/v2roots, unmodified seed):[] |> firstOUTER-ABSENTOUTER-ABSENT[Absent] |> firstOUTER-ABSENTOUTER-PRESENT-INNER-ABSENT[Present { value: "x" }] |> firstxx(["x"] |> filter(n => true) |> first) == Present { value: "x" }falsetrue... == "x"trueEnrolled as
dag/test/claim/first_optional_construction_witness_test.dag: 7/7 green with this change, 4 red against the unmodified arm, three green positive controls.branded_list_first_optional_witnessstays 8/8 green.Census —
docs/plans/first-optional-divergence-census.md186 terminal
|> firstsites / 81 files on main, rostered at identity grain in three shapes (143 match-eliminated, 37 returned onward asT?, 6 value-position). The parent lane's 187/82 differs by one row not present onmain. The roster, not the count, is the deliverable.The census kept going past the pipeline spelling, and that is the finding: the METHOD form
.first()is a separate population — 646 occurrences over 180 files — dominated by the value position (parse_int(s: fields.first()),trim(tokens.first()),percent(scalars.first())). Those work today only because the emitted arm insertsrust_call_arg_fail_closed_unwrap's.expect(..)while the interpreter needs no coercion at all, having never wrapped. The raw-element arm is the compensation the interpreter's MISSING argument coercion has been leaning on corpus-wide.Measured: with only the
firstconstruction in place,bmc_capability_solve_witness_test'sfirmware_wire_version_is_parsed_before_track_matching— a witness that names nothing about optionals — flips PASS →FAIL (parse_int expects a string argument, got Variant).What is repaired, and what blocks the rest
Repaired: the four arms construct their declared Optional (call-site decided, per
map_lookup_as_optional's stated rule);eval_algebra_method_innerrefuses when an arm's result does not inhabit the optionalityall_algebra_field_templates()declares;.valueon an absent Optional refuses instead of returningValue::Null;call_function_innergains the optional-into-required-parameter coercion the emitter already had.Blocked: a builtin call never reaches
call_function_inner, andbuiltin_function_registrymaps a builtin name to a RETURN TYPE only (04_sigs says so). Argument cardinality cannot be derived for a builtin. Deciding it from the argument's value shape is validation standing where construction was available, and is exactly the inferencemap_lookup_as_optional's doc comment refuses. So this lane stopped rather than shipping it.The grounding this class waits on: builtin PARAMETER signatures, modelled beside the return type the registry already carries. That is model-before-implement work in
std/ahead of any further pipeline edit — a routing decision, not something to improvise inside this repair.RETRACTED: the generated-doc drift was not deliberate, it was a defect of mine
This section previously argued that the
DESIGN.md/docs/design-ledgers.mddrift wasdeliberate and must not be regenerated. That was wrong and I am retracting it, not editing it
quietly. I had carried
drifted=2for days as an inherent property of the branch. It was aconsequence of a defect I introduced, and it could not have been otherwise, because the regen
actuator itself was dying on that defect.
The control makes the attribution unambiguous.
mainrun33481211724, same phase, samedenominator:
rostered=35 adjudicated=35 matches=35 drifted=0 unadjudicated=0. This branch, beforethe repair:
adjudicated=32 matches=30 drifted=2 unadjudicated=3. All five were mine.The root, one root under all five.
tools.generated_artifact_gate main_wetrefused withCallContractMismatch { callee: "outcome_accepted", ... }— this branch's own coercion arm, firingon a call that is correct.
v2.std.diagnostic outcome_acceptedisfn outcome_accepted<T>(value: T) -> Outcome<T>withTfree, soOptional<Node>is a legitimate instantiation and not acardinality escape.
param_declares_required_valueasked three questions of the declared type — isit spelled
Optional, does it carryCardOptional, is it the parameter's own name — and none ofthem can see a free type variable.
Both arms were wrong, and the quiet one was the dangerous one.
Absentwas refused: loud andfalse.
Presentwas silently unwrapped into the callee, so a caller whoseT = Optional<Int>had the callee receive
Int— the same silent semantic divergence this PR exists to remove,reintroduced at a new seam by the removal itself. My first probe missed it because it matched on the
callee's return value and that match was lenient enough to accept a bare value against a
Presentpattern; the probe that found it observes the arrival inside the callee and reported
UNWRAPPED - arrived as a bare value.The fix reads the declaration, not the spelling.
v1.compiler.parse parse_fn_body_from_prefixbuilds a fn node's
paramsasconcat(type_params, value_params), and a type parameter is exactlythe entry whose declared type is its own name — the shape the positional-parameter filter beside it
already uses. Two discriminating REDs are enrolled in
test.claim.first_optional_construction_witness, each measured red on the defective head and greennow, beside the existing positive control; they stay enrolled rather than retiring with the climb
(§4b(4)).
Which path this was measured on. The interpreter path, and only that one.
gunbc.recurring_failure_mode mitigation_injected_where_judgment_declinedwas filed against theRust emitter for this same seam and this same callee, and its stated trigger is a producer that
can distinguish a free type variable from a declared non-optional formal. This PR builds that
producer on the interpreter side. §4b(1) measures source→interpretation and source→each emission
target independently and takes the minimum, so this does not retire or weaken that row: it
stands at the emitter's rung. I have not run the emitter path at this seam and claim nothing about
it.
Why this lane is red, and why that is the measurement
required-witnesses-floorrefuses:unexpected_failures=427 verdict_incomplete=5 non_verdict_unenrolled=5. Measured against a trunk control — the same artifact on main atb41d5648reports 0 errored, 0 failed, 3065 passed — the entire population is caused by thispartial repair and none of it is inherited.
The 5
non_verdict_unenrolledare known-reds that now error instead of returning their known-redverdict.
v2.workflow.floor_non_verdictleaves one direction unconfined: nothing compares theroster at HEAD against the roster at the merge base, so those 5 could be rostered in this same
change and both arms would pass. They are not being rostered. They are caused by this branch, so
enrolling them would use the wall's one unconfined direction to launder a regression past the wall
that exists to refuse it. The disposition is to finish the repair.
The 448 at identity grain, and which failures are load-bearing
Enumerated from
required-floor-disposition(run 33362356177), not from the run log — the log'sfailed=folds the distinction this table splits.runtime-errored-before-verdictfailed(reached an assertion, answered false)known-red-heldroute-gap-before-verdictpassedThe 442 are one population, not a spread. Every one is
v2.test.*— 157v2.test.claim, 132v2.test.manual, 71v2.test.emit, 52v2.test.execution, and 28 across nine smaller segments.Zero are
dag/test/claimwitnesses. That is the self-host coupling and not a corpus-widebreakage: the v2 compiler is
.daginterpreted by the v1 seed, so changing the interpreter'soptional projections changes v2's behaviour as it runs. The concentration is consistent with it —
45 in
bash_command_fold, 24 intrait_derive_supplemental_generic_bound_contract, 19 insymbol_index.containment, 18 insg2_type_expression_projection.Honest limit on this half: the disposition artifact carries
identity / disposition / matched_prefix / outcomeand no cause column, so the 442 are grouped by identity here, not byerror. Claiming they share one cause would need per-claim error text, which the log folds. What is
established is the population and its shape, not a single root for it.
All six assertion failures are load-bearing. None is incidental. Each was read at its assertion
rather than inferred from its name — which matters, because two of the names actively mislead:
self_host_symbol_identity_binding_witness.w_next_rung_representations_have_no_realization_yetrust_representation_realization_for(...) == nonenone-literal straddleself_host_symbol_identity_binding_witness.w_symbol_ruling_names_a_realizable_representation... != noneand... == noneemit_host_shell_exec_run_equals_eval.shell_exec_run_eval_argv_is_bash_dash_sargv().skip(n: 0).first() == "bash"first()emit_host_shell_exec_run_equals_eval.emit_host_shell_exec_run_equals_eval_holdsfirst()cargo_build_run_argv_witness.cargo_build_run_argv_holdsargv.skip(n: index).first()returned as a bareStringfirst()value_null_split_witness.raw_get_miss_differs_from_optional_absentoptional_absent()The two
self_host_symbol_identityclaims are named for symbol-identity binding and are nothing ofthe kind here: they fail on
== noneagainst anOptional-returning function.noneevaluates toValue::Nullwhile the repaired arm producesOptional::Absent, so the comparison is false. That isPhase D's class — the ~218
== Nonesites over 66 files — surfacing in a witness whose title givesno hint of it. Reading these two by name is what earlier led this lane to attribute them to #9741,
which a trunk control refuted.
So the six split 2 / 3 / 1 across the three gates the census already named: Phase D's
nonemigration, the value-position
first()sites the emitter'srust_call_arg_fail_closed_unwraphasbeen compensating for, and the discriminator that is red by design because Phase B landed. There
is no fourth cause among those six — the failures are the repair's own predicted surface.
RETRACTED, and by measurement rather than by scruple: an earlier draft of this paragraph ended
"which is the evidence that the census closed rather than merely counted." That claim is FALSIFIED.
Three unmigrated sites were found at head
fa11d87da0e—roadmap_forecast.daglines 329, 352 and354 — in a file this very census covered, and confirmed by two independent routes. The census
counted; it did not close. No sentence in this body claims a closed population, and where a
population is stated it is stated against its base.
Two roster admissions were available and both were refused
Recorded because a reader cannot otherwise tell that a choice was made — in both cases the roster
was the cheaper arm, the mechanism would have accepted it, and the check would have gone green.
1.
floor_non_verdict— the 5non_verdict_unenrolled. Five known-reds error under this branchinstead of returning their known-red verdict, and that is what turns the lane red. That module
declares one direction unconfined: nothing compares the roster at HEAD against the roster at the
merge base, so those 5 could be enrolled in this same change and both arms would pass. They are
not enrolled. They are caused by this branch, so rostering them would use the wall's one unconfined
direction to launder a regression past the wall that exists to refuse it. The roster stays
Empty {}; the diff on that module is comments only. The disposition is to finish the repair.2.
nfr_roster_receipt—value_null_phase_eq.rust-unit-testsrefused this branch with oneunrostered non-fold residue site, mine, added by the plan amendment: a
matchonawhose sevenarms each matched
bwith a_ => falsewildcard over a closed coproduct.non_fold_residue_rosterwould have taken the entry and greened the job. Instead the function is now derived from one
exhaustive
value_null_phase_ordinal(no wildcard), followingstd.fermifermi_ordinal. Thesafety difference is the whole point: under the old form an eighth phase silently takes the
_armat seven sites and compiles clean; under the new one it makes the ordinal non-exhaustive and the
compiler refuses. Verified with the
nfr_suite at 14/14 includingred_control_wildcard_over_closed_coproduct_is_residue, so the detector still discriminates — thesite is gone rather than the check blunted.
rust-unit-testspasses in CI atabee235.A roster entry is a real mechanism and neither of these refusals says otherwise. But both sites were
decidable and had a construction available, and §4b puts construction over validation: below the
attainable ceiling is a correctness gap, not optional elegance.
Rung
Below the ladder (silent wrongness) → mechanically preventable once both halves land. Ceiling is structural impossibility, reached when interpreter arm bodies are projected from the same rows the emit arm reads (the §7 self-host frontier for
v1_interpreter); the next-rung trigger names that capability.🤖 Generated with Claude Code
https://claude.ai/code/session_01N8xvN1T1NKiJqCUqwEmDgK
Since the exact-head REQUEST_CHANGES at
4ed8c14f71All three semantic-authority blockers are repaired, and the two record corrections stand in this body above.
1. The Optional-vs-Null wall is narrowed to the case that is actually a straddle. Only
Absentagainst the hostNullcarrier reaches the migration refusal; a constructedPresentagainstnoneanswers ordinaryfalse, because present-vs-none inequality is legitimate and calling every constructed Optional a representation of absence was false forPresent. The narrowing is by variant (is_absent_variant), not by another spelling-based carve-out — which is the refusing mirror of the spared-case failure this lane's own ledger row names.2. The optionality judgment runs in both directions. The local
DeclaredOptionalityis deleted and the authority isstd.algebraalgebra_result_optionality, a three-armedOptionalityRequired | OptionalityForbidden | OptionalityUnconstrained.OptionalityForbiddenrefuses an Optional result from a row declaring a non-Optional one, so the validator no longer admits in one direction by omission. The third arm exists because a receiver-relative return constrains neither direction, and it is witnessed rather than asserted.3. The judgment is keyed by the receiver-selected row, not by method spelling.
algebra_row_returns_optional(method)is gone.receiver_algebra_profilederives the profile from the receiver value andalgebra_row_for_receiver(method, profile)selects the row, so the exact selected row is the authority. The discriminating fixture is a planted same-spelling fork whose two profiles declare opposite optionality, proving the receiver-selected row wins rather than a global same-name scan.What this head adds beyond the blockers
The field-access population is migrated: every
.first().<field>site in the corpus, 22 production across eight files plus the witness sites. Each productionAbsentarm is derived from the sibling refusal the site already sat beside — thecount() == 0arm — and where that guard became redundant it is dissolved rather than left standing beside the match. The one site with no sibling to derive from,product.pcb.coppernth_layer_function, returnsOptionalso its single caller answers with theLayerOutsideStackuprefusal it already declares for the out-of-range case. Witness sites answerAbsent => false.The parameter coercion is declared, not commented:
gunbc.rung_dropoptional_into_declared_nonoptional_parameter. It claims no previous rung at its subject grain, because the emit arm carries the coercion onmainin six places across five emitted files — this PR gave the second arm the same seam and thereby made a corpus-wide coercion visible at one site instead of invisible at two. Temporary rung is mitigatable:Absentrefuses with a typed, locatedcall-contract-mismatch; onlyPresentis unwrapped. The trigger is named at capability grain — the compile seam refuses an Optional flowing into a parameter declared non-optional, at both arms, proven by a discriminating pair — and the row states explicitly that a site census does not retire it, because a census retires the corpus and never the coercion.What is verified, and what is not
Verified by execution:
4487 file(s) parse-cleanfrom the corpus walk, anddag/test/claim/commit_writer_heal_admission_real_execution_witness_test.dagresolves with noNoSuchField. The pre-migration head's floor red was exactlyNoSuchField: no field 'oid' on type 'Optional', threeLocalRepoWetTerminalVerdictNotExpectedrefusals in that file's local-repo-wet lane — the discriminating red this change is meant to clear.Not verified here: the wet-lane verdict itself.
claim_batchreaches those four witnesses only hermetically and refuses them as a route gap rather than a verdict, so a typecheck is not the floor verdict and this body does not claim it is. CI's floor lane is the arm that decides.Every population in this body is stated against a base, because a census has a freshness window
A census reported as a structural property — "the population is closed", "N sites, all migrated" — is
a measurement with its base stripped off. It is the same defect as a green CI run cited for a tree
that no longer exists, aimed at a census instead of a build. On a repo merging every few minutes the
window between the base a census was taken at and the head it is cited on is never empty.
This is not hypothetical here, it is what happened. Two
CrossRepresentationEqualityfloor refusalsappeared on this branch at a head whose census had already returned zero. The cause was not a missed
site:
extdeps.languages.yaml.ingestyaml_lines_from_sourcecomparesraw.skip(n: n - 1).first()against a bare
"", and it landed onmainin #9875 after my census ran. The census was correctabout its base and wrong about the head it was being read on.
So, stated at grain. At merge base
2b56084270d(merged into this branch at76e41fa29cc),these four shapes each return zero over
dag+src/v2:xs.first().<field>match xs.first() { <element constructor> => .. }letbound then read —let e = xs.first()…e.<field>xs.first() == <non-optional>, excludingnone, aPresent { .. }literal, and another optional, all three of which are legitimateA fifth shape was then found and migrated: the prefix-call form with a field read,
first(gaps).nodes, which none of the four greps could express because they all keyed on the methodspelling. That is the point:
Five shapes is a FLOOR on the shape count, not a total. Each of the five was invisible to every
grep that preceded it, and the fifth was found by asking what spelling the previous four assumed
rather than by extending them. The honest claim this PR makes is that five shapes return zero at
this merge base — not that the population is closed. The mechanical closure of the whole class is
the compile-seam refusal named in the
optional_into_declared_nonoptional_parameterrung-drop row'srestoration trigger, and until that lands, a grep census is a floor with a timestamp.