Skip to content

Carry occurrence identity on every semantic v1 Node - #9344

Merged
briansrls merged 41 commits into
mainfrom
session/crisp-lynx-780
Aug 28, 2026
Merged

briansrls merged 41 commits into
mainfrom
session/crisp-lynx-780

Conversation

@briansrls

@briansrls briansrls commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Make NodeOccurrenceIdentity a required field across the complete semantic v1 Node construction surface. Authored parser construction mints identity transactionally; semantic rebuilds preserve it; genuinely compiler-created nodes name OccurrenceSynthetic explicitly; the post-parse walk validates carried identity and produces the occurrence sidecar.

This draft currently contains the prerequisite required-field control and the pre-change stamp-order oracle. The carrier conversion remains in progress.

Admission authority

Amend the Step 2 exception to permit the parser and shared Node-construction surfaces to receive and thread NodeOccurrenceIdentity, so every successful authored v1 Node is constructed with OccurrenceMinted rather than acquiring identity through a later reconstruction. The existing post-parse occurrence walk becomes a validator and sidecar-index producer over identities already carried by the graph. This exception admits no pre-identity node family, optional or unstamped identity, synthetic default, reconstruction bridge, or general exported-surface growth. It exists solely for the ratified v2 self-host namespace cut and retires with the v1 seed.

§4b guarantee row: parser context publication

Subject grain Error class / invariant Current rung Bounded population repaired here Attainable ceiling Next-rung trigger
v1 parser combinator result publication A combinator must publish the context its accepted child returned, never the context it received; otherwise later authored nodes can be minted from a stale allocator state. Mitigatable. The current parser still relies on an unenforced context-threading convention. Focused corpus witnesses and occurrence-transport refusal contain the exercised failures, but a stale publication remains writable at an unexercised combinator. Four observed batches: function parent identity after parameters/type parameters/inferred/body/properties; if condition/branch/parent publication; recursive accepted-child lists for predicates, variants, type arguments, fields, uses, service operations, resource capabilities, parameters, statements, lambda statements, arguments, match arms/statements, field initializers, and expression lists; slice end-operand publication (#9344). The index arm was made uniform but had no observed failure. Refusing error paths publish no successful node/context pair and are outside this population. This is the bounded population actually repaired, not a claim over all parse shapes. Structurally impossible: input and child-published contexts have distinct carrier types, so a stale input context cannot inhabit a result publication. Introduce the distinct published-context carrier: parse functions consume the input-context type, successful child results carry the advanced-context type, and publishing unchanged context on legitimate no-progress/error paths requires an explicit named conversion. Returning the input context where an advanced context is required then becomes a type error.

Test plan

  • target/release/gunbc run --claim-run ... --function omitted_required_record_field_refuses — PASS; asserts exactly one blocking MissingField row naming identity.
  • target/release/gunbc run --claim-run ... --function complete_required_record_literal_accepts — PASS.
  • cargo test -p v1-compiler --test namespace_occurrence_serde occurrence_transport_round_trips_with_node_identity_and_paths -- --nocapture — PASS on the pre-change stamp-order oracle.

Build receipts:

The diagnostic-census fixture truthfully declares ReadsLiveTree; direct execution passes, while the current required floor declines live-tree witnesses. The PR does not claim required-floor enrollment for that control.

gunbc-ci-auto-heal and others added 6 commits August 26, 2026 16:18
…ore exhaustiveness over the two abort-side dispositions

MAIN IS RED, and the finding is HOW rather than what. This is a SEMANTIC
MERGE CONFLICT between two PRs that were each correct and each green, and
NEITHER IS AT FAULT:

  #9227  cd7cf33  adds dag/gunbc/build_target.dag, which MATCHES over
                      ClaimDisposition
  #9263  a968415  adds PanickedBeforeVerdict and NotAttemptedAfterAbort
                      TO ClaimDisposition

Neither PR touches the other's file. There is no textual conflict, no
merge-tree signal, and both merged cleanly. One grows a coproduct, the other
adds a match over it, and main refuses at strict preparation the moment they
meet:

  dag/gunbc/build_target.dag:177:3: error: non-exhaustive match:
    missing variant(s) PanickedBeforeVerdict, NotAttemptedAfterAbort
  dag/gunbc/build_target.dag:378:3: error: non-exhaustive match:
    missing variant(s) PanickedBeforeVerdict, NotAttemptedAfterAbort

#9263 was genuinely green on its own head (witnesses/build/floor all success,
03:38-04:56Z) and merged at 15:16Z against a main that had meanwhile acquired
the match. So this is not a PR that merged on a missing check. NO PER-PR GATE
CAN CATCH THIS CLASS BY CONSTRUCTION, because each PR is green against the
base it was tested on; the combination is what is untested. That is worth
recording separately from this repair, because the repair will look routine in
six hours and the gap will not have moved.

