Skip to content

T emit go/rust bounds - #681

Merged
briansrls merged 17 commits into
mainfrom
session/sharp-heron-47
Apr 24, 2026
Merged

briansrls merged 17 commits into
mainfrom
session/sharp-heron-47

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Opened from session-dashboard for session sharp-heron-47.

Copy link
Copy Markdown
Contributor Author

Review finding:

This test does not establish the receipt it names. emit_omni_demo_fixtures_green is supposed to prove Rust, Go, and Python are all green under their real toolchains, but the implementation silently returns None when go or python3 are unavailable and still passes.

That means CI can go green while checking only Rust, with Go 0/N checked; Python 0/N checked printed as diagnostics. For a lane-closure gate, that is too weak: it turns a missing toolchain / unverified target into a passing test instead of an unmet receipt.

If this is meant to be a real closure gate, the test should fail or be explicitly ignored/skipped at the test level when the required toolchains are unavailable. As written, it is a useful local parity harness, but not a truthful proof that emit_omni_demo_fixtures_green has landed across all three targets.

briansrls and others added 3 commits April 23, 2026 22:07
…3 Python exclusions

python.dag was missing seven Int operator realizations that Rust and Go
already had: mul (*), div (//), ne (!=), lt (<), le (<=), gt (>), ge (>=).

This unblocked list_map_then_fold_twelve (uses *), list_filter_then_fold_seven
(uses >), and nested_list_builtins_inside_lambda_six (uses * inside a lambda)
from Python emission — all three were excluded from PYTHON_EMIT_EXCLUDE with
a MissingOperatorRealization note.

After regenerating bootstrap and lifting those exclusions, the Python
determinism matrix now covers 8/9 PROGRAM_FIXTURES (same as Go), and the
emit_omni_demo_fixtures_green closure test checks 8 fixtures instead of 5.
The sole remaining Python exclusion is recursive_function_call_six (Loop).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…h python.dag snapshot

Register `tests/boundary/m1_5_emit_omni_demo_test.rs` in
`EXPECTED_HAND_AUTHORED` with director-approved receipt (T-Emit lane
closure, sharp-heron-47). Refresh `parse_corpus_manifest.txt` to
reflect `python.dag`'s updated item count and hash after gaining 7
operator realizations (`mul`, `div`, `ne`, `lt`, `le`, `gt`, `ge`).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review April 24, 2026 02:14
…in assert

Split the single test into two:

- `emit_omni_demo_rust_roundtrip` (non-ignored): CI gate that runs
  unconditionally; proves the omni fixture set emits valid, executable Rust.

- `emit_omni_demo_fixtures_green` (#[ignore]): T-Emit lane closure receipt.
  Marked ignore because go/python3 are absent in CI. When run with
  --ignored it asserts both toolchains are reachable and fails hard if
  either is missing — a missing toolchain is an unmet receipt, not a skip.

Addresses review finding: prior implementation returned None for absent
toolchains and passed with 0/N targets checked, making it a useful local
harness but not a truthful lane-closure proof.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: claude / claude-opus-4-7
  • Commit: 8a52a8fd · Trigger: schedule
  • Thinking: 46s wall

Findings

  • Non-blocking — Python // vs Rust/Go truncated integer division (src/v3/spec/python.dag:470, python_int_div uses carrier "//"): Python's // is floor division, while Rust and Go integer / truncates toward zero. For negative operands these diverge (e.g. -7 / 2 → -3 in Rust/Go, -4 in Python). The T-Emit parity test in this PR will silently green as long as no omni-fixture exercises negative integer division, but the realization is semantically non-equivalent to its Rust/Go counterparts. Worth either a negative-dividend fixture added to the omni set or a comment pinning the known constraint on OrderedRing.div.

  • Non-blocking — tmp-dir leakage (src/v3/compiler/tests/boundary/m1_5_emit_omni_demo_test.rs:27-33): next_roundtrip_dir() allocates under std::env::temp_dir() and never cleans up; repeated local runs (especially with three toolchains × N fixtures) will accumulate v3_emit_omni_roundtrip_* directories indefinitely. A tempfile::TempDir or manual cleanup on success would be kinder.

Neither is a substrate / invariant / modeling-discipline violation. The boundary test is properly documented as class-5 in sg0_census_test.rs:140-146 with a named dissolution trigger ("dag-native multi-toolchain roundtrip harness"), which satisfies tracked-debt requirements. The Python op additions are mechanical and symmetric with the existing python_int_sub/python_int_eq pattern.

Verdict

APPROVE_WITH_COMMENTS — Small, narrowly-scoped diff: six Python operator realizations, a three-way parity boundary test, and the exclusion list shrink this unlocks. Modeling discipline and census bookkeeping are respected. Only the Python floor-div semantic mismatch is worth following up on before the omni-fixture set grows.

@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: 8a52a8fd64

ℹ️ 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/v3/spec/python.dag Outdated
language: python_language
target: Int
op: OrderedRing.div
carrier: "//"

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 Align Python Int division with Rust/Go truncation

Using "//" for OrderedRing.div makes Python Int division floor toward negative infinity, while the existing Go/Rust realizations use "/" on int64/i64 (truncate toward zero). This introduces cross-target semantic drift for any program that can produce negative operands (for example, (-3) / 2 yields -2 in Python but -1 in Go/Rust), so emitted Python behavior can now disagree with the same DAG on other targets.

Useful? React with 👍 / 👎.

python_int_div: add comment at definition site pinning the known
floor-vs-truncated divergence for negative dividends (-7/2 → -4 in
Python, -3 in Rust/Go). Omni fixtures don't exercise this case; the
constraint is pinned rather than fixed until a target-appropriate
truncating-div primitive is modeled.

m1_5_emit_omni_demo_test: replace bare temp-dir allocation with a RAII
`TmpDir` wrapper whose `Drop` impl calls `remove_dir_all`. Repeated
local runs with three toolchains × N fixtures no longer accumulate
`v3_emit_omni_roundtrip_*` directories indefinitely.

Regenerate bootstrap and refresh parse-corpus manifest for the
python.dag comment addition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: codex / gpt-5.4
  • Commit: 8a52a8fd · Trigger: schedule
  • Thinking: 341s wall

Findings

  • BLOCKING — src/v3/spec/python.dag:477 (INVARIANTS.md P2 Boundary Discipline / “emission is translation, not decision-making”): python_int_div maps OrderedRing.div to Python //, which is not the same operation the other backends use for Int division. Rust/Go integer / truncates toward zero, while Python // floors for negative quotients, so a valid program like -3 / 2 will disagree cross-target. The new omni-fixture reopening only exercises */> cases, so this drift is currently untested.

Verdict
REQUEST_CHANGES. The harness additions look coherent and the targeted boundary tests pass locally, but python_int_div is not semantically aligned with the existing Int contract across targets.

briansrls and others added 2 commits April 23, 2026 22:25
…_idiv

Python's `//` is floor division, which diverges from Rust/Go integer `/`
(truncate toward zero) for negative dividends (-7/2 → -4 in Python, -3
in Rust/Go). This is a semantic correctness violation for any DAG that
produces negative integer division.

Fix:
- Add `__v3_idiv(a, b)` preamble helper using `divmod`-based adjustment:
  if the remainder is non-zero and operand signs differ, adds 1 to the
  floor quotient to restore C-style truncation toward zero.
- Change `python_int_div` carrier from `"//"` to the full-expression
  template `"__v3_idiv({lhs}, {rhs})"`.
- Extend the Python emitter's binary-op rendering to detect full-expression
  carriers (those containing `{lhs}`) and render them directly instead
  of inserting into the `({lhs} {op} {rhs})` infix template.

Regenerate bootstrap and refresh parse-corpus manifest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Both the floor-div finding (flagged P1 by Codex, P2 here) and the tmp-dir leakage have been addressed in subsequent commits on this branch. Current HEAD is 3936bc5cb.

Python OrderedRing.div — now truncates toward zero:

  • Added __v3_idiv(a, b) to the Python preamble. It uses divmod-based adjustment: if r != 0 and (a < 0) != (b < 0), adds 1 to the floor quotient — restoring C-style truncation without floating-point, correct for all integer sizes.
  • Changed python_int_div carrier from "//" to the full-expression template "__v3_idiv({lhs}, {rhs})".
  • Extended the Python emitter's binary-op rendering to detect full-expression carriers (containing {lhs}) and render them directly rather than inserting into ({lhs} {op} {rhs}).

-3 / 2 now yields -1 in Python, matching Rust (-1) and Go (-1).

The earlier "pin comment" approach was superseded by the actual fix before this review was relayed.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: claude / claude-opus-4-7
  • Commit: b276e554 · Trigger: schedule
  • Thinking: 74s wall

Findings

  • src/v3/spec/python.dag:477 + src/v3/compiler/src/emit/python_target.rs:806 — OperatorRealization.carrier is now overloaded as two semantic forms (infix symbol like "*" vs full-expression template like "__v3_idiv({lhs}, {rhs})") distinguished by substring probing carrier.contains("{lhs}"). The field is declared substrate, read by the emitter, and the shape now depends on string content. This is the exact pattern P3's "Case enumeration / string-sentinel probing" and P1's "heuristic = missing upstream fact" warn against — the faithful move is a typed carrier variant (e.g. Infix(Symbol) | Template(String)) or to push binary_op itself to always be a template so only one form exists. Non-blocking because the overload is narrow and the probe is deterministic, but worth tracking: Go/Rust will hit the same split the first time either needs a target-specific helper (e.g. overflow-checked ops), and the second callsite is when this should dissolve.

Exploratory observations

  • emit_omni_demo_rust_roundtrip shells out to rustc per fixture with no optimization level / shared target dir; fine for correctness but this will get slow as the omni set grows. A shared CARGO_TARGET_DIR or a single multi-fn source would amortize.
  • The sg0 census entry (sg0_census_test.rs:140-147) names a real dissolution trigger (".dag-native multi-toolchain roundtrip harness"), which satisfies the scaffold-dissolution requirement for this hand-authored boundary file. Good.
  • __v3_idiv truncation via divmod adjustment is correct for the full Python int domain — no overflow hazard since Python ints are arbitrary precision.

Verdict

APPROVE_WITH_COMMENTS — lifts three Python exclusions with correct semantics (truncation-toward-zero pinned on all three targets), adds a real three-way parity test with an honest toolchain-assert (no silent skips), and labels the scaffold with a dissolution trigger. The carrier-overloading above is the only substrate concern and is narrow enough to defer.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: codex / gpt-5.4
  • Commit: b276e554 · Trigger: schedule
  • Thinking: 241s wall

Findings

  • BLOCKING — src/v3/spec/python.dag:473 and src/v3/compiler/src/emit/python_target.rs:803 split binary-operator authority in two: most operators still flow through python_target.syntax.binary_op, but division now smuggles a whole expression template through OperatorRealization.carrier, and the emitter distinguishes the two shapes with carrier.contains("{lhs}"). That violates INVARIANTS.md P2 / docs/modeling-discipline.md Practice 5-6: the boundary no longer declares whether carrier is an infix token or a full expression, so the consumer has to reverse-engineer string contents by convention.

Verdict
REQUEST_CHANGES. The runtime intent here looks fine, but the modeling shape is not: this introduces a second authority for Python binary-expression syntax and a convention-based discriminator in the emitter. I’d want that represented explicitly in the spec/API before merging.

briansrls and others added 2 commits April 23, 2026 22:53
…expression templates

`ExpressionSyntax.binary_op` and `OperatorRealization.carrier` both
claimed authority over how binary expressions are rendered. The emitter
had to reverse-engineer carrier string content (`carrier.contains("{lhs}")`)
to decide which path to take — a string-sentinel violation of the modeling
discipline (INVARIANTS.md P2, Practice 5-6).

Fix: make `OperatorRealization.carrier` the sole authority.

- Remove `binary_op` from `ExpressionSyntax` in `std/emit_model.dag`.
- Remove `binary_op` from `python_expressions`, `go_expressions`, and
  `rust_expressions` in all three spec files.
- Convert all infix operator carriers ("+", "-", "*", "/", "==", "!=",
  "<", "<=", ">", ">=", "&&", "||", "and", "or") to full-expression
  templates: `"({lhs} + {rhs})"` etc. Python's `__v3_idiv` carrier
  gains outer parens to match: `"(__v3_idiv({lhs}, {rhs}))"`.
- All three emitters (`emit.rs`, `python_target.rs`, `rust_target.rs`):
  remove `binary_op` field from the expression-syntax binding struct,
  remove the `syntax_field_string("binary_op")` load, and replace the
  three-binding template call with a direct two-binding render on the
  carrier. The `carrier.contains("{lhs}")` probe in python_target.rs
  is also removed — it is no longer needed.

Every `OperatorRealization.carrier` is now self-describing: it is always
a full-expression template with `{lhs}` and `{rhs}` placeholders, with
no external format convention required to interpret it.

Regenerate bootstrap and refresh parse-corpus manifest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: claude / claude-opus-4-7
  • Commit: cbb9777e · Trigger: schedule
  • Thinking: 61s wall

Findings

None blocking. This PR is a textbook coprod-dissolution:

  • ExpressionSyntax.binary_op (shell template) + per-realization carrier (operator token) were two sources of authority jointly determining the emitted binary expression. The diff collapses them into a single source — each realization's carrier is now the full expression template (src/v3/std/emit_model.dag:168, src/v3/spec/*.dag, src/v3/compiler/src/emit.rs:333,1339, python_target.rs:67,797, rust_target.rs:323,3341). Matches docs/modeling-discipline.md § "Dissolve coprods".
  • The move correctly enables target-specific shapes (Python __v3_idiv(...) for OrderedRing.div, python.dag:477) that the old shell template couldn't express — prior scaffold, now dissolved into the right place.
  • __v3_idiv (python_target.rs:671) correctly pins the OrderedRing.div = truncation-toward-zero semantic with a comment citing the source-of-truth invariant. Fail-closed on divergent Python // semantics.
  • New boundary test m1_5_emit_omni_demo_test.rs is registered in EXPECTED_HAND_AUTHORED with a documented + bounded + named dissolution trigger ("when a .dag-native multi-toolchain roundtrip harness exists", sg0_census_test.rs:140-147) — tracked debt per the criteria.
  • Honest lane-closure receipt: missing go/python3 is a hard failure, not a skip (m1_5_emit_omni_demo_test.rs:188-195). Good — unmet receipt ≠ green.
  • Python exclusion list shrinks to just recursive_function_call_six with comment naming the precise remaining blocker (Behavior::Loop).

Exploratory observation (non-blocking)

Authority for "binary-op carriers must reference {lhs} and {rhs}" now lives implicitly in every OperatorRealization author's head. render_named_template substitutes silently — a carrier like "+" would emit literally "+" with no error. The omni roundtrip catches it behaviorally, but a parse-time check in parse_expression_syntax / realization loading that binary-op carriers contain both placeholders would turn a runtime divergence into a fail-closed load error. Worth considering next pass; not a blocker for this PR.

Verdict

APPROVE — clean dual-authority dissolution, tracked scaffolding, honest receipts, semantic fidelity on Python div. Ship it.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: codex / gpt-5.4
  • Commit: cbb9777e · Trigger: schedule
  • Thinking: 282s wall

Findings

  • src/v3/spec/python.dag:464, src/v3/compiler/tests/integration/common/determinism_fixtures.rs:101, src/v3/compiler/tests/boundary/m1_5_emit_omni_demo_test.rs:181 — NON-BLOCKING, TESTING.md (behavior-driven): this PR adds Python runtime semantics for mul/div/ne/lt/le/gt/ge and removes the operator-dependent fixtures from the Python exclude list, but the only end-to-end behavior check for those newly enabled paths is emit_omni_demo_fixtures_green, which is #[ignore] and gated on Go as well. In normal CI those paths only get determinism coverage, so a semantic bug in __v3_idiv or one of the comparison carriers could still slip through.

Verdict: APPROVE_WITH_COMMENTS. The modeling/single-authority side looks clean, and the Rust omni roundtrip passed locally. My only concern is that the new Python operator behavior is not covered by an always-on behavior assertion.

briansrls and others added 5 commits April 23, 2026 23:01
… lists

PR #692 landed Behavior::Loop emission for both Python and Go. The sole
remaining entry in GO_EMIT_EXCLUDE and PYTHON_EMIT_EXCLUDE was
recursive_function_call_six (blocked on Loop support). Both lists are now
empty; all 9 PROGRAM_FIXTURES are covered by the omni set and by the 5×
determinism matrix for every target.

Update stale comments in determinism_test.rs to reflect the current state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_structurally

The test was asserting `carrier == "+"` (old infix symbol form). After the
carrier unification in the previous commit, rust_int_add's carrier is now
`"({lhs} + {rhs})"`. Update the assertion to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…holders

`render_named_template` is silent when a carrier lacks the expected
placeholders — a carrier like "+" would emit literally "+" instead of a
binary expression. Add a load-time check in all three emitters that rejects
any OperatorRealization whose carrier does not contain both {lhs} and {rhs},
turning a silent runtime divergence into a fail-closed load error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The new Python Int operators (mul, div, ne, lt, le, gt, ge) only had
determinism coverage in CI — the rendered template content was never
asserted. Add emit_python_int_operators_use_correct_expression_templates:
five always-on (non-ignored) checks that verify each operator emits the
expected Python token/call without requiring a Python toolchain.

Specifically: * emits the * operator, / emits __v3_idiv(...), != emits !=,
< emits <, > emits >.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: codex / gpt-5.4
  • Commit: 022d9a55 · Trigger: schedule
  • Thinking: 231s wall

Verdict: APPROVE. The diff looks clean and is directionally aligned with the rubric: removing ExpressionSyntax.binary_op and making OperatorRealization.carrier the sole authority improves boundary discipline rather than weakening it, and the new emitter checks fail closed if a carrier no longer names {lhs}/{rhs}. I did not find a concrete violation in the changed lines.

Focused verification passed: m1_4_emit_python_test::emit_python_int_operators_use_correct_expression_templates, m1_5_emit_omni_demo_test::emit_omni_demo_rust_roundtrip, and emit_matrix_program_python_is_deterministic. I could not run the ignored three-target parity receipt because go is not installed in this workspace.

@briansrls
briansrls merged commit bc87f5c into main Apr 24, 2026
4 checks passed
briansrls added a commit that referenced this pull request Apr 24, 2026
Rebased session/eager-wren-78 onto origin/main (squashed prior merge skew).

- Extend std.verification with AlgebraicLawKind + scaffold TestPredicate variants
  (ExecuteCommand, ForAllTargets, LensOutputEquals, DifferentialEquals, AlgebraicLaw)
  and documented dissolution triggers; single authority note on TestClaim.
- Regenerate bootstrap fixtures + parse_corpus_manifest.txt for the new surface.
- Add M1.5 verification + testgen integration coverage (fail-closed shell handling,
  runner-deferred boundaries without global panic-hook mutation).

Emit/spec/boundary files match main (#681 emit paths retained).

Made-with: Cursor

@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: a26eb13a · Trigger: schedule
  • Thinking: 353s wall

Non-blocking — Strengths

  • src/v3/std/emit_model.dag Removing ExpressionSyntax.binary_op and moving full binary expression templates into OperatorRealization.carrier aligns with single-authority emission.

✅ No blocking concerns in the current diff.

@briansrls briansrls mentioned this pull request Apr 24, 2026
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