Skip to content

v2: one roster of kernel value types; a declared Bool is judged (dag_binding_type_bool deleted) - #12785

Merged
gunbai-bot[bot] merged 67 commits into
mainfrom
session/smart-newt-725-kernel-roster
Oct 1, 2026
Merged

gunbai-bot[bot] merged 67 commits into
mainfrom
session/smart-newt-725-kernel-roster

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

DRAFT, stacked on #12763 (which is stacked on #12566 + #12714 + #12629). The diff against main shows all of them until they land; this PR's own change is 15 files. Do not merge.

What it does

v2.extdeps.languages.dag had three hand-written if-chains that each restated which symbol a kernel type has: the resolver's spelling table (dag_kernel_type_binding_optional), its declaration table (dag_kernel_type_declaration_binding_optional) and the denotation join (dag_binding_denotation). For Bool they disagreed.

They are replaced by one roster, dag_kernel_value_type_roster. A row is a value-type node owned by a std authority, an optional spelling, and the declaring paths that spelling may resolve to. A kernel type's canonical binding is the atom identity of its value-type node, derived from the row and written nowhere else. The three functions are now folds over the roster, so they cannot disagree.

Kernel type Value-type node Spelling row
Int v2.std.integer integer_int_type_node yes (v2.std.integer.Int, std.integer.Int)
Bool v2.std.logic bool_node yes (v2.std.logic.Bool, std.types.Bool)
Symbol v2.std.compilers.target_model symbol_kernel_type_node no
Char v2.std.compilers.target_model char_kernel_type_node no

The defect (DESIGN 6b)

The symptom was in infer: a declared Bool was never judged. fn f(x: Int) -> Bool { 3 } and a Bool-declared record field holding 3 were accepted with a counted UndecidableFormalUnresolved.

