Skip to content

Pkg11c: lower variant and record fields into declared field identities on the native route, and bind match-arm binders - #12033

Merged
gunbai-bot[bot] merged 59 commits into
mainfrom
session/quick-bat-813
Sep 23, 2026
Merged

gunbai-bot[bot] merged 59 commits into
mainfrom
session/quick-bat-813

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Pkg11c. On the native route no v2 stage lowered a variant or record field: type C = A(Int) | B kept A(Int) as a preserved positional_variant_payload shell, records went to the graft's residual forest, and a match pattern kept only its constructor atom — A(x) => x lost x. This lands the field model in std and ONE stage that lowers declarations, constructions and eliminations through it, plus the resolver frame that binds the arm's binders.

Base and landing order

#11998 is OPEN, not merged. dbaf88c9adb is on session/gentle-tern-521, not on main, so this branch CARRIES #11998's commits rather than building on landed work. Landing order set by the manager: #11998 first, then this. If #11998 lands first, its commits collapse in the squash; confirm the diff against main then contains only this lane's work.

Two of the converted witness modules are #11998 authorship carried here — the coproduct rows — converted on this branch because the floor enforces the per-claim ceiling here and they breach it here. The module annotation says so, so this is not editing someone else's claims unannounced.

What this does NOT close — read this before the rung-drop row

An earlier revision of this body claimed this PR closes the standing HOLD on #11998 and retires variant_fields_unlowered_on_the_native_route. That claim is withdrawn and the row STANDS, narrowed to one residue.

Both halves of the trigger execute: the lowering (body_lower_type_variant, body_lower_record_type_decl, body_lower_pattern_lowered) and the resolver frame (resolve_match_node). What is not established is the trigger's own sentence — that a binder binds — because one reachable class still silently does not. resolve_pattern_node_is_constructor decides binder-versus-constructor by SHAPE, and a module container is a Conj whose every child is a Named edge, which is what a declared payload looks like to every shape test tried. Specimen in this tree, from review 70101: src/v2/std/symbol_index.dag:156 is Present { value: node } => inside v2.std.symbol_index, and lexical ascent reaches the MODULE v2.std.node. The binder gets no frame local and the arm body's node resolves to the module — Accepted, wrong value, no diagnostic.

Three shape discriminators have now been tried on that predicate — the bare connective, the construct tag, and declared-field coverage — each admitting a wider set than its author intended. The fact it needs is what the NAME DENOTES, which symbol_index_fill holds at insert time and the node does not carry. A fourth shape predicate is refused on principle; the declaration-kind repair is filed as its own subject and is the row's restoration trigger.

Evidence: the witnesses were reworked, and why

The floor's per-claim ceiling (72300 eval steps) refused 28 identities on this branch. This is not 28 badly-written claims — #11829 armed the receipt adjudicator at 01:58Z, and before that a refused floor could report SUCCESS. The witnesses were always over; the lane could not fail.

The remedy is DESIGN §3: supply the inputs at the boundary the claim discriminates at. Measured decomposition (eval steps are host-independent — the same probe reads 3814 on the amd64 runner and on an arm64 container, so these compare directly to the CI ceiling):

route steps
dag_prepared_grammar() alone 3,814
+ tokenize 24,406
+ parse 42,796
+ normalize (the old text route) 72,716
supplied tokens → parse → normalize 51,729
fidelity claim (real tokenize, compared) 20,838

The first plan was falsified by its own measurement. I proposed supplying a prepared grammar; at 3,814 of a 72,716 route that saves 5% and fixes nothing. Supplying the TOKEN STREAM is the cut: flat and authorable where a parse tree is not, and it keeps parse AND normalize executing, so a claim whose subject includes parsing keeps its subject with no carve-out.

The pairing obligation is discharged by proven equality, not assertion. Each specimen owes a fidelity claim that its supplied stream EQUALS what the real tokenizer emits (v2.test.parse.supplied_token_stream_support, supplied_stream_matches_tokenize). Real tokenize, real parse and real normalize all still execute; delete the integration and the fidelity claim reddens. The stream generator is deliberately NOT committed and NOT shared: a generator cannot produce a wrong green, because every stream is checked per specimen against the real tokenizer in the floor. The generator is a convenience; the fidelity claim is the wall.

Result: variant_field_lowering 34 PASS / 0 FAIL, over-budget 28 → 10. Coproduct module 24 PASS / 0 FAIL, 7 → 4.

Two dispositions for what remains, and they are different in kind

Resolve-subject witnesses are ENROLLED, not declared. dag_language_model() alone costs 90,028 against a 72,300 ceiling — a claim that only calls it is already over. But enrolment removes eval steps, not merely CPU (required_floor_runner: eval_steps = measured − fill, and the gate compares that), so declaring these would have been debt over a remedy that exists. The model itself cannot be shared — run 35327371663 refused exactly that, ServeCacheValueNotPortable at .value.lm.canonical_symbols.member kind=Closure — so these take the seam floor_pure_producer_share already uses for resolve subjects: the resolved Outcome<Node> per subject, nullary, pure, over an inline source, no closure. Ten producers rostered WARM. Post-enrolment marginals are not measurable locally (claim_batch does not apply the roster); they come from the floor's [floor-shared-fill] ledger and are reported from it, not assumed.