The compiler catching it the instant the two met is fail-closed working
correctly. It is the only thing that did catch it.

THE MAPPING IS DECIDED BY THE PARTITION THESE MATCHES ALREADY DRAW, not by
severity. blaze_test_status_of_claim_disposition already sorts on DID THE
CLAIM RUN -- RuntimeErrored is FAILED because it ran and blew up, while
RouteGap, HostToolUnresolved and ObservationUnreadable are all INCOMPLETE
because they never ran. So:

  PanickedBeforeVerdict   -> TestStatusFailed       it executed and died
  NotAttemptedAfterAbort  -> TestStatusIncomplete   it never executed

INCOMPLETE is the honest arm here rather than the soft one. Rendering a claim
that never ran as FAILED asserts that an assertion failed when no assertion
ever executed -- the execution-provenance loss DESIGN forbids, where a stage
refused before it ran must not inhabit the same carrier as a stage that ran
and found a defect.

In claim_disposition_verdict both are StandingUnsatisfied, for the same reason
read the other way: neither is a claim that satisfied its standing, and
admitting an unattempted claim as satisfied would let an aborted run report a
standing it never tested.

Verified by compiling dag/gunbc/build_target.dag as an entry.

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

The arm-by-arm policy roster enumerated every ClaimDisposition BY HAND, so the
two arms this PR adds would have landed with no executing evidence -- the exact
specification-without-execution gap DESIGN names, one rung up from the
non-exhaustive match that caused the outage.

Both dispositions join the roster, and a dedicated witness pins the split that
decides them: PanickedBeforeVerdict exports FAILED beside RuntimeErrored (the
claim ran and died), NotAttemptedAfterAbort exports INCOMPLETE beside RouteGap
(the claim never ran). The INCOMPLETE half is the assertion that earns its keep
-- it goes red on precisely the collapse that is tempting to make, where a claim
that never executed is reported as one whose assertion failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 16:20 push and the 16:27 ready-flip should each have fired a witnesses run
-- witnesses.yml lists both synchronize and ready_for_review, and carries no
draft guard -- and neither produced a run of any kind. Not queued, not failed,
not startup_failure: absent. The fleet was dispatching normally throughout that
window, so this is specific to this ref rather than the outage pattern seen
earlier today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Land the required NodeOccurrenceIdentity field across the COMPLETE v1 Node construction surface (375 literals + ~305 builder sites), under the operator's exact PublicSurfaceGrowth override: no optional field, no synthetic default, no node-kind subset, no Node.ident reuse — and the carrier PR must ca Carry occurrence identity on every semantic v1 Node Aug 26, 2026
Brian Searls added 23 commits August 26, 2026 17:18
…xhaustive' into HEAD"

This reverts commit 9f56a4e, reversing
changes made to 1bc049d.
Brian Searls added 9 commits August 27, 2026 07:32
# Conflicts:
#	src/v1/04_resolve.dag
#	src/v1/stage0/src/v1_compiler_emit_rust.rs
#	src/v1/stage0/src/v1_compiler_infer.rs
#	src/v1/stage0/src/v1_compiler_infer_resolve.rs
#	src/v1/stage0/src/v1_compiler_trait_derive_emit.rs
#	src/v1/stage0/src/v1_tests_claim_transport_roster_closure_witness_test.rs
# Conflicts:
#	src/v1/04_infer.dag
#	src/v1/stage0/src/v1_compiler_infer.rs
# Conflicts:
#	src/v1/04_infer.dag
#	src/v1/stage0/src/v1_compiler_emit_rust.rs
#	src/v1/stage0/src/v1_compiler_infer.rs
#	src/v1/stage0/src/v1_std_core.rs
# Conflicts:
#	src/v1/04_infer.dag
#	src/v1/stage0/src/v1_compiler_compile.rs
#	src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs
#	src/v1/stage0/src/v1_compiler_emit.rs
#	src/v1/stage0/src/v1_compiler_emit_rust.rs
#	src/v1/stage0/src/v1_compiler_infer.rs
#	src/v1/stage0/src/v1_compiler_infer_env.rs
#	src/v1/stage0/src/v1_compiler_infer_items.rs
#	src/v1/stage0/src/v1_compiler_infer_method.rs
#	src/v1/stage0/src/v1_compiler_infer_patterns.rs
#	src/v1/stage0/src/v1_compiler_infer_resolve.rs
#	src/v1/stage0/src/v1_compiler_infer_service.rs
#	src/v1/stage0/src/v1_compiler_infer_types.rs
#	src/v1/stage0/src/v1_compiler_parse.rs
#	src/v1/stage0/src/v1_compiler_trait_derive_emit.rs
#	src/v1/stage0/src/v1_std_core.rs
#	src/v1/stage0/src/v1_tests_claim_transport_roster_closure_witness_test.rs
Brian Searls and others added 3 commits August 28, 2026 05:43
# Conflicts:
#	src/v1/stage0/src/v1_compiler_emit_rust.rs
#	src/v1/stage0/src/v1_compiler_infer.rs
#	src/v1/stage0/src/v1_compiler_infer_types.rs
# Conflicts:
#	src/v1/stage0/src/v1_compiler_emit_rust.rs
#	src/v1/stage0/src/v1_compiler_infer_method.rs
#	src/v1/stage0/src/v1_std_core.rs
Two generated mirrors conflicted: v1_compiler_infer.rs and v1_compiler_infer_types.rs. The
generated-artifact merge driver refused them by design - it leaves the ours side in the worktree
with NO conflict markers and marks the path unmerged, because neither side's bytes are the
projection of the MERGED authorities and picking a side drops the other's authority-derived
content.

