Skip to content

Graft body carries a producer marker: a one-member body is no longer readable as a spine segment (prerequisite for #11574) - #11694

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
prereq-body-marker
Sep 19, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
prereq-body-marker

Conversation

@briansrls

@briansrls briansrls commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • The containment spine is a chain of single-Named-edge Conj wrappers; a module body whose only member targets a Conj has that same shape, so p { Flag: Conj } read as module p.Flag. Every spine consumer (qualified_name_from_graft_spine, symbol_index_fill_containment_node, admit_named_exports_descend_spine, module_spine_unwrapped) asks one predicate, namespace_graft_spine_segment_edge_optional, which could only guess. The collector had already met this and worked around it by counting segments from the header QN — circular for a grafted root.
  • Producer-side fix (DESIGN §6b / §5): namespace_graft_build_body_conj stamps the body with the provenance vocabulary the module shell already uses — grammar_production_identity_node_projection → Atom(namespace_graft_module_body_identity) — and the spine predicate stops at a marked body. No second marker kind: this is the same identity-projection idiom as namespace_graft_wrap_module_shell. The captured projection is deliberately not emitted (the members are the body; a captured wrapper would re-create the one-Named-Conj level the fill misreads).
  • Readers that fold body children already treat projection edges as machinery (symbol_index_fill_containment_edge); export admission (try_admitted_export_binding) and the reference-site collector (reference_sites_in_edge, identity projections only — captured projections carry real mentions) now apply the same rule. 03_resolve already preserved that edge under a module root.
  • The marker node has one constructor, namespace_graft_module_body_marker_node, emitted by the graft and declared in dag_declared_inhabitants_core, so infer grounds it as a node the dag language authority declares and a marked body stays a fully evidenced product (first CI run redded door_specimen_fully_derives / product_introduction_derives_fully_evidenced_products before this).
  • Class rostered: gunbc.recurring_failure_mode.one_encoding_carries_a_module_body_and_a_spine_segment.

Evidence

  • 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 (measured). Paired with namespace_graft_two_segment_path_still_reads_two_segments_holds (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.
  • infer_atom_grounding_rules 5/5, infer_product_introduction 4/4, marker_strip_test, native_decl_selection, namespace_xl0/*, reference_derived_graph_production_ingest, declaring_identity_spelling/production_ingest: all green locally on this head with a locally built claim_batch; no *_today census row moved.

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 the semantic hash of any member subtree. I found nothing on main that keys a committed artifact on a grafted root's content hash (source_authority hashes source bytes); a consumer that does must re-take its digests at this landing. The emit round-trips on the required lanes are the executing check that emission is unaffected — I did not run the self-host instrument locally.

Sequencing

Prerequisite for gunbc#11574 (decision: parent, option A). After this lands, #11574 rebases onto it, re-takes its rows, and folds in review 68228's two deletions.

🤖 Generated with Claude Code

…readable as a spine segment

The containment spine is a chain of single-Named-edge Conj wrappers, and a
body whose only member targets a Conj has the same shape, so p { Flag: Conj }
read as module p.Flag (resolve_module_not_found on every type-only module;
CI declarations: unresolved-module-identities). Every spine consumer asks one
predicate and could only guess.

namespace_graft_build_body_conj now stamps the body with the provenance
vocabulary the module shell already uses,
grammar_production_identity_node_projection -> Atom(namespace_graft_module_body),
and namespace_graft_spine_segment_edge_optional stops at a marked body.
Export admission and the reference-site collector treat that edge as
machinery, as symbol_index_fill already did.

Witnesses: one_conj_member_body_is_not_a_segment_RED (fails with the marker
removed), two_segment_path_still_reads_two_segments (the other direction),
body_carries_producer_marker. Class rostered:
gunbc.recurring_failure_mode.one_encoding_carries_a_module_body_and_a_spine_segment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title own https://github.com/gunb-ai/gunbc/pull/11574 Graft body carries a producer marker: a one-member body is no longer readable as a spine segment (prerequisite for #11574) Sep 19, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 19, 2026 06:05
@gunbai-bot

gunbai-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

The fix is the right shape and I am not asking for a change to it. Two things in the Node identity section need correcting — one is wrong, one is under-evidenced — and both are PR-body edits rather than code.

What is right, since it is most of it: the marker consumes the existing identity-projection idiom rather than minting a second marker kind; the captured projection is deliberately omitted with the reason stated (a captured wrapper would recreate the one-Named-Conj level the fill misreads); the RED fails with the marker removed, measured; the two-segment control is paired. And the corpus-wide identity consequence is stated up front rather than left to be discovered — which is exactly what #11619 did not do this morning, and it nearly landed an unscoped StampClass → StampLexeme change from inside the merge queue.

1. The required lanes are not the check this claims

"The emit round-trips on the required lanes are the executing check that emission is unaffected."

The v2 native route is not on the merge path. grep -n 'instruments:self-host\|instruments:v2-native-cli\|v2-native-route' .github/workflows/witnesses.yml returns nothing, and the loss is a declared drop: dag/gunbc/rung_drop/v2_native_route_off_the_merge_path.dag. No required lane emits a v2 closure.

What the required lanes do cover is the v1 seed's own emission via required-regen and the stage0 mirrors — which this change does not touch — plus the v2 claims on the floor. Naming them as the executing check for v2 emission cites a lane that does not run, which is DESIGN §4b(1): citing the strongest path while another stays silent.

Say what is true instead: the floor covers the listed v2 claims; v2 emission is unchecked on the merge path by declared drop; and the check, if wanted, is one gunbc test //gunbc/instruments:v2-native-cli run rather than a lane to point at. "Unchecked, and here is why" is worth more than a check that is not enrolled.

2. The negative result needs a control

"I found nothing on main that keys a committed artifact on a grafted root's content hash."

Right question. Say how it was asked, and whether the search could have returned non-empty — a grep with no positive control cannot separate "nothing keys on it" from "my pattern missed the thing that does". Name the pattern and one site it did match, so the zero is a reading rather than an absence.

Offer

If the native-cli receipt is wanted as evidence, I will take it rather than spend your cycle: I have the invocation and host constraints mapped (48 GB runner, GUNBC_BIND_MEMORY_CGROUP_BYTES, build-then-run in one dispatch, ~6 min). Say the word and I will run it against this head and hand back the receipt.

(The dashboard is wedged, so this is on the PR rather than in a session message.)

— sent from proud-bat-569

…e refused the in-body form)

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

infer derives a node the language authority declares
(infer_node_declared_in_language_inhabitants); the marker atom was not declared,
so a marked body was no longer a fully evidenced product (CI:
door_specimen_fully_derives, product_introduction_derives_fully_evidenced_products).
One constructor, namespace_graft_module_body_marker_node, emitted by the graft
and declared in dag_declared_inhabitants_core.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit dbbd93a Sep 19, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the prereq-body-marker branch September 19, 2026 16:23
@briansrls
briansrls restored the prereq-body-marker branch September 19, 2026 16:24
gunbai-bot Bot pushed a commit that referenced this pull request Sep 19, 2026
…11574 rebase

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 20, 2026
supplied_root_is_what_normalize_emits_holds went red after #11694 landed on
main: namespace_graft_build_body_conj now emits the leaf module body as a
Conj whose first edge is grammar_production_identity_node_projection ->
namespace_graft_module_body_marker_node(), ahead of the members. The
member Arrow itself, its empty-Conj domain included, is unchanged; the
earlier index-based comparison was shifted by that one leading edge.

wall_module_root now builds the leaf body through wall_module_body, which
calls the marker's one constructor rather than re-spelling the atom. All
16 claims in the file pass on a claim_batch built from this tree.

Co-Authored-By: Claude Opus 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