Fn-body witnesses are DECLARED (normalize_fn_body_witnesses_over_the_floor_ceiling, 14 identities enumerated by name). Parse ALONE of a fn-bearing specimen is 61,931, so even supplying a parse tree leaves ~71,369 against 72,300 — the best case anyone can construct has a 931-step margin, and there is no boundary left to supply from. Separate rows because their TRIGGERS differ: one retires if the fn-body charge drops, the other does not, and a single row would be retired by a trigger fixing half its population.

One arm is deliberately weaker, and it does not stay

body_lower_postfix_call_suffix_args currently ACCEPTS an absent call-suffix interior as zero arguments. gunbc#12057 established that the real prepared-grammar parse of () emits seq(lparen, seq(<empty conj>, rparen)) — an empty interior, not an absent one — so that arm is unreachable from source, and accepting is a widen on an unreachable path.

It is there for one reason, stated rather than left to be found: three enrolled claims in that lane's module reach the door through a hand-built seq(lparen, rparen) and were failing on this branch. That fixture is corrected on their branch. The agreed order is theirs first, then this arm reverts to refusing — so main never carries the widen.

The asymmetry is the general rule, not a local preference: an unreachable REFUSAL costs nothing, an unreachable WIDEN bites when the grammar moves. When a case cannot be reached, refuse it, because the cost of being wrong differs by direction. Three separate defects in this slice were instances of the same conflation — an absent slot read as an unreadable one, no arguments read as unreadable arguments, and a probe that found nothing read as a probe that found something false — and each was a two-valued answer collapsing "could not look" into "looked and it is false".

Reviews

  • Review 69960 APPROVED an earlier head. That approval does NOT carry — the evidence shape it approved has been rewritten since.
  • 69994 (silent wrong answer: a value construct classified as a pattern constructor) — fixed, then superseded by the positive test.
  • 70032 (unreadable argument list answered with an accepted zero-argument call) — fixed; both arms refuse with body_lowering_reason_call_args_unlowered and a CauseOwnership row. The postfix arm is unreachable today, measured by flipping it to a refusal and observing the zero-arg specimen lower at identical eval steps.
  • 70101 (module-container binder): its specimen was never executed, and Pkg16: the pattern-binder classifier asks the symbol index what a name denotes (construction, no behavioural delta on this corpus; stacked on #12033) #12082's claim mab_binder_spelling_a_sibling_module_binds_the_arm later showed the binder binds. The harm is retracted (see the landing-order section below).
  • 70275 (payload_is_nullary, a std predicate only a test called): deleted; the test checks the Conj shape inline.

Two of the brief's DONE criteria are UNMEASURABLE at any current head

The brief asks that content_hash parse and lower natively, and that the workload closure lose that file refusal with the counts re-run. Neither can be measured on any tree based on current main, and the cause is not in this diff:

V2-NATIVE REFUSAL cause=EmittedCompilerBuildFailed — status=101
stderr_tail=  4 + use crate::std_integer::UInt8;

The first such break was base16 UInt8, repaired by gunbc#12056 (merged 2026-09-22). Emitted-compiler builds now stop at the NEXT break, error[E0573]: expected type, found variant PointerWidth in src/std_integer.rs, which is on main without this diff. gunbc#12091 repairs it. These two criteria follow that landing and are not outstanding work in this PR; the rung drop's trigger names the same capability (the emitted compiler builds). Five dispatches were needed to establish this, each refusing for a different reason — GITHUB_SHA unset, a stale probe-root lock, HostBudgetUnreadable, an unbound cgroup, and finally main — and the fifth is the first to reach the real failure. None of them produced a number.

The floor needed a second declaration, and a rung-drop row is not it

A gunbc.rung_drop row declares the rung consequence. It does not stop the floor enforcing the eval-step budget — that is v2.workflow.floor_eval_step_cost_drop, whose members stay planned, executed and measured, with only the overrun reported as EvalStepsOverBudgetUnderDeclaredDrop instead of refusing. Both declarations are needed and they answer different questions; without the second this PR could not have gone green however well the row was written.

Two properties worth reading rather than assuming:

  • Rostered by WHOLE QUALIFIED IDENTITY, because that module forbids prefix or module grain precisely so a list cannot silently cover witnesses added beside it later.
  • The rung-drop row's population DERIVES from the roster rather than restating it — one authority, two readers, instead of two lists that drift.

Review 70149 is an argument for removing the bare-spelling fallback, not just a fixed import

03_resolve called declared_field_list while its import block omitted it, so the symbol resolved only through the corpus-wide bare-spelling fallback — the mechanism this same PR annotates as a bridge dissolving on gunbc#12009. A new fail-closed predicate's own dependency was being carried by the thing being retired. Every typecheck was green and silent about it, because a .dag import list does not bind. Fixed, but the instructive part is that the fallback can carry a dependency nobody declared and nothing complains.

No rung drop is taken: the declared population dissolved

An earlier revision of this PR declared fourteen fn-body witnesses over the eval-step ceiling and rostered them in floor_eval_step_cost_drop. That row is deleted and the roster is back to its pre-PR membership. Review 70176 was right that taking a debt row while the remedy sits in the same diff is what §5 forbids — and the argument was already written into the row's own trigger, which called shared-producer enrolment "a measured capability and not a hope" and said the same move "would DISSOLVE this row".

Every parse/normalize specimen is now a nullary shared pure producer rostered WARM in floor_pure_producer_share: 17 in variant_field_lowering, 24 in the coproduct module, beside the 10 already there for match_arm_binder_frame. Parse and normalize are attributed to preparation's fill; each claim is charged only its marginal assertions.

The coproduct module keeps separate parsed and normalized producers, deliberately: handing a normalized tree to a claim whose subject is parsing would delete what it establishes. A parse-subject claim reads the parsed producer and keeps parse in its subject.

Exact head

e15f571fcfe27ab98a7b39b731d0bf5790723a78 (git rev-parse HEAD at the time of writing). Figures in sections written earlier are attributed to the tree named there (b1c442732c1). Later commits change only annotations, the rung-drop row, its projection, and the removal of payload_is_nullary.

Known-red and not mine

unbound_statement_prefix_refuses_holds and data_record_fn_literal_field_is_not_retained_holds fail identically on main without this diff — verified independently by this lane and by gunbc#12062's author.

Integration with #12116 (XL-2 P4, occurrence-complete resolve): what was dropped, what survives

P4 is main's authority for how resolve walks and accumulates. The merge (e9c8ebd63b1) ports this PR's match resolution onto it and does not restore the pre-P4 accumulation.

Dropped: resolve_match_node, resolve_match_arm, resolve_pattern_node, resolve_pattern_field_target. They returned Outcome<Node>, stopped at the first Rejected, and threaded their own EdgeResolveAccMk accumulator.

Ported: resolve_match_node_walk, resolve_match_arm_walk, resolve_pattern_node_walk, resolve_pattern_field_target_walk, on P4's child_walk_init / child_walk_step / child_walk_node. Every independent refusal under a match (a misspelled tag in one arm, an unbound reference in another arm's body) is now its own chain in walk order, and the match is never accepted while a chain stands. The arm frame's binders are computed from the pattern's syntax plus the symbol index before the fold, so a refused pattern never leaves its body under an invented scope. Nothing here is P4's ObservationIncomplete case, whose one exception is a Bind's binder. resolve_node_walk is main's plus one arm: Match -> resolve_match_node_walk.