So they were NOT hand-resolved. They are the output of claim_executor --required-regen over the
merged .dag tree, installed from target/stage0-regen-candidate/src, and verified byte-identical to
that candidate.

CHECKED, because a regeneration that silently drops one side looks exactly like a correct one:
this branch's subject is occurrence identity, and the regenerated mirrors carry 148 and 31
references to NodeOccurrenceIdentity/occurrence_identity respectively. No .dag file conflicted, so
the authority merged cleanly and only its projection needed rebuilding.

Carries the same two rustfmt reflows as #9644 (cli_run.rs, line-length only, from #9637
lengthening the roadmap authority paths): pre-existing on main, arriving here via the merge, and
the generated pre-commit hook refuses without them.

NOT INCLUDED, deliberately: main also carries generated-surface drift in v1_rt.rs and four drifted
generated artifacts. Those are main's, not this branch's, and converging them here would hide them
inside an unrelated PR. #9644 covers the artifact drift; v1_rt.rs is separate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review August 28, 2026 23:21
@briansrls
briansrls merged commit 655f82a into main Aug 28, 2026
0 of 3 checks passed
@briansrls
briansrls deleted the session/crisp-lynx-780 branch August 28, 2026 23:21
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-08-28T23:29:23.514375Z 7f9c70d Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f9c70ddb8

ℹ️ 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".

