Skip to content

v2: one binder reader -- every binder type read goes through node_query declared_field_from_edge (XL-2 PR2b-1) - #12899

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
session/eager-heron-413-pr2b1
Oct 1, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
session/eager-heron-413-pr2b1

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

XL-2 PR2b-1. A refactor only: no representation change and no behaviour change.

Why

The 2026-10-01 side-chat ruling puts a default on the BINDER, not on its type. It requires ONE binder representation (a required type, an optional default, one reader and one builder), shared by fn parameters, service io fields and record fields. Changing today's name -> type binder shape is a replacement migration (DESIGN §3), which may never leave two shapes coexisting.

A census found the builders already centralized (body_lower_typed_param_edge_of). The readers were scattered: about 15 production functions read a binder edge's .target directly as its type. If the shape changed now, every one of them would misread a binder node. So the migration is staged in three PRs, and the shape is single at every point:

  • 2b-1 (this PR): one reader over today's shape.
  • 2b-2: one builder.
  • 2b-3: the atomic switch, done inside that reader/builder pair.

Change

  • The reader. It is the existing v2.std.node_query declared_field_from_edge, which returns DeclaredField { name, type_node, cardinality }. Reusing it avoids minting a second name. Beside it is member_edge_type_node, for sites that also see positional members: a binder's type through the reader, and a positional member's target, which is its type.
  • Sites now reading through it:
    • v2.compiler.infer: infer_conj_edge_named_type_for_binding and infer_formals_from_domain (the latter also covers record formals).
    • v2.compiler.resolve: resolve_record_field_type_optional.
    • v2.std.compilers.semantic_decl_emission: target_semantic_decl_field_surface_from_edge.
    • v2.std.compilers.target_model: produced_decl_param_segment_tokens and produced_decl_function_type_param_tokens.
    • v2.compiler.translate: the record-field slot arm of translate_algebra.
    • v2.std.node_query: conj_payload_type_name_go.
    • v2.std.concept_index: field_refs_from_conj_node.
    • The lenses: lifecycle_carrier, unit_modeling, reference_derived_residency_reading (three sites) and cost.copied_port_derivation.
  • Not changed here:
    • Generic walkers that descend into every child without typing it: resolve's arrow and bind walks, translate's subtree walk, symbol_index_fill containment. They only matter when the shape changes, so they move in 2b-3.
    • Coproduct ARM edges, which are not binders.
    • Type-parameter binders, which have their own representation and no type or default.

Evidence

  • On the seed interpreter, three lens tests over migrated sites return true: flat_scalar_unit_leaf_flagged_holds, modeled_unit_field_passes_holds, raw_dissolve_on_string_field_is_rejected.
  • dpo_infer_formals_follow_declared_order (infer formals) was OOM-killed on a default-size remote runner before it reported, so this PR's CI floor is its evidence.
  • Every migrated site is the identity over today's shape (type_node IS e.target), so the floor's existing witnesses are the regression check.

🤖 Generated with Claude Code

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE-MERGE at exact head 7a97b3ffa5a810bd0095951e66bcaf1957e5826f.

No findings.

This is a representation- and behavior-neutral PR2b-1 cut:

  • The existing v2.std.node_query.declared_field_from_edge is the one binder reader. On today's shape, every named binder still yields DeclaredField { name: edge.label, type_node: edge.target, cardinality: ... }, so each migrated read is extensionally identical.
  • member_edge_type_node is only the mixed-member projection: named members delegate to that reader; positional members retain e.target. It introduces no second binder model.
  • Infer, resolve, translation, declaration emission, target rendering, concept indexing, and the named lenses now consume the shared projection instead of independently assuming edge.target is the type.
  • No binder builder, node shape, conformance rule, generic subtree walk, coproduct-arm representation, or type-parameter representation changes in this PR. The single representation therefore remains unchanged until the planned atomic reader/builder switch.
  • The final commit is the authored refactor merged with current main; the resolved 04_infer.dag conflict retains both main's changes and the shared-reader conversion.

Exact-head floor, generated, emit-build, and witnesses pass. GitHub reports the PR clean and mergeable.

Merge-queue landing only: the actual merge_group candidate must pass against then-current main; no direct merge or check bypass.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit c084d6d Oct 1, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/eager-heron-413-pr2b1 branch October 1, 2026 10:31
gunbai-bot Bot pushed a commit that referenced this pull request Oct 1, 2026
…om_edge) at every conflicted site; lens member arms read Authored

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.

1 participant