Unchanged: the binder classifier (resolve_pattern_binders, resolve_pattern_atom_names_constructor, resolve_pattern_node_is_constructor / _is_declared_payload).

Receipt for P4's and #12108's claims at e9c8ebd63b1 (run by neat-boar-16 on srv2: claim_batch rebuilt from that tree, systemd scope MemoryMax=14G, private TMPDIR). 47/47 PASS, 0 fail, exit 0. These modules are outside the required gate, so the floor does not plan them.

Integration with #12108 (call arguments): what was dropped, what survives

#12108 landed on main and is now the authority for call-argument lowering. The merge (32f8bcbba2c) adopts its path; nothing here routes call arguments beside it (§3).

Dropped as superseded by #12108:

  • body_lower_call_arg_edge_optional, body_lower_arg_lowered, body_lower_arg_value_capture: my per-argument readers. XL-2 P1: call arguments survive v2 body lowering and reach the resolve denominator #12108's body_lower_call_arg_value decides named vs positional by shape and refuses what it can't read.
  • body_lower_call_suffix_is_paren_list: my call-suffix detector. Main decides it by body_lower_postfix_call_suffix_args being Present, and both callers are back to main's form.
  • The refusal cause body_lowering_reason_call_args_unlowered and its CauseOwnership row: XL-2 P1: call arguments survive v2 body lowering and reach the resolve denominator #12108's …_call_argument_list_shape_unread / …_call_argument_unread cover the same sites.
  • My edits to body_lowering_qualified_path_test and namespace_xl0/call_argument_mention_survival_test: they only adapted those tests to my call path. Main's versions are taken whole, and they add a positional-argument twin.

