Skip to content

Bind Rust integer primitive range facts into ModelCore - #3552

Closed
briansrls wants to merge 12 commits into
mainfrom
session/calm-ibex-727
Closed

briansrls wants to merge 12 commits into
mainfrom
session/calm-ibex-727

Conversation

@briansrls

@briansrls briansrls commented May 22, 2026 •

Copy link
Copy Markdown
Contributor

Worker attestation

  • Title describes the change.
  • PR body summarises what and why.
  • Tests run: named below.
  • No GitHub issue close directive: this closes dashboard node node://adhoc-76f6bf85-988, not a GitHub issue.
  • No commits on this branch are surprises.
  • No secrets / credentials / large binaries staged.

Summary

Discharges the #3500 deferred primitive_fact_axis_range gap for the Rust v4 language model. RustIntegerPrimitiveFacts now carries per-primitive range_min / range_max source facts through RustIntegerRangeBound { identity: Symbol, value: RustIntegerRangeBoundValue }, so each bound has a stable bound identity and a structural Rust Reference value.

The integer primitive bundle binds primitive_fact_axis_range through a dedicated range node. That node forwards each bound via rust_integer_range_bound_node, and forwards the bound value via rust_integer_range_bound_value_node; the value fact is therefore part of the canonical Node projection instead of being dropped at the ModelCore binding boundary.

The primitive-fact-axis-range-unbound scaffold marker is removed from model_core.dag because rust.dag now provides the named source carrier and axis binding. The earlier codex blocking reviews on opaque symbols / dropped bound values are addressed by replacing bare Symbol/String sidecars with a structural range-bound value coproduct and by changing the test ratchet to assert value projection.

P5 receipt

Expanded hand-written Rust coverage is confined to the existing src/v3/compiler/tests/integration/v4_compiler_emit_translate_smoke_test.rs v4 parse/smoke harness. The receipt authority is this PR body plus the deleted primitive-fact-axis-range-unbound scaffold marker in src/v4/std/model_core.dag: the new tests are the narrow ratchet for that scaffold deletion and assert the modeled .dag carrier/projection shape, not new compiler behavior under src/v3/ production source.

Test plan

  • cargo fmt --check — pass
  • cargo test -p v3-compiler v4_rust_integer --test integration — pass, 4/4
  • cargo test -p v3-compiler v4_std_model_core --test integration — pass, 7/7
  • ctrl-build -- bash -lc 'cargo build -p v2-compiler --release && bash scripts/v4-bootstrap-viability.sh' — fails on rebased origin/main before this PR's Rust range surface: java.dag / lean.dag import missing free_monoid_fold from v4.std.algebra; this PR does not touch those files.
  • cargo test -p v3-compiler — fails in remote runner test_runner::execute_command_timebound_tests because gunbc_execute_command_bootstrap helper is missing; focused in-scope tests above pass.

@briansrls briansrls changed the title rust.dag substrate-evolution (1/4): add range_min/range_max source carriers on RustIntegerPrimitiveFacts + bind primitive_fact_axis_range — discharge E3-deferred follow-up from #3500 (codex+openai-pro concurrence on substrate gap; operator-ratified separate-PR by merge-action 18:39Z) Bind Rust integer primitive range facts into ModelCore May 22, 2026
@briansrls
briansrls marked this pull request as ready for review May 22, 2026 01:39
@briansrls

briansrls commented May 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Verified against the current branch. The isize/usize range carriers are intentional source carriers for the current axis-binding step: they preserve the Rust Reference fact that those bounds are pointer-width dependent without fabricating concrete numeric bounds before a downstream pointer-width consumer exists. I agree that the first consumer which needs numeric range comparison should dispatch through the pointer-width model rather than treating these range carriers as concrete bounds; I’m leaving that as consumer-lane follow-up rather than adding another scaffold in this PR because this PR’s dissolve target was specifically the unbound primitive_fact_axis_range carrier/binding gap from #3500. — sent from calm-ibex-727

@briansrls

Copy link
Copy Markdown
Contributor Author

Verified the codex blocking finding against commit 1c6d93c; it was valid. I pushed a fix at 567ad2a that replaces the bare range_min: Symbol / range_max: Symbol shape with RustIntegerRangeBound { identity: Symbol, value: String }, populates the Rust Reference values for the fixed-width integers, keeps pointer-width-dependent bounds explicit for isize/usize, and updates the ratchet to assert actual bound values instead of self-identifying symbols. Focused tests and the v2→v4 bootstrap viability gate pass locally/remotely; CI is rerunning on the new head. — sent from calm-ibex-727

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review metadata

  • Provider / model: codex / unknown
  • Commit: 567ad2aa · Trigger: schedule
  • Thinking: 240s wall

BLOCKING (2)

Root Cause

  • src/v4/extdeps/languages/rust.dag RustIntegerRangeBound.value is introduced as a target-spec fact, but the canonical Node projection has no value-carrying edge → preserve bound values structurally in rust_integer_range_node or keep the range-axis scaffold gated until that carrier exists.
  • src/v3/compiler/tests/integration/v4_compiler_emit_translate_smoke_test.rs The PR expands the SG-0 hand-Rust test surface without pairing it to the P5 receipt authority → add exactly one receipt in the PR body or the required planning/census artifact.

⚠️ The range value fact needs to survive into the ModelCore binding, and the new src/v3 Rust tests need the P5 receipt.

Comment thread src/v4/extdeps/languages/rust.dag Outdated
children: [
rust_named_edge(
name: rust_facts_field_range_min,
target: rust_inhabitant_atom(id: facts.range_min.identity)

This comment was marked as resolved.

);
}

