Skip to content

Namespace canonical binding: one cardinality authority with declared v1 adapter - #7506

Closed
gunbai-bot[bot] wants to merge 87 commits into
mainfrom
session/neat-raven-513-closeout
Closed

gunbai-bot[bot] wants to merge 87 commits into
mainfrom
session/neat-raven-513-closeout

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Lands namespace canonical binding (namespace-canonical-binding roadmap node): one cardinality authority (occurrence_binding_from_candidates / module_path_binding_decide) with unique-on-chain semantics (0 → Unresolved, 1 → bind, 2+ → Ambiguous). Production v1 global-bare, fn-parent, containment census, and loader paths route through that decide; nearest-wins / ImportScoped first-hit / from-anywhere bypasses are removed.

This PR continues the work from #7427 (session/vivid-swift-497) under the namespace program closeout session. The stage0 module_path_owner_binding_decide adapter remains a declared scaffold fork (generic emission Gate-1-blocked); hand-Rust growth is censused at +201 lines across three files with dissolution triggers.

Class-B import restores: Unique-on-chain exposed the witness-discovery cascade (#6985) — pool-coincidence binding. This PR re-adds bare-reference imports so the corpus stays green under closure-independent resolution. The closeout session adds explicit imports for serialize_applied_diff_swap_operands_test.dag and application_serializer.dag (discovery-corpus failures on the prior CI run).

Test plan

  • occurrence_binding_resolve_witness_test.dag — 19/19 binding witnesses green
  • namespace_unique_on_chain_policy_test.rs — hand-Rust policy witnesses + LOC census (9/9)
  • regen_stage0 --verify — regen_divergence_count=0
  • cargo check -p v1-compiler-tests --tests — compile gate clean
  • CI floor on this branch (in flight after Class-B import closeout fixes)

Worker attestation

  • Title describes the change (not the session id or branch).
  • PR body summarises what and why.
  • Tests: occurrence_binding witnesses + policy census + regen verify executed locally; CI floor pending.
  • No secrets / credentials / large binaries staged.
  • No surprise commits — branch history is the vivid-swift-497 namespace-canonical-binding lane plus two closeout Class-B import fixes.

gunbc-ci-auto-heal and others added 30 commits July 30, 2026 08:06
Co-authored-by: Cursor <cursoragent@cursor.com>
The v1 adapter no longer imports generic std.occurrence_binding modules
into stage0; regen drops the stale lib.rs module declarations and emits
the String-only cardinality fold that avoids the BindingCandidate closure
annotation the emitter could not import.

Co-authored-by: Cursor <cursoragent@cursor.com>
Under NamespaceOnlyY, containment_resolve_fn_v1_for_module now applies
the same on-chain cardinality fold as inference: empty chain → Unresolved,
one → unique hit, two-plus → Ambiguous. Witnessed by
zero_on_chain_containment_census_matches_inference_unresolved.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ategory predicate.

global_bare_is_ambiguous and cli_run containment census now call module_path_owner_binding_decide instead of inline chain.len() counts; occurrence_category_admissible becomes occurrence_category_binding_verdict at its single authority in std.occurrence_identity.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ction in sigs.

Remove the no-op project_module_path_binding_decide wrapper and route func-parent cardinality through ModulePathBindingProjection directly instead of 0/1/2 Int sentinels.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move FreeMonoid containment walkers to std.occurrence_identity (fold-based ancestor membership), register v1 adapter and hand-Rust policy witnesses with roadmap anchors and non_fold_residue rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
Codex review 44830: the unique index arm bypassed the canonical decision path,
binding off-chain declarations when only one corpus-wide candidate existed.
Inference, lookup, and containment census now enumerate chain candidates and
fold through module_path_owner_binding_decide for both index variants; adds
single-off-chain regression tests with scaffold receipt update.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sync committed stage0 outputs with 04_env/04_lookup canonical-binding
routing (regen_stage0 --verify clean). Merge origin/main so heal's
binary/source skew guard and regen job see an up-to-date tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
18e132f landed the .dag policy-switch removal but omitted the emitted
stage0 refresh, so tests asserting policy-bracket independence still hit
nearest-wins/first-hit in v1_compiler_infer_env/sigs. Regen + fmt align
the executable artifact with module_path_owner_binding_decide everywhere
(review 44928).

Co-authored-by: Cursor <cursoragent@cursor.com>
The 1004 "parse failed" messages were one wholesale resolve failure
reported N times: analyze_to_surface collapsed parse/enumerate/no-module
into Option::None, and parse_dag_file discarded result.error. Surface
those causes. Then move floor_discovery_scan_test_decl_names into
floor_naming_hygiene so test_module_hygiene resolve no longer pulls
filesystem_io's stripped ExternalAuthority/Uri imports (msg_7c1fcc27).

Co-authored-by: Cursor <cursoragent@cursor.com>
Closing GlobalBareUniqueBinding's from-anywhere fallback (roadmap
out_of_scope: no "only one of these anywhere") makes import-stripped
extdeps/std files refuse under heal/regen resolve. Restore the pre-strip
import blocks for the heal closure, plus the few never-imported surfaces
that had the same accidental coverage (ssh/session, os/invocation,
artifact, body_producer_forward, cross_tree.resolution). Verified
generated_artifact_gate main_wet ExitSuccess locally.