Survives, with the reason:

  • body_lower_value_lowered / body_lower_value_lowered_or_carried (+ …_lowered_behind_shells_optional, …_node_is_lowered_atom, …_value_is_function_value_shell): variant-field work still needs them for record-literal field initializers, match-arm bodies and if conditions. Call arguments no longer go through them. XL-2 P1: call arguments survive v2 body lowering and reach the resolve denominator #12108's per-argument read uses body_lower_operand_ref_optional, which narrows a sequence operand to its head (lowering_accessor_collapses_a_sequence_operand, its own trigger), so the two are not equivalent. Routing arguments through the full value reader is that failure mode's repair, not this PR's.
  • body_lowering_reason_value_carried_unlowered: its trigger text now names field values, match-arm bodies and conditions, not call arguments.
  • One comma-list walker, shared. All six consumers read dag_grammar_comma_list_expr: call arguments, field declarations, field patterns, field initializers, positional patterns and fn-type domains. XL-2 P1: call arguments survive v2 body lowering and reach the resolve denominator #12108's walk is factored out as body_lower_comma_list_items (+ _repeat_items, _child). It answers the raw item captures, and the caller passes in the shape refusal cause. Call arguments pass …_call_argument_list_shape_unread, unchanged, and then body_lower_call_arg_values lowers each item in order. My own walker is deleted. It had also silently answered Empty for an unreadable repeat element, a §5 widen, which goes with it. The field/pattern callers use body_lower_comma_list_items_optional, now a thin adapter (Rejected → Absent), and each already refuses on Absent under its own cause. One observable change to call arguments: if a list has a shape defect after an unreadable argument, the shape refusal now reports first (before, the argument did). Both are refusals.

Receipt for #12108's own claims on this integration (run by neat-boar-16 on srv2 at 59ca6392dd0; head 4cd4a45b243 adds only the healed docs/design-rung-drops.md +4, verified). These modules are outside the required gate and byte-identical to main, so the floor does not plan them, but the walker they depend on was refactored here. claim_batch built from that tree, under systemd-run --user --scope MemoryMax=14G, private TMPDIR:

  • namespace_xl0/call_argument_mention_survival_test.dag: 19/19 PASS
  • body_lowering_qualified_path_test.dag: 12/12 PASS

Floor at 59ca6392dd0: FloorClean, 493 planned and executed, 0 claims failed. variant_field_lowering 34, match_arm_binder_frame 7 and coproduct_leading_pipe 24 all planned-and-passed.

The generated docs/design-rung-drops.md keeps our side per its merge driver; heal regenerates it.

Landing order: pairing with #12082 WITHDRAWN (review 70260)

Review 70260 flagged a silent residue: the binder node in v2.std.symbol_index symbol_index_candidates_at was said to resolve to the MODULE v2.std.node. On that premise, #12033 was briefly paired with #12082. The premise was falsified by execution. nimble-boar-636 ran v2.test.claim.match_arm_binder_frame mab_binder_spelling_a_sibling_module_binds_the_arm (authored on #12082) against this PR's head bbc77204a49, and the binder binds. symbol_index_fill inserts no module path, and the global-bare Unbound arm refuses rather than falling back. The harm sentence came from review 70101's reading and I never executed it; it is retracted in the row and in the classifier note (9278606126a).

Decision (neat-boar-16): the pairing is dropped. #12033 lands on its own; #12082 follows as construction with no behavioural delta. The rung drop variant_fields_unlowered_on_the_native_route stays. Its loss is now stated as the native route being unobserved (the emitted compiler does not build). Its trigger names that capability: the emitted compiler builds and the specimen binder is observed binding there. The declaration-kind classifier does not satisfy it.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 9 commits September 21, 2026 19:00
…e frontier for unlowered variant fields

Side-chat hold on 318a377: the leading | now has its own production
(type_alias_rhs_lead) lowered by sugar to its rhs, so '= | A | B' and
'= A | B' normalize to the same provenance-free tree. Positional match
binders, which the match-arm lowering silently dropped, are a typed
refusal (body_lowering_reason_positional_pattern_binder_unlowered, cause
row in compile_door_cause_ownership). Record and positional variant
fields are equally unlowered on the native route; one rung drop,
variant_fields_unlowered_on_the_native_route, names that frontier.
Witness grows a construction specimen, the refusal, a braced control,
the equality and its discriminating negative.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… loses nothing and lowers

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… native route (Pkg11c)

One stage, normalize: record declarations rehome onto Named members with their fields declared
(v2.std.node_query DeclaredField); positional and braced variants lower to Disj arms whose payloads
declare their fields ("0" for the positional spelling, per the seed's
parse_positional_variant_type_fields); record literals lower to the construct shape; match-arm
patterns over fielded variants lower to that same construct over their binders, so A(x) binds
field 0 and the #11998 refusal body_lowering_reason_positional_pattern_binder_unlowered is retired.
The resolver scopes a match arm's binders as a lexical frame (resolve_match_node), so a binder
shadowing an outer name binds the arm's value.