Comment thread src/v1/04_resolve.dag
ItemResolveResult {
item: Node {
name: item.name, span: item.span, ident_span: item.ident_span, children: resolved_children,
occurrence_identity: OccurrenceSynthetic, name: item.name, span: item.span, ident_span: item.ident_span, children: resolved_children,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve item identities during resolution

Every successfully parsed declaration reaches this reconstruction with a minted item.occurrence_identity, but the resolved item is unconditionally marked OccurrenceSynthetic. Consequently, compile_to_resolved produces module-item nodes that can no longer be correlated with the authored IDs retained in the graph's occurrence-transport sidecar. Carry item.occurrence_identity into this semantic rebuild instead.

Useful? React with 👍 / 👎.

Comment thread src/v1/04_resolve.dag
let resolved_anno = if texpr.type_annotation == none { none } else if is_type_expr_annotation(n: texpr.type_annotation.value) { Present { value: anno_resolved.resolved } } else { texpr.type_annotation }
let let_node = Node {
name: let_binding_name_at(texpr: texpr, source_indices: env.source_indices),
occurrence_identity: OccurrenceSynthetic, name: let_binding_name_at(texpr: texpr, source_indices: env.source_indices),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve let-expression identity during resolution

When an authored let is resolved, this replacement node discards texpr.occurrence_identity and becomes synthetic. Thus, even if item-level identity is preserved, every resolved let loses its parser-minted occurrence and no longer matches its sidecar entry; use the original expression's identity for this rebuild.

Useful? React with 👍 / 👎.

Comment thread src/v1/04_infer.dag
PropertyInferenceResult {
prop: Node {
name: p.name, span: p.span, ident_span: p.ident_span,
occurrence_identity: OccurrenceSynthetic, name: p.name, span: p.span, ident_span: p.ident_span,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep authored property identity during inference

For any property whose value is inferred, this reconstruction replaces the property wrapper's minted identity with OccurrenceSynthetic. Properties that take the deferred branch retain p unchanged, so identity behavior now depends on the inference judgment rather than authorship, and judged properties cannot be correlated with their parser-side occurrence entries. Preserve p.occurrence_identity here.

Useful? React with 👍 / 👎.

briansrls pushed a commit that referenced this pull request Aug 29, 2026
briansrls pushed a commit that referenced this pull request Aug 29, 2026
…the string literal it was authored as

Bisect pinned main's runtime failure (trim expects a string, got Null on the
converge actuator) to 655f82a (#9344). Mechanism: the rewritten
parse_optional_from_key built the from_key property's value node with
NoExprData (key carried only as a node NAME), and the new field_to_child_node
passes parsed properties through instead of re-materializing them — but the
interpreter's extract_from_key accepts only ExprLiteral{LitStr}, so every
'output field from "channel"' mapping silently missed, the output key fell
back to the field name, and effect-result fields decoded as Null
(git.Core.ConfigLocalGetInRepo: .success survived by name, .value did not).

The from token IS a string literal in the grammar (ShLitStr), so the fix makes
the property value carry ExprLiteral{LitStr{key}} at the one construction site
in v1.compiler.parse parse_optional_from_key; the mirror is regenerated via
--required-regen (surface drift resolved by installing the candidate).
Smoke: the converge actuator executes end-to-end again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y
briansrls added a commit that referenced this pull request Aug 29, 2026
…osition (13 clusters to named submodules) (#9648)

* guarantee_rung_drop: close the record #9612 left unterminated

The wall_deadline_shared_fill_attribution_stall record landed without its
closing brace, so every gunbc run over the dag root refused at module index
(expected expression, found Eq) -- the same collided merge that duplicated the
cli_run.rs definitions. With the brace, the documented converge actuator entry
runs end-to-end again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Plan: hand off the per-invocation whole-tree tax finding

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Correct the pool-tax finding: linear ~20-25ms/pool-module eager graph facts, no cwd switch; fast controls were panics

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split 1/n: move seven census clusters to cli_run/ submodules (pure code motion)

test_migration, compile_clean, non_fold_residue, class_b_census,
languages_census, external_authority, inert_carrier — 107 items, ~2.1k lines.
Mechanics: each cluster becomes a cli_run/ submodule with 'use super::*' back
into the parent plus the parent's use-header; the parent re-exports
'pub(crate) use <mod>::*' so every existing path keeps resolving. Private
moved items widen to pub(crate), which rewraps a few signatures under rustfmt.
No semantic change; build-verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split 2/n: witness_gates, emit_host, complexity_gates, doc_graph, declared_refs, census_heads (pure code motion)

89 items, ~2.1k lines. Bin-consumed pub fns get explicit pub use re-exports
(the pub(crate) glob does not cross the lib/bin crate boundary).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split: widen eight report/plan types to pub(crate) (private-interface lints; CI sets -D warnings)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Plan log: cli_run decomposition progress and the two deferred cores

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split 3/n: fallback_arm_census, p1_cohort, owned_data, live_read_decode, active_workset (pure code motion)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Remove merge markers both brace-fixes left in guarantee_rung_drop.dag

Both sides of the merge fixed #9612's unclosed record identically; the auto-
merge kept both hunks' markers. Smoke-verified: the converge actuator (now at
dag/gunbc/repo/ after the filename reorg) compiles and executes again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split 4/n: entry_resolve — the resolver/index core (75 items, ~2.5k lines, pure code motion)

The pool-tax subject now has its own reviewable home: module path index,
module-graph facts, import closures, the process shared index and resolve
store (thread_local statics widened to pub(crate)), typed-module cache,
multi-entry index shell, resolve stage/span accounting. Bin-consumed fns get
explicit pub use; two cache types widened for the private-interface lint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* cli_run split 5/n: required_floor_runner — the floor fold and claim execution (49 items, ~4.8k lines, pure code motion)

run_required_floor, claim evaluation/measurement, discovery corpus, diff
observation, prepared-subject inventory, resource sampling, cgroup envelope,
route-gap expectations, floor stream/verbosity plumbing. Same recipe: bin-
consumed fns re-exported pub; two expectation/edit types widened for the
private-interface lint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Plan log: resolver core and floor runner moved

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Plan: standing dependency map (store/native/delete-eval-loop) and the single pre-registered execution test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Plan log: bisect pins the trim-Null runtime regression to #9344

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

* Fix #9344's effect-output regression: the from-key property value is the string literal it was authored as

Bisect pinned main's runtime failure (trim expects a string, got Null on the
converge actuator) to 655f82a (#9344). Mechanism: the rewritten
parse_optional_from_key built the from_key property's value node with
NoExprData (key carried only as a node NAME), and the new field_to_child_node
passes parsed properties through instead of re-materializing them — but the
interpreter's extract_from_key accepts only ExprLiteral{LitStr}, so every
'output field from "channel"' mapping silently missed, the output key fell
back to the field name, and effect-result fields decoded as Null
(git.Core.ConfigLocalGetInRepo: .success survived by name, .value did not).

The from token IS a string literal in the grammar (ShLitStr), so the fix makes
the property value carry ExprLiteral{LitStr{key}} at the one construction site
in v1.compiler.parse parse_optional_from_key; the mirror is regenerated via
--required-regen (surface drift resolved by installing the candidate).
Smoke: the converge actuator executes end-to-end again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qPeVyc2VjbdN4os17UG3y

---------

Co-authored-by: Claude <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