Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
c0d77bc
Rehome type and data declarations onto Named graft edges.
Sep 18, 2026
c7eb597
Use match for type/data unit dispatch so the optional Edge unifies.
Sep 18, 2026
f8b6587
Do not treat a type/data shell without a captured child as a declarat…
Sep 18, 2026
c773382
Pair record field names with their types from user atoms under the fi…
Sep 18, 2026
fcec4c2
Probe why record construction still refuses after type grafting.
Sep 18, 2026
7139336
Keep only user-named flatten members so record field blocks are not m…
Sep 18, 2026
8bfb5c8
Restore the record-construct assemble hold after the flatten filter.
Sep 18, 2026
80feda1
Take the type name as the first user atom in the declaration, not seq…
Sep 18, 2026
b83df09
Rehome unwrapped record types from ident + field-block sequences.
Sep 18, 2026
267bc60
Drop the duplicate Box record source and unused assemble-reason helper.
Sep 18, 2026
295036c
Bind a pending type name to the next field-decl block in graft order.
Sep 18, 2026
b65254d
Name record types from the type keyword then ident, and keep flatten …
Sep 18, 2026
50e87ba
Keep flatten members whose targets are types or functions, not bare f…
Sep 18, 2026
672f325
Discriminate the record-graft refusal by reason prefix.
Sep 18, 2026
f59380e
Use the builtin starts_with for record-reason prefixes.
Sep 18, 2026
0cb1f05
Pin the record assemble refusal to remaining resolve reasons.
Sep 18, 2026
a176c6a
Narrow the resolve-* refusal family for record graft.
Sep 18, 2026
269ddb0
Do not treat the module qualified name as a pending type during graft.
Sep 18, 2026
3f4e166
Probe empty record braces separately from fielded records.
Sep 18, 2026
e9ee8c5
Record field bags are Cardinality so a type-only record is not a graf…
Sep 18, 2026
8a1eaa8
Drop diagnostic assemble-reason probes; keep the owed record controls.
Sep 18, 2026
3fbcf5e
Keep record field types as type-expr nodes instead of bare atoms.
Sep 18, 2026
3972dce
Enrol empty-record assemble controls; fielded Int records remain a re…
Sep 18, 2026
7d5848c
Wrap record Conj fields in Cardinality so a type-only record is not a…
Sep 18, 2026
d88814d
Restore fielded record assemble rows now that the spine wrap holds.
Sep 18, 2026
b0bd50f
Stop compensating record rehome in graft; keep record assemble rows a…
Sep 18, 2026
0697996
Drop lexeme-prefix machinery filtering and observe flatten-drop claim…
Sep 18, 2026
614c429
Restore LCR and XL-0 record absence measurements.
Sep 18, 2026
39a95d4
Keep residual record type_decl units when a sibling graft succeeds.
Sep 18, 2026
4d73e34
Note that skipped record type_decl units are reconstructed as residuals.
Sep 18, 2026
cc7c00f
Consume dag production presence and module-metadata walkers; drop unu…
Sep 18, 2026
ace921b
Execute record-graft measurements on per-PR discovery; require Rec to…
Sep 18, 2026
58d0cb4
Build the dag grammar once per graft and locate productions with one …
Sep 18, 2026
45c10aa
Read type/data names from the dag sequence spine; stop treating Rejec…
Sep 18, 2026
33e111d
Point alias binding at the shared kw-then-ident spine.
Sep 18, 2026
f869a5a
Skip Named rehome only for the record type_decl arm, not variant fiel…
Sep 18, 2026
75f569a
Unify parse_subtree_locate_production branches as Optional rather tha…
Sep 18, 2026
c196aad
Treat field_decl_block under a coproduct Disj as Named, not a record …
Sep 18, 2026
850f9bf
Detect coproduct field blocks by a Disj anywhere under the type_decl …
Sep 18, 2026
c6dceb0
Distinguish record types from fielded coproducts by `=` and Disj, not…
Sep 18, 2026
b8957a6
Restore the field_decl_block Named skip; alias-rhs narrowing Named-re…
Sep 18, 2026
82c1fb8
Dissolve the bool production predicate and the declaration-target wal…
Sep 18, 2026
6ec06e9
Restore find-captured descent when the first matching production has …
Sep 18, 2026
f6ea532
Keep where-alias Conj members on flatten; still drop record field_dec…
Sep 18, 2026
8a027b4
Keep Named atom flatten members and drop flatten names already rehome…
Sep 18, 2026
75ff1be
Track the record graft skip as a failure-mode row; one production DFS…
Sep 18, 2026
2e1877f
State the field_decl_block graft skip as the whole skipped population.
Sep 18, 2026
dd65f7d
Drop unused Arrow import from namespace_graft.
Sep 18, 2026
60d703b
Partition graft units into Named edges and residuals in one fold.
Sep 18, 2026
485e328
Assert XL-0 record names survive residual reconstruct, not tree drop.
Sep 18, 2026
1990e13
Do not flatten through type/data units; treat residual field names as…
Sep 18, 2026
4498593
Account for every top-level unit in the graft partition; locate type …
Sep 18, 2026
0516a6d
WIP: Declaration grafting: type/data decls never become Named edges —…
Sep 19, 2026
877a89e
Merge origin/main into session/neat-moth-237 (import-list conflict in…
Sep 19, 2026
204a801
graft partition: import_decl units dissolve (Admission.imports owns t…
Sep 19, 2026
e2c262f
Graft body carries a producer marker: a one-member body is no longer …
Sep 19, 2026
1bca32b
Merge branch 'prereq-body-marker' into pr-11574-rebase
Sep 19, 2026
37f5f89
reference_site_collector: annotation at module-item grain (parse phas…
Sep 19, 2026
94a0142
Merge branch 'prereq-body-marker' into pr-11574-rebase
Sep 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module gunbc.recurring_failure_mode.one_encoding_carries_a_module_body_and_a_spine_segment

import std.types { NonEmptyStr }
import gunbc.recurring_failure_mode { RecurringFailureMode }

data one_encoding_carries_a_module_body_and_a_spine_segment: RecurringFailureMode = RecurringFailureMode {
identity: "one_encoding_carries_a_module_body_and_a_spine_segment" as NonEmptyStr,

receipts: [
"one encoding carries two meanings: the containment spine is a chain of single-Named-edge Conj wrappers, and a module body whose only member is a Named edge to a Conj has exactly that shape. `p { Flag: Conj }` and the path `p.Flag` were one tree. INVALID STATE: a grafted module whose qualified name, read back from its own nesting, is longer than the name it was authored with -- the first declaration has become a segment.",

"HARM, measured 2026-09-19 on gunbc#11574: every module whose graft body is one Conj-targeted member refuses resolve_module_not_found (the seek is for `p`, the tree answers `p.Flag`); CI's declarations phase reports unresolved-module-identities over the small fixture modules with that shape; symbol_index_fill descends the member as a segment and never indexes it. The specimen was a type-only coproduct module once its Named edge targeted the type_alias_rhs shell; `type Name = String where ...` alone had been red the same way on main before it. The reference-site collector had already met this and worked around it by COUNTING segments from the header qualified name (module_spine_unwrapped) -- circular for a grafted root, whose qualified name is itself read from the shape.",

"WHY THE READER CANNOT FIX IT: every consumer of the spine -- qualified_name_from_graft_spine, symbol_index_fill_containment_node, admit_named_exports_descend_spine, module_spine_unwrapped -- asks namespace_graft_spine_segment_edge_optional, and that predicate can only guess at the shape. DESIGN section 6b: the symptom sits at the reader; the earliest boundary that cannot justify itself is the producer that emitted a body indistinguishable from a segment. DESIGN section 5: make the state unwritable rather than teach a reader to guess.",

"THE REPAIR is producer-side and consumes the provenance vocabulary the graft already used for its module shell: namespace_graft_build_body_conj stamps the body with grammar_production_identity_node_projection -> Atom(namespace_graft_module_body_identity), and the one spine predicate stops at a node so marked. No captured projection is emitted, because the members ARE the body and a captured wrapper would re-create the very one-Named-Conj level the fill misreads. Readers that fold body children already treat projection edges as machinery (symbol_index_fill); export admission and the reference-site collector now apply the same rule to that edge.",

"EVIDENCE ENROLLED: v2.test.claim.namespace_graft.graft_shape_test namespace_graft_one_conj_member_body_is_not_a_segment_RED (a one-Conj-member body under a four-segment name reads four segments; FAILS with the producer marker removed) paired with namespace_graft_two_segment_path_still_reads_two_segments_holds (the same body under a two-segment name reads exactly two -- a marker that ended every spine after one segment would green the RED and red this) and namespace_graft_body_carries_producer_marker_holds.",

"NODE IDENTITY: the marker adds a child to every grafted body Conj, so the content hash of every grafted body, its spine wrappers and its module shell changes corpus-wide. It adds no source occurrence (OccurrenceSynthetic) and moves no declaration's occurrence identity or semantic hash of any member subtree. Nothing on main keys a committed artifact on a grafted root's content hash; a consumer that does must re-take its digests at this landing.",

"RUNG FOUND AT: silent wrongness (a fabricated qualified name accepted as the module's identity). RUNG NOW: 4, structurally impossible for the graft's own output -- the body cannot be emitted without its marker, and no reader guesses. RESIDUAL, honestly outside the marker: a hand-built spine (a fixture constructing containment nodes directly rather than through module_header_containment_graft) can still author the ambiguous shape; that residue is a fixture-authoring fact, and the discriminating RED above is the control that would catch a producer regressing to it.",
],

evidence: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module gunbc.recurring_failure_mode.type_decl_field_decl_block_not_named_at_graft

import std.types { NonEmptyStr }
import gunbc.recurring_failure_mode { RecurringFailureMode }

data type_decl_field_decl_block_not_named_at_graft: RecurringFailureMode = RecurringFailureMode {
identity: "type_decl_field_decl_block_not_named_at_graft" as NonEmptyStr,

receipts: [
"**a type_decl whose parse tree still carries dag_surface_field_decl_block is not rehomed onto a Named graft edge** (INVALID STATE: namespace_graft_type_decl_named_edge returns Absent whenever parse_subtree_locate_production finds that production under the unit. The skip is that production, not the record spelling. dag_grammar_type_variant_expr puts an optional field_decl_block on every variant, and graft runs after sugar, so the same arm covers `type Rec { n: Int }`, `type Foo = Bar {}`, and `type Box = Leaf | Cell { n: Int }`. Nullary coproducts without a field block (`type Flag = On | Off`) and type_decl units that locate no field_decl_block are Named. Narrowing the skip by type_alias_rhs / `=` is not available: those discriminators rehome records.)",

"HARM: a fielded type_decl name is not a first-class module member. Residual reconstruct keeps the unit beside a sibling Named graft so the shell is not silently deleted; that is mitigation of drop, not Named rehome. Record assemble refuses today. Fielded-variant assemble is in the skipped population and is not enrolled as a Named-green path.",

"DISCRIMINATOR: RED while the skip remains `locate field_decl_block → Absent`. GREEN when body_lower_type_decl rehomes every field_decl_block type_decl onto Named containment and the skip is deleted. Nullary-coproduct Named is a different, already-green population and does not stand for this class.",

"EVIDENCE ENROLLED: v2.test.claim.declaration_graft_assemble declaration_graft_record_type_only_does_not_accept_today and declaration_graft_record_construct_does_not_accept_today (`!assemble_accepts`) cover the record spelling of the skip. declaration_graft_coproduct_beside_record_does_not_erase_rec refuses to treat Rejected as Rec survival. No enrolled witness asserts Named for a fielded variant. They flip to a permanent regression control when that spelling accepts, they do not retire.",

"RUNG FOUND AT: 1, mitigatable -- residual reconstruct contains the drop; the invalid Named-absence is still writable. CEILING: 3 once body_lower_type_decl is the Named home for field_decl_block type_decl, so graft need not skip.",

"NEXT-RUNG TRIGGER: body_lower_type_decl rehomes a field_decl_block type_decl onto a Named containment edge (the capability tracked as gunbc#11582), and namespace_graft_type_decl_named_edge no longer returns Absent on that production. Nothing smaller retires this row: landing 11582 without that rehome, or deleting the skip without the lowering, is not the climb. Closing only the record spelling while fielded variants still skip is not the climb.",
],

evidence: [],
}
6 changes: 6 additions & 0 deletions src/v2/compiler/03_name_resolve.dag
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import v2.extdeps.languages.dag {
qualified_name_from_module_node
}
import v2.compiler.namespace_graft {
namespace_graft_parse_projection_edge,
namespace_graft_strip_provenance_marker
}
import std.algebra { Cons, Empty, FreeMonoid }
Expand Down Expand Up @@ -350,11 +351,16 @@ fn module_root_find(
}
}

// Parse-projection edges (identity / captured projections, sequence spines) are
// machinery, not exports -- the same rule symbol_index_fill_containment_edge
// applies. The body's identity projection reaches this fold as a direct child.
fn try_admitted_export_binding(e: Edge) -> DeclaredBinding? {
match try_edge_declared_binding(e: e) {
Present { value: b } =>
if dag_surface_module_header_metadata_edge(name: b.name) {
optional_absent()
} else if namespace_graft_parse_projection_edge(name: b.name) {
optional_absent()
} else {
optional_present(value: b)
}
Expand Down
53 changes: 3 additions & 50 deletions src/v2/compiler/body_lowering_fold.dag
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import v2.extdeps.languages.dag {
dag_resolve_preserve_module_metadata_subtree,
parse_production_captured_child_optional,
parse_production_emitted_identity_optional,
dag_surface_kw_then_ident_from_captured,
parse_qualified_name_segments_from_capture,
qualified_name_from_module_node,
}
Expand Down Expand Up @@ -218,30 +219,6 @@ fn body_lower_seq_child(node: Node, name: Symbol) -> Optional<Node> {
}
}

fn body_lower_fn_decl_ident_from_captured(captured: Node) -> Optional<Symbol> {
match body_lower_seq_child(node: captured, name: ^grammar_sequence_right_node_projection) {
Absent => Absent
Present { value: after_kw_fn } =>
match body_lower_seq_child(node: after_kw_fn, name: ^grammar_sequence_left_node_projection) {
Absent => Absent
Present { value: ident_node } =>
match dag_binding_branded_atom_identity(node: ident_node) {
Present { value: binding } => Present { value: binding }
Absent =>
match node_atom_identity_optional(node: ident_node) {
Present { value: sym } =>
if dag_lex_token_symbol(sym: sym) {
optional_absent()
} else {
optional_present(value: sym)
}
Absent => optional_absent()
}
}
}
}
}

fn body_lower_arrow_domain_named_bindings(root: Node) -> List<Symbol> {
match root.kind {
TypeNode { connective: Conj } =>
Expand Down Expand Up @@ -2169,7 +2146,7 @@ fn body_lower_fn_decl_to_arrow(shell: Node) -> Outcome<Node> {
match body_lower_return_type_from_fn_captured(captured: captured) {
Absent => body_lower_wrapper_retained_shell(shell: shell)
Present { value: return_type } =>
match body_lower_fn_decl_ident_from_captured(captured: captured) {
match dag_surface_kw_then_ident_from_captured(captured: captured) {
Absent => body_lower_wrapper_retained_shell(shell: shell)
Present { value: fn_name } =>
let arrow = node_synthetic(
Expand Down Expand Up @@ -4971,30 +4948,6 @@ fn body_lower_forward_row_apply(shell: Node, emitted: Symbol) -> Outcome<Node> {
}
}

fn body_lower_type_decl_ident_from_captured(captured: Node) -> Optional<Symbol> {
match body_lower_seq_child(node: captured, name: ^grammar_sequence_right_node_projection) {
Absent => Absent
Present { value: after_kw_type } =>
match body_lower_seq_child(node: after_kw_type, name: ^grammar_sequence_left_node_projection) {
Absent => Absent
Present { value: ident_node } =>
match dag_binding_branded_atom_identity(node: ident_node) {
Present { value: binding } => Present { value: binding }
Absent =>
match node_atom_identity_optional(node: ident_node) {
Present { value: sym } =>
if dag_lex_token_symbol(sym: sym) {
optional_absent()
} else {
optional_present(value: sym)
}
Absent => optional_absent()
}
}
}
}
}

fn body_lower_edge_names_where_clause(e: Edge) -> Bool {
match e.label {
Named { name: n } => n == ^dag_surface_where_refinement_clause
Expand All @@ -5021,7 +4974,7 @@ fn body_lower_type_decl(shell: Node) -> Outcome<Node> {
match parse_production_captured_child_optional(node: shell) {
Absent => outcome_accepted(value: shell)
Present { value: captured } =>
match body_lower_type_decl_ident_from_captured(captured: captured) {
match dag_surface_kw_then_ident_from_captured(captured: captured) {
Absent => outcome_accepted(value: shell)
Present { value: type_name } =>
match body_lower_find_where_host_conj(root: captured) {
Expand Down
Loading
Loading