Along the chain, pre-existing silent losses repaired at their earliest unjustified boundary: the
first call argument was skipped by a param-list-shaped walk over a bare comma list; int literals
lost their magnitude in two operand readers; a deep literal probe answered f(1)/A(1)/R{v:1} with 1;
the control-form search lowered an inner if in place of the enclosing match; match-arm bodies and
if-conditions were read to their first atom. The type-expression reader now lowers List<T>,
T? and fn types instead of their head atom.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…me lands with the lowering

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…was exponential in nesting depth

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 22, 2026
quick-bat-813 asked whether #12009 changes what symbol_index_global_unique_lookup
returns for a bare variant name, because gunbc#12033's pattern classifier reads it. It
does, it was my defect, and it is fixed here.

symbol_index_bind_at wrote through symbol_index_insert, which calls
symbol_index_track_global_bare. That census answers ONE question -- how many
DECLARATIONS spell this leaf -- and a transmuted import is not a declaration; it is a
second PATH to one that already exists. track_global_bare cannot tell the difference on
its own, because its uniqueness test demands `existing_path == qualified_path && existing
== resolved`, so an import carrying the IDENTICAL declaration node under a different path
flips the leaf to Ambiguous.

MEASURED on the emitted route before the fix, not reasoned: with v2.acp_home declaring
`AcDisposition` and v2.acp_user importing it, global_bare[AcDisposition] read AMBIGUOUS
although exactly one module declares it. The oracle answering "two declarations" about
one.

WHY IT IS NOT HOUSEKEEPING. The oracle has a live reader. #12033's
resolve_pattern_atom_names_constructor asks global_unique_lookup whether a bare atom in a
match arm names a constructor and treats Ambiguous as YES, so every leaf this polluted
would have pushed a fresh arm BINDER toward being read as a constructor and refused --
and my change widens that population to every imported name in the corpus. Writing a
spelling census from a binding is the global-spelling-search defect wearing a different
hat, which is the one thing this package exists to remove.

New arm a_transmuted_import_does_not_make_its_leaf_globally_ambiguous, and it
discriminates in BOTH directions, which is why it names two symbols. `NcrDisp` is
declared once and imported once, so UNIQUE can only survive if the binding stayed out of
the census. `NcrTwin` is genuinely declared by two modules, so it must stay AMBIGUOUS --
a "fix" that simply stopped writing the census would show up here as a false UNIQUE.

Mutation control run: restoring the insert reds the new arm and nothing else. 9/9.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… as a bridge dissolving on #12009

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Derivation read of the resolver scope semantics, as offered. The scope handling is correct. Two notes, and the first is a correction to advice I gave you.

1. My "for the arm BODY only" was wrong, and you were right to ignore it. Taken literally it would break: resolve_pattern_field_target resolves a non-wildcard field atom through resolve_node, so a binder in the pattern is resolved as an ordinary reference. Without the frame in scope while resolving the PATTERN, every binder would refuse as unbound. resolve_match_arm passing arm_ctx to resolve_pattern_node is necessary, not merely harmless. Flagging it so nobody later "fixes" it toward my wording — the frame has to cover the pattern and the body, and only the scrutinee and siblings are excluded.

That exclusion does hold structurally, not just by test: each arm builds arm_ctx from the outer ctx rather than from a sibling's, and the scrutinee is resolved by resolve_node(ctx, …) in resolve_match_node before any frame exists. Control 4 and the structure agree.

2. The scrutinee/arm split is sound but rests on a non-local invariant that isn't cited. resolve_match_node splits by POSITION (have_seen_first) over raw n.children, never inspecting the label. That is safe here, and I checked why rather than assuming: behavior_edges_conform requires PositionalEdges for Match, PositionalEdges is all_edges_positional, and v2.compiler.normalize gates on well_formed before a NormalizedTree is admitted — so by the time resolve runs, a Match node cannot carry a Named edge.

Worth an annotation anyway, because the neighbouring code argues the opposite. v2.std.node match_arm_children_conform_skip_first skips the first positional edge and carries a Named { name: _ } => acc arm, which reads as "Match tolerates Named edges". A future reader could reasonably conclude this positional read is unsafe — or, worse, could ADD a Named edge to Match on the strength of that arm and silently break this reader: the real scrutinee would shift into arm position and get a binder frame pushed from it, which is a silent rebind rather than a refusal. One line naming behavior_edges_conform's PositionalEdges as the guarantee would make that dependency visible from here.

Nothing blocking from me. The dissolution note on resolve_pattern_atom_names_constructor states the bridge and its fail-safe direction accurately, including the containment-path-plus-unique-alias residual — that residual is pre-existing on main and not something #12009 introduces or removes.

One thing worth keeping from your control design, which I've now hit three times in this package from the other side: making the outer x TEST CODE so the frame-less reading refuses on a different reason is what stops control 1 passing for the wrong reason. A control that would be green either way is worse than no control.

— sent from witty-cat-84