Measured on the real route, the earliest unjustified boundary was the language model, not infer. Resolve bound a declared Bool to bool_node_symbol (bool_node's own identity). The join denoted dag_binding_type_bool, a second symbol that only hand-built fixtures and infer's literal typing carried. So the resolved atom reached every declared-type judgment as something the join answered Absent for. Int had one symbol on both sides, which is why it worked.

dag_binding_type_bool is deleted in this change, as a replacement cut: infer's infer_literal_type_binding, six fixture sites in the language model and four test files move to bool_node's identity. No reader of the old name remains.

Scope decisions

  • Symbol and Char are a fork, recorded here and not resolved. Each has two authorities: a kernel value-type node in v2.std.compilers.target_model, and a declaration its authored spelling resolves to (v2.std.node Symbol, std.types Char). That is the same fork class as Int and Bool, where the ruling is one authority, the declaration visible in scope. The corpus does spell both in type positions, so binding either spelling to the kernel atom here would change what every such reference resolves to. Their rows therefore carry no spelling row and name, in converges_on, the declaration each converges on once de-forked. Nothing binds through that field; There is a second fork underneath: the one roster of kernel names is std.types kernel_type_set, and Symbol and Char are not in it, so target_model calls them kernel atoms while the kernel name roster does not know them. kvr_symbol_and_char_are_a_recorded_fork_that_binds_no_spelling_holds holds both sides as they are (no spelling, no declaration binding, not in kernel_type_set; Int and Bool are) and goes red if either side changes without the other. The de-fork lane (wise-dove-693) has taken both names and decides per name whether it is genuinely kernel or declaration-backed.
  • Float, Secret, Json, Unit, Bytes get no row. None has a value-type node in a v2 std authority, so there is nothing for a row to point at, and I did not invent one. Each is filed as its own failure-mode row (kernel_type_<name>_has_no_v2_value_type_node) with that node as its trigger. Unit is the most exposed: v2 sources outside tests spell it in 14 type positions.
  • String is excluded. By the text ruling, v2 String is FreeMonoid<Char>, not a kernel atom.
  • Relation to De-fork Float: binary64 authority in extdeps (IEEE 754-2019); kernel Float denotes it #12547 (std.kernel_type_denotation), agreed with wise-dove-693. Three separate facts: what a kernel name means (De-fork Float: binary64 authority in extdeps (IEEE 754-2019); kernel Float denotes it #12547's table), which v2 node carries the type in resolve and infer (this roster, a realization checked against the meaning, as Rust f64 is there), and converges_on (a provisional de-fork pointer, deleted when the fork closes). This roster adds no meaning. After De-fork Float: binary64 authority in extdeps (IEEE 754-2019); kernel Float denotes it #12547 lands, the Int and Bool rows are keyed by its std.kernel_type_name admission instead of a bare spelling, so a row for a non-kernel name is refused by construction and the five failure-mode rows become an identity join. Whichever lands second does that.
  • No single kernel type authority exists in v2 for the carrier. std.types kernel_type_set lists the kernel names only. The roster derives from the per-type node authorities that do exist.

Evidence

v2.test.claim.compiler.kernel_value_type_roster_witness_test, 6 claims, 6/6 locally.

Neighbouring suites on this head, same binary: record-field witness 13/13, denotation 3/3, declared-return 12/12, arrow-elimination 7/7, application-argument 10/10, refinement-discharge 4/4, body-let-annotation 22/22, branch-infer 4/4 and 2/2, match fail-open 7/7, atom-grounding 11/11, self-grounding wall 12/12, data-decl grounding 9/9, qualified-construct 9/9, declaration-graft 18/18, call-argument mention survival 18/18, match-arm binder frame 15/15.

Coordination

Census of newly refused sites

Instrument: claim_executor --v2-native-route --source-root dag --source-root src/v2, the route that runs v2 resolve -> infer -> eval over real modules. One BuildBuddy dispatch per sha, each verified at its pin; both exited 0.

base head
modules in the universe 832 833
refused before infer — not measured 767 768
reached v2 infer (N) 65 65
of those, accepted 35 35
of those, infer_refused 30 30
  • M = 0 newly refused, and 0 newly accepted. Every module has the same outcome at base and head. Every test has the same (identity, stage, cause) at base and head, apart from this PR's own claims: the new witness module's six, and the renamed record-field claim. Those are refused before infer on this route (a dag/std/algebra.dag import does not lower natively) and run on the seed-interpreted floor route instead.
  • What did change: 27 refusal chains got one link shorter. In 27 tests across 12 modules that were already refused at infer, the chain at base began infer_grounding_not_derived @ <node "bool_node_symbol">: a declared Bool type atom the join could not denote, left on the frontier. At head that link is gone in all 27, and bool_node_symbol appears in no verdict chain at all (27 at base, 0 at head). Each of those tests is still refused, at the same stage, for the same cause, by the next underived node in its chain. So the roster removes a frontier node; on this population it does not yet change a verdict.
    • By module: computation_identity_test 5, self_host.frontier_probe_semantic_family_receipt 5, namespace_graft.zero_metadata_test 3, self_host.v2_emitter_direct_rust_door_contract 2, the go/kotlin/python/typescript grammar claims 2 each, and 1 each in infer_transform_binary_infix_witness_test, claim_pipeline.infer, sg5_set_non_ordable_falsification, compiler_frontier_emit_probe.

Limits. N is 65 of 833, and they are v2.test.* modules, not the product corpus. The other 768 are not measured, not zero. As on #12763, the census obligation carries forward to when the v2 front end reaches the floor path for a wider population.

An earlier dispatch of this pair returned only its base half (the head run's output stopped after checkout with no build or exit line), so it was discarded and both were run again.

Still owed

🤖 Generated with Claude Code

Brian Searls and others added 30 commits September 27, 2026 16:30
…; cut every consumer root-first

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

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…parameter_order, reference_closure)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…red input); retype main's new resolved-tree test sites

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ts use the named no-declarations constructor

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Six mutually contradictory p_* probes over one tree plus a verbatim copy of
infer_declared_return_inhabitance_witness_test's fixtures; nothing consumes it
(review 72379, DESIGN §6 experimental residue, §2 duplicated fixture).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…); typecheck clean over 116 files

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ted symbol and reads .root

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ResolvedTree and walk .root

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n from their post-split homes

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…vedTree.resolved_declarations (neat-boar-16 ruling)