Co-authored-by: Cursor <cursoragent@cursor.com>
Align seed with 04_env/04_occurrence_binding after review 44987/44993
deleted the Bool helper, and restore cloud/body_producer_forward/artifact
imports that unique-on-chain exposed in heal main_wet.

Co-authored-by: Cursor <cursoragent@cursor.com>
Loader Ambiguous/Unique arms used nearest-ancestor / from-anywhere
while inference folds via module_path_owner_binding_decide — same
authority as containment_resolve (review 45004).

Co-authored-by: Cursor <cursoragent@cursor.com>
Move is_prefix_of onto List (= FreeMonoid) in std.types so emit
attaches Clone, regenerate the stage0 seed (two-pass fixed point),
and delete the accidental second occurrence_id_eq (review 45022).

Co-authored-by: Cursor <cursoragent@cursor.com>
…d arity.

Malformed transports refuse before Bound/Unbound/Ambiguous, and index lookups
use entries_by_id once instead of rescanning OccurrenceIndex.entries.
FreeMonoid stays out of container_type_arity so String literals do not collide
with FreeMonoid<Char> (review 45043; calm-badger String/FreeMonoid diagnosis).

Co-authored-by: Cursor <cursoragent@cursor.com>
Brian Searls and others added 22 commits July 30, 2026 21:31
The autosave committed the in-progress merge with conflict markers still in
both files (3 marker lines each) and 8 duplicated import names. This commits
the actual resolution.

Both conflicts are import-list collisions. gunbc/witness_row_cost.dag is a
union: keep this branch's names and add main's TimedOut (declared at
dag/std/observation.dag:208), inserted in sorted position.

The witness test is NOT a union. Main's side lists nine names, but eight of
them already appear in the same import block below the conflict region, so
taking the union would have duplicated them. Only
witness_cost_seed_timed_out_event (gunbc/witness_row_cost.dag:540) is
genuinely new, so that is the only name added; the block is then re-sorted.

Verified by execution: the entry compiles clean with no diagnostics, and the
import block has 0 duplicates.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
reference_occurrence_by_id rebuilt an index the validation boundary had
already built and thrown away: occurrence_transport_validate constructs
references_by_id to decide declaration refusals, but ValidatedOccurrenceTransport
carried only entries_by_id, so reference lookup re-derived the same fact with a
linear filter over the references list.

That is a second representation of a fact this boundary owns, and it is the
exact rescan the module's own authority note already forbids -- "Resolvers
consume the validated carrier -- never rescan ... per authored occurrence."
The note stated the rule while the code beside it broke it.

references_by_id is now a field on ValidatedOccurrenceTransport, populated at
the single construction site from role_index_build.references_by_id (already in
scope there), and reference_occurrence_by_id is a map_get on it. Both authority
notes are updated so the prose matches the carrier rather than rotting against
it.

The declarations/references lists stay on the carrier: the refusal folds
consume them in order, so they are traversal inputs, not a lookup path.

Verified by execution, not inspection: all 11 occurrence-binding witnesses pass
(unique / unbound / ambiguous / duplicate, the module-path trio, the
single-fold-authority claim, and three refusal controls). RED control run --
emptying the carried index turns unbound_reference_refuses and
unique_reference_is_bound FAIL, while unknown_occurrence_refuses correctly
stays green because it is the miss path an empty index cannot change; the
perturbation was restored and confirmed absent from the commit. regen wrote
only std_occurrence_identity.rs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The merge with origin/main (PR #7490's typecheck perf fixes) conflicted in
the generated v1_compiler_infer.rs, and the autosave committed the tree with
the conflict markers still in it — cargo fmt's diff-marker gate failed the
build job in 52s.

04_infer.dag merged cleanly and is byte-identical to main's, so the file is
derived, not hand-picked: regen_stage0 emits it, and the two-generation check
(rebuild from the regenerated source, then regen_stage0 --verify) reports
regen_divergence_count=0.
… fork

§5 — diagnostic_to_span minted two placeholder SourceSpans for the
OccurrenceTransportViolation arm: a bespoke "<unknown-occurrence:N>" file and a
wildcard "<occurrence-transport-refusal>". Both are removed; the arm now renders
no_span(), the corpus's single no-location authority.

The wildcard was the absorbing arm the reviewer named — a future spanless
refusal would have been absorbed into an anonymous placeholder. It is now
unreachable by construction rather than merely unused: adding a variant reds the
total, wildcard-free matches in occurrence_transport_refusal_diagnostic_span and
_diagnostic_message. The "<unknown-occurrence:N>" file was additionally a §2
duplicate — the occurrence id is already carried by the message, its single owner.

Proven by execution, not inspection: no dag/test/claim witness imports v1 at all,
so the two discriminating tests live in the lane's Rust witness.
unknown_occurrence_refusal_renders_no_span_never_a_minted_pseudo_file reds if the
placeholder returns (it rejects any span whose file names the id);
span_carrying_refusal_still_reports_its_authored_span reds if the fix over-reaches
and flattens real spans. 11/11 green.

§3 — global_bare_chain_ambiguity_labels_from_decide and
func_parent_closure_ambiguity_labels_from_decide were token-identical modulo a
bind name. Collapsed to one ambiguity_labels_from_decide: the call site is not
part of the fact.

Bound stated, not hidden: diagnostic_to_span still returns SourceSpan, not
SourceSpan?, so absence is rendered rather than typed. Typing it is a
load-bearing seed signature change across 3 .dag and 24 Rust call sites — a
separate corpus-wide change, recorded in the carrier note.

Also repairs four typecheck_module callers left stale by #7490 (main's test crate
does not compile; nextest left CI 2026-07-11, so no gate saw it). The lines match
PR #7494's exactly so the two converge instead of conflicting; #7494 also adds the
cargo check gate that closes the hole.

Census re-derived from its rows: +104 +83 +14 +4 = +205, witnessed.
regen_stage0 --verify: regen_divergence_count=0.
Whole-tree compile-clean on this branch reported 3 hard UnresolvedType
diagnostics, all in dag/extdeps/cloud/gcp/auth_print_access_token.dag:
ExternalAuthority x2 and Uri x1.

It is the Class-B shape this PR already restores across the corpus: the file
references ExternalAuthority, Uri and Https but imports only std.types, so those
bare cross-module references resolved by pool-membership coincidence. Under
closure-independent unique-on-chain neither extdeps.uri nor
extdeps.external_authority is on extdeps.cloud.gcp.*'s containment chain, so
zero-on-chain is Unresolved rather than a whole-corpus search — the intended
refusal, landing on a file the restore pass missed.

The imports are the pattern its own sibling already uses (extdeps.cloud.gcp
serviceusage): import extdeps.external_authority { ExternalAuthority } and
import extdeps.uri { Uri, Https }.

Verified by execution: gunbc compile --entry on that module's closure reports
0 blocking errors (was 3 UnresolvedType); the 2 remaining diagnostics are
advisory under gunbc.compile_clean_diagnostic_policy.
…-fold

Finding 1 (census inconsistency) — REAL, and wider than reported. The
merge-repair row's prose still read "+7 lines" after the scalar, the file list
and the total were corrected to 4. Fixed.

Auditing every numeric claim in the carrier then found a second stale pair the
review had not reached: the cli_run row carried an absolute before/after LOC
pair, and #7483 grew that file by ~1,556 lines, so both halves were false while
the delta stayed exactly right. The row's own stated method already says a delta
is the correct measure for a 32k-line host module, so the absolutes were a second
representation of a fact it already owned — deleted rather than re-pinned, since
re-pinning only resets the clock on the same rot.

Every number in the carrier now ties: 104 = 348-244, 83, 14, 4, total 205.

New witnesses close the class rather than just the instance. The total already
had a sum-and-prose tie, which is why the total stayed correct; the per-row prose
had none. merge_repair_growth_is_censused now pins the scalar at 4 AND requires
"+4 lines" in its note, and cli_run_carries_no_stale_absolutes refuses the
deleted absolute. That second witness caught its own bug on first run: the
explanation I wrote quoted the stale number, so the note still carried it. Now
described rather than quoted — a dead number reprinted in prose is still a number
this carrier appears to assert.

Finding 2 (substrate any-fold) — REAL, and the delete arm is the right one.
occurrence_containment_path_contains_ancestor had ZERO consumers corpus-wide
(dag, src/v2, src/v1): its declaration, its own note, its own emission. The
review 45014/45081 correction is what orphaned it — once prefix stopped
consulting ancestor-membership alone it had no callers — so deleting it completes
that fix instead of leaving a dead second surface.

Not routed through a canonical any, deliberately: any exists ONLY in
src/v2/std/algebra.dag (v2.std.algebra, the compiler's private copy of std).
dag/std/algebra.dag, the authority, has none. Importing it would point the
authority at a copy of itself — a §3 inversion. With zero consumers there is no
surface to preserve, so deletion is both smaller and correct.

regen_stage0 --verify: regen_divergence_count=0. 9/9 census witnesses,
11/11 binding witnesses green.
Review 45420 (REQUEST_CHANGES) — REAL. The retention row in
test.retirement.namespace_unique_on_chain_policy_retained embedded its OWN copy
of the census (before=244 after=277 net=+33). When the real receipt moved to
348/+104, the copy stayed behind and became false without anyone touching this
file — a §3 parallel representation of a fact the scaffold owns.

Took the review's second option rather than its first: the numbers are DELETED,
not aligned. Aligning two copies only resets the clock on the same drift, which
is precisely what happened here and, one review earlier, to the cli_run
absolutes (review 45409). The row now names
gunbc.namespace_unique_on_chain_policy_scaffold as the one census authority and
carries no numbers of its own.

New witness closes the class, since this is the second recurrence:
retention_defers_to_one_census_authority refuses "net=+" and "after=" in the
retention reason and requires it to name the authority. That is now three
carriers where the numeric drift is mechanically refused rather than reviewed.

Also review 45417 (APPROVE, non-blocking): ambiguity_labels_from_decide still
carried a _ => [] arm inherited from the two functions it replaced.
ModulePathBindingProjection is a closed 3-arm type, so a wildcard means a future
variant silently yields NO labels — an ambiguity reporting as unambiguous, the
same absorbing shape this PR deleted from diagnostic_to_span. Hit and Miss are
now explicit; behavior is identical ([] for both), and adding a variant is a
compile error rather than a silent empty list. Verified in the emitted Rust: the
match has no _ => arm.

Not changed from review 45417, with reason: binding_candidates_for_reference's
Absent => acc arm. Validation already refuses with
MissingAuthoredOccurrenceIdentity when a declaration id is missing from the
index, so on a ValidatedOccurrenceTransport the arm is unreachable — the bad
state is unwritable, not merely unchecked — and it is an explicit Option arm, not
a wildcard, so no future variant can slip through it. Making that unreachability
structural means having the validated carrier pair declarations with their
entries, a std signature change out of scope here.

regen_stage0 --verify: regen_divergence_count=0. 10/10 census witnesses,
11/11 v1 lane tests, cargo check -p v1-compiler-tests --tests clean.
TWO INDEPENDENT FIXES.

1. The floor's first COMPLETED run (43m13s, no timeout) failed on real Class-B
resolve errors: src/v2/lens/affected_set/closure_deep_chain.dag,
closure_superset_safe.dag and sg_claims_test.dag. closure_deep_chain.dag had
ZERO imports and referenced Node, Edge, DependencyView, dependency_lens,
affected_set_closure, contains, claim_atom_node and more as bare cross-module
names resolving by pool-membership coincidence. Under closure-independent
unique-on-chain none of those declaring modules is on
v2.test.lens_affected_set.*'s containment chain, so they refuse — the intended
behavior, landing on files the restore pass missed.

Why they were missed locally: the whole-tree compile-clean I ran uses
witness_layer_roots, but the floor's DISCOVERY corpus resolves each *_test.dag
closure. Different scope, so a clean whole-tree run does not imply a clean
discovery batch. Auditing that scope also surfaced a fourth zero-import file CI
had not yet reached, frontier_observation.dag, fixed here before it could red a
later run.

Verified by execution: closure_deep_chain, closure_superset_safe and
frontier_observation each compile with 0 blocking errors (was 13, 13 and 3
unresolved names).

2. Review 45443 (REQUEST_CHANGES) — REAL, and pointed at this PR's own headline
claim. occurrence_binding_decide was a signature-identical forwarder around
std.occurrence_binding occurrence_binding_from_candidates. Both were public and
each had its own witness suite, so the module asserting "THE one name-decision
function" shipped two public names for one decision — the §3 nickname it exists
to prevent.

Deleted the forwarder rather than keeping it as an entry point: it added no
behavior, and a second name for one decision is the violation regardless of
intent. Both internal callers and both witness call sites now name
occurrence_binding_from_candidates directly. module_path_binding_decide is
retained because it is not a forwarder — it constructs the occurrence and
candidate population from module paths, which is real work.

19/19 binding witnesses green across both suites; regen_divergence_count=0.
The autosave pushed an in-flight automated edit (260 files, +1276 lines) that
was still being verified. It is reverted whole, not patched forward.

WHY REVERTED RATHER THAN FIXED: the insertion logic appended imports after the
final closing brace in files whose leading import block ended early, producing
"expected item declaration" parse errors. 41 files were corrupted; repairing
them mechanically fixed 15 and left 35, i.e. the repair was reproducing the
class it was meant to remove. That is the DESIGN section 5 workaround signal --
noticing you are routing around your own breakage is the line stop -- so the
edit goes back to the last verified state instead of forward.

WHY THE VERIFICATION MISSED IT, which matters more than the bug: the restore was
checked with claim_batch --entry, which reported 273/273 OK on exactly the files
that regen then rejected. claim_batch's parse path tolerates a trailing import;
build_module_path_index does not. A green run from the wrong oracle is not
evidence, and this one produced a confident 273/273 over corrupted files.

WHAT THE WORK ESTABLISHED, and is kept as measurement rather than diff:
- 219 of src/v2's 549 test files fail to resolve under this branch.
- On a 96-file differential against origin/main using the identical binary and
  invocation on both sides: 77 are clean on main and broken here, 19 fail on
  main too. So roughly 175 are genuine regressions of removing the whole-corpus
  fallback, and the rest are pre-existing and not this lane's to fix.
- A 45,299-symbol corpus index resolves 98.3% of names to exactly one module,
  so the restore is mechanically tractable -- the failure above was insertion
  position, not symbol mapping.

The four hand-verified Class-B fixes from 4bf0c5e are untouched.
PR #7494 landed the identical typecheck_module caller repair on main, so
the four lines this PR censused as merge repair are no longer in its diff.
That is exactly the trigger the row declared for itself: "this row deletes
when the 7490 repair lands the same fix on main (the delta goes to 0 by
convergence)."  So the row is deleted rather than carried as a permanent 4.

This is a dissolution, not a correction.  The three surviving rows are
unchanged and re-measured against the new merge base 6c6e2dc:

  src/v1/tests/src/namespace_unique_on_chain_policy_test.rs  +104
  src/v1/stage0/src/cli_run.rs                                +83
  src/v1/stage0/src/module_path_index/parsed_dag_file.rs      +14
  src/v1/stage0/src/cli_run/test_module_hygiene_bridge.rs      +0
                                                             ----
                                                             +201

The witness suite is the thing that forces this: it asserts the total
equals the sum of its rows AND that the census note spells the same total,
so leaving 205 in place would have gone red rather than quietly drifting.
Both halves updated together; 9/9 green by execution.

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

The serialize_applied_diff_swap_operands witness imports this module;
without explicit imports both files refuse under closure-independent
unique-on-chain binding (pool-coincidence coverage removed).

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot gunbai-bot Bot changed the title namespace program closeout Namespace canonical binding: one cardinality authority with declared v1 adapter Jul 31, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 31, 2026 18:50
@gunbai-bot
gunbai-bot Bot marked this pull request as draft July 31, 2026 18:50
@gunbai-bot

gunbai-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Converting to draft and closing shortly — not a defect in the work, a scope stop.

This branch continues PR #7427's namespace-canonical-binding lane, and #7427 was frozen by operator ruling earlier today. The two Class-B import fixes it adds (serialize_applied_diff_swap_operands_test.dag, application_serializer.dag) are part of a corpus-wide import-restoration program that has been cancelled outright — a whole-corpus measurement showed the true population is 771 files / 18,048 diagnostics, and the ruling was that authoring imports into them would build the representation the roadmap is committed to deleting.

The replacement program is already dispatched as five lanes from main: #7507 (census authority), #7508 (cardinality kernel extracted from #7427), #7509, #7510, #7511. Fixing individual missing imports per floor run is explicitly the thing that ruling ruled out.

No work is lost — #7427 remains open as the audit record, and its kernel is being extracted properly in #7508.

— sent from calm-badger-682

@gunbai-bot

gunbai-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Closing per calm-badger-682 ruling: closeout work item was a placeholder, not a dispatch. Namespace program continues via PRs 7507–7511; #7427 frozen as audit record.

@gunbai-bot gunbai-bot Bot closed this Jul 31, 2026
@gunbai-bot gunbai-bot Bot mentioned this pull request Jul 31, 2026
6 tasks
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