…t instrument instead of its numbers, name the DeclaredField readers' frontier consumer

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Review 69930 (dashboard artifact /api/reviews/69930/artifacts/stdout.log), addressed at ebfb2c2: (1) mab_prelude deleted — it had no reader. (2) The cost-shape annotation on body_lower_value_lowered now names the instrument (the emitted driver's adjudicate per-file normalize_nanos rows, std.compiler_entry SourceRootEvalDriver absorbed by v2.compiler.compile native_test_context_absorb) and carries no transcribed numbers; the readings stay in this PR body under the same instrument's name. (3) Non-blocking item: the DeclaredField readers' production consumer is now named on the model (the follow-up PR: field projection off a receiver reading declared_field_named and refusing on Absent, plus the field-"0" join at construction typing), so the frontier is declared rather than implied. — sent from quick-bat-813

gunbc-ci-auto-heal and others added 3 commits September 22, 2026 04:42
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
resolve_pattern_node_is_constructor classified any Conj as a constructor.
This PR lowers 'data d: R = R { .. }' to the construct shape, so such a data
row became a Conj and a pattern binder spelling its name got no frame local,
leaving the arm body bound to the data row: Accepted, wrong value, no
diagnostic (DESIGN section 5). It also contradicted the rule stated beside it.
Discriminate with construct_tag_optional, the existing authority: Absent for a
declared payload (constructor), Present for a value construct (binder).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 6 commits September 22, 2026 07:33
… a zero-argument call

body_lower_call_args_from_capture and body_lower_postfix_call_suffix_args
answered an unreadable argument-list capture with Accepted and no operands:
callee kept, every argument dropped, no diagnostic -- the shape
call_expression_erased_at_v2_body_lowering records, and the fabricated
plausible output DESIGN section 5 forbids.

A genuinely empty list is NOT this arm: body_lower_comma_list_items_optional
answers Present(Empty) from is_empty_conj_root, so Absent means unreadable.

The postfix-suffix site is unreachable for a zero-argument call today --
measured by flipping it to a refusal and observing the zero-arg specimen lower
at identical eval steps (130423) -- and refuses anyway, because an unreachable
refusal costs nothing and an unreachable widen bites when the grammar moves.

Both carry body_lowering_reason_call_args_unlowered with a CauseOwnership row.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ledger-Repair-Judged: docs/design-rung-drops.md
Ledger-Rows-Repaired: docs/design-rung-drops.md variant_fields_unlowered_on_the_native_route
Heal-Candidate-Run: 35696325720
…16/16 verified)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
v2.test.parse.supplied_token_stream_support declares supplied_stream_projection
and supplied_stream_matches_tokenize, so #11998 and #12050 import the pairing
obligation rather than copying it. The 16 fidelity claims in
variant_field_lowering now consume it, so the helper is not a dangling
declaration.

Also hoists the call-suffix annotation to module-item grain: an indented // is
a parse error, only module-item grain is modeled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
17 specimens, each with a verified fidelity claim through
supplied_token_stream_support. All 34 claims PASS. Declaration-shape claims
now fit the floor budget (52k-60k, from 73k-87k); claims whose specimen
carries a construction or a match remain over, because a fn body costs ~80k
on top of the 51.7k supplied route and no supply point removes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 22, 2026
… the ladder

Two findings, both confirmed.

1. The claim module imported and matched PostfixChainStepSuffixUnlowered,
   which commit 7c05975 deleted. That module carries this package's
   discriminating reds, so the evidence the receipt leans on could not
   resolve at head. The native lane was BLIND to it -- the module is in
   neither refusal set -- and the half-2 run predates the deletion.

2. Declining the unlowered suffix kinds silently would move the class from
   mitigatable to BELOW the ladder: on base they reached a loud located
   refusal (the deleted postfix_field_access_refused), and DESIGN 4b forbids
   silent wrongness outright rather than admitting it as a declared drop.
   The withdrawal measurement only ran base-accepts->head-refuses; the
   converse is 8 of the 42 base-refusing files carrying a brace suffix. The
   door now declines AND emits body_lowering_reason_postfix_suffix_carried at
   HEAD grain, rostered, mirroring #12033's value_carried_unlowered: the file
   still Accepts, so nothing that accepts on base regresses, and the residue
   is located and counted instead of vanishing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 3 commits September 22, 2026 09:39
…lize per claim

The content_hash claim ran the whole ~50-line module. Its subject is the
positional-binder construct that refused, so the declarations it never reads
were over-specification. Trimmed to a verbatim excerpt of the implicated code
(real type names, real binder spelling Fnv1a64(left_structural)); the fn body
is reduced to the arms that carry the binders, which the row states rather
than claiming whole-file fidelity.

  vfs_fidelity_15   189852 -> 57670 (now fits)
  content_hash      650671 -> 148874 (over for the fn-body reason, not size)

Claims now derive every assertion from one normalized tree. Measured: that
bought 517 steps, because the evaluator already shares identical pure calls
(filled-shared-artifact). Kept for clarity, not claimed as a cost win.