The head reached resolve as an unlowered dag_surface_qualified_name shell,
which resolve preserves unchanged as module metadata, so a declaration's
carrier was never resolved. It is now lowered through the one type-expression
lowering; resolve binds it; an undeclared carrier refuses unbound.
ResolvedTree gains resolved_declarations, the same module fold over the
resolved root, alongside symbol_index (the index resolution consulted). The
other declaration-body type positions are a declared frontier
(gunbc.recurring_failure_mode declaration_body_type_shell_preserved_unresolved).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
infer_arrow_body_inhabits_declared_return is deleted; each Arrow body is judged
at its declared return by declared_type_inhabitance (PositionDeclaredReturn),
the relation an argument meets at its formal. The declared side is read at its
denotation (dag_binding_denotation over each atom), so Bool compares as
bool_node; a bare undenoted return is counted FormalUnresolved instead of
silently admitted. #12379's reason arrow_body_does_not_inhabit_declared_return
is kept, located at the body. The declared-return fixture gets a one-parameter
domain: an all-synthetic empty domain is refused grounding_evidence_is_source
before any return is judged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…o later stage reads it; #12407 reads resolved_declarations) (review 72652)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n/patterns), reader census

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…truct-tag misread row (confirmed by execution)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…terns and nullary values lower through one route

The construct tag edge carries construct_tag_marker and targets the authored
qualified-name spine (a bare tag is its one-segment case); resolve binds it through
the existing doors (qualified door for 2+ segments, bare door for 1) and refuses a
non-constructor answer. Every reader migrates in one motion; no Symbol tag remains.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…er is the only new case

Narrowing it to the first edge refused field-projection bodies
(v2.std.diagnostic diagnostics_fatal_reason) and with them every importer of
diagnostic on the native route. The qualified_construct fixture now carries a
field-projection body so the shared ingest reds if it narrows again. Also: a
construct tag answered by anything but a constructor declaration or a kernel atom
refuses; plan records the one-door ruling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…12407) uses bool_node's identity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 30, 2026 17:27
gunbc-ci-auto-heal and others added 5 commits September 30, 2026 17:31
…rough a forwarding second name (review 73309)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…not inside it (DESIGN 4c)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 7 commits September 30, 2026 18:43
…the claim instead of dropping out (review 73338)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/v2/std/node.dag
#	src/v2/workflow/floor_pure_producer_share.dag
…5-kernel-roster

# Conflicts:
#	dag/gunbc/recurring_failure_mode/construct_field_value_not_typed_against_the_record_declaration.dag
#	src/v2/test/claim/compiler/infer_record_construct_field_inhabitance_witness_test.dag
#	src/v2/workflow/floor_pure_producer_share.dag
… (merge repair)

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

# Conflicts:
#	src/v2/extdeps/languages/dag.dag
…5-kernel-roster

# Conflicts:
#	src/v2/workflow/floor_pure_producer_share.dag
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Sep 30, 2026
gunbc-ci-auto-heal added 2 commits September 30, 2026 23:43
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit e8a7de1 Oct 1, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/smart-newt-725-kernel-roster branch October 1, 2026 05:38
gunbai-bot Bot pushed a commit that referenced this pull request Oct 1, 2026
gunbai-bot Bot pushed a commit that referenced this pull request Oct 1, 2026
… kernel value-type roster

main (#12785) folded the Int, Bool and Symbol if-chains into dag_kernel_value_type_roster, which the
spelling lookup, the declaration lookup and the denotation join all read. The conflicting hunks take
main's folds, and the kernel host text is added there:
- a String row: host_text_type_node, spelling "String", declaration v2.std.node.String;
- decision A becomes a field of the roster, so one kernel type's facts sit in one row. KernelValueType
  gains foreign_declaration. The String row is ForeignDeclarationBinds and every other row is
  ForeignDeclarationRefuses. dag_kernel_type_foreign_declaration reads the row instead of comparing
  bindings.
- The roster comment ("String is not a kernel atom in v2 at all") and the
  dag_kernel_string_type_spelling comment ("does not yet") now name the String row.
Stage0: the emit_rust, bindings and std_types mirrors were reset to main's copies and regenerated to
first_generation_equal=true (pass 3).
All claims hold on the rebuilt compiler: kernel String, Symbol, resolve, the map-literal rows (the
kept row still red), and #12785's kernel_value_type_roster_witness_test (6/6, so the String row
satisfies the roster laws).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Oct 2, 2026
Conflicts are import lines: main's side is taken with Bool/True/False removed from
v2.std.logic imports (the cut's rewire, applied to the 78 lines main added). The three
files main deleted stay deleted. floor_grandfathered_roster keeps both sides' rows. The
kernel value-type roster (#12785) Bool row now names std.types.Bool as its one
declaration; its witness asserts the retired v2.std.logic.Bool path binds nothing.
Generated mirrors take the #12559 side, to be regenerated.

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