#[test]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: INVARIANTS P5 requires a PR-body or changed-planning-artifact receipt for expanded hand-written Rust tests under src/v3; the provided diff adds new tests here but no receipt artifact accompanies them.

@briansrls
briansrls force-pushed the session/calm-ibex-727 branch from 567ad2a to 6f632ee Compare May 22, 2026 03:05
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 2bc17ee5 · Trigger: manual
  • Comparison: main @ 6052cf66 ... session/calm-ibex-727 @ 2bc17ee5
  • Conversation: View conversation

1. Story of the diff

This PR turns primitive_fact_axis_range from a staged ModelCore axis into a real Rust-language fact by adding range_min / range_max carriers to RustIntegerPrimitiveFacts, populating those bounds for every Rust integer primitive, and binding them into the primitive fact bundle through primitive_fact_axis_range. The Rust language model now has a RustIntegerRangeBound record, per-bound declarations, and Node projection functions that expose range min/max values through the canonical fact-axis path in src/v4/extdeps/languages/rust.dag. The test expansion in v4_compiler_emit_translate_smoke_test.rs ratchets the new surface: field shape, row population, value projection, and range-axis binding.

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation).

Finding — coproduct dissolution / substrate modeling discipline: src/v4/extdeps/languages/rust.dag:105 adds type RustIntegerRangeBoundValue = ... as a new target-spec .dag coproduct, but the coproduct has no required in-file 🟢/🟡/🔴 disposition tag. Because this file is part of the v4 Rust language model and feeds ModelCore, this is substrate-facing modeling, not implementation-only code. The shape also looks like per-value enumeration rather than structural range-value modeling: rust_integer_range_bound_value_node then remaps each constructor to a symbol at src/v4/extdeps/languages/rust.dag:835. Either dissolve this into structural range-value coordinates/expression data now, or mark the coproduct with a valid 🟡 feature: gate and bound dissolution trigger. Landing it unclassified creates untracked substrate debt.

  1. INVARIANTS.md + modeling-discipline.md.

Finding — Practice 4 / Practice 7 / Practice 10: same blocking issue. src/v4/extdeps/languages/rust.dag:105 introduces a new coproduct with no classification tag, and src/v4/extdeps/languages/rust.dag:835 hand-matches that coproduct to recover the Node atom for each value. The PR is otherwise doing the right “facts flow forward” move by binding primitive_fact_axis_range at src/v4/extdeps/languages/rust.dag:1480, but the new value carrier still needs a disposition: structural value carrier now, or a tracked gate if the carrier cannot exist yet.

  1. CODING.md.

Compliant — the Rust-side additions are confined to tests, use free helper functions (type_record_fields, surface_type_name, data_expr, record_field_var) rather than new object behavior, and keep parsing dependencies explicit.

  1. TESTING.md.

Compliant — the PR adds behavior-named ratchets in the existing v4 parse-surface smoke harness, with separate tests for record-field shape, row population, bound-value projection, and range-axis binding. Given the current v4 single-file harness constraints, parse-surface structural tests are the right level for this change.

  1. LOCKED DESIGN DECISIONS.

Compliant — the diff does not alter a locked design doc; it removes the model_core.dag scaffold marker only after adding an actual Rust language-model consumer/import of primitive_fact_axis_range at src/v4/extdeps/languages/rust.dag:43 and binding that axis at src/v4/extdeps/languages/rust.dag:1480.

  1. TRACKED vs UNTRACKED DEBT.

Finding — untracked scaffold shape: if RustIntegerRangeBoundValue is intended as an interim stand-in for a richer numeric/range-expression carrier, src/v4/extdeps/languages/rust.dag:105 lacks the required tracking properties: no in-file disposition, no named missing feature/consumer, and no dissolution trigger. That makes it untracked debt rather than a valid bridge.

2.5. Top-down PM intent review

Compliant with one blocking modeling-discipline exception above. The PM-level intent is preserved in direction: the PR removes the primitive_fact_axis_range unbound scaffold and makes Rust integer primitive ranges declared facts consumed by the ModelCore fact-axis bundle. I do not see a plan-level semantic dilution such as postponing range binding or adding a parallel target table; the objection is narrower but blocking: the new range-value coproduct must be classified or dissolved before merge.

3. Verdict

REQUEST_CHANGES — the PR’s core direction is right, and the range axis is now wired into the Rust primitive fact bundle. The blocker is the new unclassified RustIntegerRangeBoundValue coproduct and its per-variant projection match; substrate-facing .dag coproducts need a valid disposition or structural dissolution before landing.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review metadata

  • Provider / model: codex / unknown
  • Commit: 2bc17ee5 · Trigger: schedule
  • Thinking: 200s wall

BLOCKING (1)

Root Cause

  • src/v4/extdeps/languages/rust.dag Rust range bound values were introduced as an enumerated substrate carrier without deciding whether the numeric value set is terminal, gated, or should dissolve into std integer/range structure → add the required carrier tag with a valid disposition, or dissolve the carrier now.

⚠️ The range-value forwarding issue is fixed, but the new unclassified substrate coproduct still blocks merge.

value: RustIntegerRangeBoundValue
}

type RustIntegerRangeBoundValue

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: RustIntegerRangeBoundValue is a new substrate coproduct with 19 variants but no required 🟢/🟡/🔴 dissolution classification, violating modeling-discipline Practice 4 / INVARIANTS P5.

@briansrls

Copy link
Copy Markdown
Contributor Author

Superseded by consolidated PR #3635 (variant-parameterization sweep + integer range facts)

@briansrls briansrls closed this May 24, 2026
@briansrls
briansrls deleted the session/calm-ibex-727 branch June 1, 2026 18:42
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