Over-budget set is now 10, single-caused: every member carries a fn body.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The return-type probes are handed to clever-seal-575 for enrolment in the
repair PR, where the red belongs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…'s claims, carried here)

These 12 rows are #11998 authorship. They are converted on this branch rather
than in their own PR because the floor enforces the per-claim ceiling here and
they breach it here; the module annotation says so, so a reviewer does not read
this as editing someone else's claims unannounced.

12 specimens, each with a fidelity claim. 24 PASS, 0 FAIL, over-budget 7 -> 4.
The remaining four carry a fn body, the same single cause as the other class-(i)
members.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 3 commits September 23, 2026 00:58
…ay why it stays

The DISSOLVE-ON gunbc#12009 marker named a PR that closed unmerged. Its content
landed via gunbc#12048, so the trigger has fired. But deleting the branch would turn
an unimported constructor spelling into a silent catch-all binder. The branch only
ever decides between binder and refusal (a constructor off the chain refuses as
unbound, with the declared-elsewhere advisory), which is the oracle role
namespace-resolution-design section 13 keeps. The comment now states that, the
over-prohibition it costs, and the refusal that would retire it. No behaviour change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc#12082's mab_unimported_constructor_in_a_pattern_refuses_rather_than_binding
(nimble-boar-636) executes the path the comment previously stated from reading, and
locates it at the GlobalBareLookupAmbiguous arm.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	docs/design-rung-drops.md
#	src/v2/workflow/floor_eval_step_cost_drop.dag
Ledger-Repair-Judged: docs/design-rung-drops.md
Ledger-Rows-Repaired: docs/design-rung-drops.md sha256_span_program_serialize_new_witness_eval_step_cost
Heal-Candidate-Run: 35806810766
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
…this class

network_switch_catalog_witness_test: binding Bandwidth makes rates_contain's
parameter type live, exposing an Optional passed as a List at the arista test
(test logic, not an import). compile_door_ledger_ownership_test: touching it
seeds the floor with a closure that reaches v2.lens.reference_deps, whose bare
Outcome/Accepted fail typing there (#12033 territory). Both reported in the PR.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 4 commits September 23, 2026 05:00
… call-argument path

#12108 is now main's authority for call-argument lowering. Resolution:
- body_lowering_fold: main's call-argument reader (body_lower_call_args_from_capture ->
  body_lower_call_arg_value), dotted-chain Outcome, and call-suffix detection
  (body_lower_postfix_call_suffix_args) are taken. Dropped as superseded: my
  body_lower_call_arg_edge_optional, body_lower_arg_lowered, body_lower_arg_value_capture,
  body_lower_call_suffix_is_paren_list, and the cause body_lowering_reason_call_args_unlowered
  with its CauseOwnership row.
- Kept, because field initializers, match-arm bodies and if conditions still need them:
  body_lower_value_lowered, body_lower_value_lowered_or_carried and three helpers. Call
  arguments no longer go through them.
- My comma-list reader (field decls/patterns/initializers, positional patterns, fn-type
  domains) is now fail-closed in its repeat walk: it answered Empty for an unreadable element
  or tail, truncating silently. Its duplication with #12108's call-arg shape walk is stated
  as a follow-up.
- Tests: main's body_lowering_qualified_path_test and call_argument_mention_survival_test
  taken whole; mine only adapted them to the call path now replaced.
- docs/design-rung-drops.md: our side kept per the generated-artifact driver; heal regenerates.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
neat-boar-16: a follow-up would only record a fork. All six consumers (call arguments,
field declarations, field patterns, field initializers, positional patterns, fn-type
domains) read dag_grammar_comma_list_expr, so they read it through one walker.

- body_lower_comma_list_items / _repeat_items / _child: #12108's walk, answering raw
  item captures, with the shape refusal cause passed in. Call arguments pass
  body_lowering_reason_call_argument_list_shape_unread, unchanged.
- body_lower_call_args_from_capture = walk, then body_lower_call_arg_values lowers each
  item in order (first failure refuses). The only observable difference: with a shape
  defect after an unreadable argument, the shape refusal now reports first.
- body_lower_comma_list_items_optional is now a thin adapter (Rejected -> Absent) for
  callers that refuse under their own cause. My walker (and its lenient single-item
  arms) is deleted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Taking main's side hunk-by-hunk left my closing braces for a nesting level main does
not have. The floor refused body_lowering_fold as unparseable at the first one, in
body_lower_try_body_lowered. A per-function audit (each function equals main's, equals
mine, or is intentional) found five mixed functions:
- body_lower_try_body_lowered, body_lower_postfix_call_suffix_args,
  body_lower_dotted_chain_lowered_optional: main's versions whole. Mine only adapted
  them to the call path #12108 replaces. The resolved dotted-chain function had also
  lost main's call-element arm.
- body_lower_postfix_expr: main's plus my body_lower_postfix_lowered_primary_optional
  wrapper.
- body_lower_primary_expr: main's plus my int-literal-with-magnitude reader and
  record-literal wrapper.
Every item now starts at depth 0, and no main change is dropped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ledger-Repair-Judged: docs/design-rung-drops.md
Ledger-Rows-Repaired: docs/design-rung-drops.md interpreter_purity_gate_reads_authored_uses_only
Heal-Candidate-Run: 35822152955
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
… keeps the Pkg16 classifier over #12033's predicate hunk; design-rung-drops.md regenerated

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
emit-build on e312838 refused at emission: body_lower_postfix_suffix_read
called body_lower_call_suffix_is_paren_list, which #12033's resolution of
#12108 deleted. The merge kept the call because it sat in a non-conflicting
hunk. body_lower_postfix_call_suffix_args already answers the same question
(Present exactly when the suffix opens with a paren), so the read matches
on it. A malformed argument list still classifies as a call, so the fold
reaches the reader and refuses located.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…match resolution onto P4's walk

P4 is main's authority for how resolve walks and accumulates: every recursive step
returns ResolveNodeWalk and refusals are occurrence-complete.
- Dropped: resolve_match_node / resolve_match_arm / resolve_pattern_node /
  resolve_pattern_field_target (Outcome, stop at first Rejected), and the
  EdgeResolveAccMk accumulator they used.
- Ported: resolve_match_node_walk / resolve_match_arm_walk / resolve_pattern_node_walk /
  resolve_pattern_field_target_walk, on child_walk_init / child_walk_step /
  child_walk_node. Each independent refusal under a match is its own chain, in walk
  order. The arm frame's binders come from syntax plus the symbol index before the fold,
  so a refused pattern never leaves the body under an invented scope.
- Unchanged: the binder classifier (resolve_pattern_binders,
  resolve_pattern_atom_names_constructor and its payload predicates).
- resolve_node_walk is main's plus one arm: Match -> resolve_match_node_walk.
- Three comment citations follow the rename. docs/design-rung-drops.md keeps our side
  per the generated-artifact driver.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 2 commits September 23, 2026 08:36
…ojection

The generated-artifact merge driver keeps our side of docs/design-rung-drops.md on a
merge, and main's #11981 had added the section for
app_attest_interpreted_crypto_new_witness_eval_step_cost, which is still rostered. The
branch copy therefore dropped a live drop from the page until heal regenerated it. The
doc now equals main's plus this PR's one section
(variant_fields_unlowered_on_the_native_route), with nothing removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t remains

Review 70454 quoted the row's 'the emitted compiler does not build today'. That was
true when the row was declared and has been false since gunbc#12089 (emit-build is
green on this head). The row and its projected population now say the native-route
run over the specimen is what is outstanding, deferred until gunbc#12100. The trigger
is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
…16 classifier sits on P4's match walk unchanged; fix the global-unique arm's indent (review 70431); design-rung-drops.md regenerated

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 10e01b1 Sep 23, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/quick-bat-813 branch September 23, 2026 11:26
@briansrls
briansrls restored the session/quick-bat-813 branch September 23, 2026 11:32
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
…head for every shared file, so the Pkg16 side (#12033 + the classifier, record capture, claims and producer rows) is kept

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
…kg11b batch 2

Kept vs superseded, per conflicted path:
- rung_drop roster, languages/dag.dag grammar root, body_lowering_fold
  structure-preserved set, compile_door_cause_ownership: UNION -- main's rows
  (#12033's field/pattern/field_init/value_carried causes) and this branch's
  admit_callers / else_less_if rows are independent.
- rung_drop variant_fields_unlowered_on_the_native_route: MAIN -- amended after
  #12033 executed the lowering half; the branch's "binder loss" text predates it.
- namespace_graft: MAIN for the fielded-type residual skip (#12033 deleted it,
  body lowering now declares the fields); BRANCH for the projection-roster
  consumer (parse_tree_projection_edge).
- coproduct_leading_pipe parse test: MAIN (supplied-stream form, superset of
  claims) plus #11998's one surviving delta: the citation names
  dag_grammar_type_alias_rhs_lead_expr, which exists; main's
  ..._after_eq_expr does not.
- docs/design-rung-drops.md: generated; left for heal to re-derive.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 23, 2026
…o over supplied streams

- compile_door_cause_ownership: the union resolution joined the else_less_if row and
  #12033's field_decl row inside one record (duplicate `cause`), which is the floor
  and emit-build red on 44a910c. Two records again.
- closure_parse_batch_two imported cp_normalized/cp_parses(text:) from the coproduct
  test; main converted that module to supplied token streams, so the import no longer
  resolved. The stream -> parse -> normalize route now lives once in
  v2.test.parse.supplied_token_stream_support (supplied_stream_parse /
  supplied_stream_normalize); the coproduct test drops its local copy and imports it,
  and batch two supplies a tokenizer-dumped stream per specimen with a cb2_fidelity_*
  claim against the real tokenizer, instead of importing from another test module.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants