Skip to content

gen-python: land t27c's Python backend, measured over every spec (Closes #5983) - #6012

Open
gHashTag wants to merge 2 commits into
masterfrom
feat/gen-python
Open

gHashTag wants to merge 2 commits into
masterfrom
feat/gen-python

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #5983

Why

t27c gen-python was written on 2026-09-29 as 774ec4da9. That commit exists only on two local branches and on no remote, so nothing built from master can run it. Two specs also describe Python wrongly:

  • compiler_matrix.t27 names python as the backend that does not exist.
  • codegen_python.t27 is a CLARA stub. It asserts def/class output that a data-only backend never prints, and test-report reports it BLOCKED.

What

  • Cherry-pick of 774ec4da9 (codegen_python.rs, main.rs, and the shared value layer in codegen_js.rs).
    • The artifact is data. Consts become assignments. An enum becomes a dict whose discriminants resume counting after an explicit one. A struct becomes a descriptor dict.
    • fn/test/bench/invariant blocks are announced in a comment, not stubbed.
    • Every module ends with __STRUCT_ORDER__, __DECL_ORDER__ and __NOT_EMITTED__.
  • codegen_js.rs. The cherry-pick had reworded two JS/TS refusal messages. The wording is now chosen per target, so gen-js and gen-ts keep master's text.
  • bootstrap/tests/gen_python_behaviour.rs (new, 5 tests). Without python3 on PATH, a test still checks the artifact text and skips only the read-back of values.
  • bootstrap/src/codegen_python.t27 is rewritten.
    • It states the data-only contract as constants.
    • It carries ten *_LINE strings, each naming the exact line gen-python prints for a sample declaration. The integration test fails if any of them is not a line of the artifact.
    • test-report result: 2/2 pass, invariant proved. It was BLOCKED before.
  • specs/trinity/compiler_matrix.t27: ABSENT_BACKEND is now go, and the test asserts != "python". The comment says the matrix does not yet measure gen-python, just as it does not measure gen-js or gen-ts. The --self-check fixture in tools/trinity_compiler_matrix.py follows.
  • Seals: both touched specs are resealed, and seal --verify gives all hashes MATCH.

Measured: t27c gen-python over every specs/**/*.t27, then ast.parse

outcome count
artifact parses (ast.parse) and executes 1173
gen-python refused (no output, exit 1) 12
artifact printed but not valid Python 0
total 1185

All 12 refusals are parser refusals that master already has. On master's own t27c, all 12 specs exit 1 on gen, gen-c, gen-rust, gen-js and typecheck, with the same parser message (12/12 checked; only the Parse error:/Compile error: prefix differs). They are the suite's existing Parse failures: 12.

n first error line (normalised) specs
6 parse error at module level near line N: unexpected token after expression statement: Ident ar/ternary_logic, benchmarks/bench_nn, benchmarks/gf16_bfloat16_nmse, conformance/e2e_scenarios, physics/e8_lqg_bridge, physics/hslm_benchmark (5 of the 6 have a Markdown body)
2 unterminated string literal physics/gamma-conflict, physics/lqg_cs_bridge
2 parse error in fn ...: Expected RBrace, got Bang test_framework/graph_drift_detection, test_framework/verilog_bench_harness
1 parse error at module level ...: Comma api/tri_net_api
1 parse error in fn ...: Expected RBrace, got Semicolon ar/datalog_engine

What the 1173 modules leave out. Across 100 specs, __NOT_EMITTED__ holds 222 declarations. Each one is announced in the module, never silently dropped.

count reason
41 function call in a const
40 a statement where a declaration was expected
23 a name this spec does not declare
19 not an array literal
17 names a type
15 another module
10 depends on something itself not emitted
8 declared further down
4 no Python spelling

gen-js / gen-ts parity: both are byte-identical to master's t27c (6765d63) on all 1185 specs, with 0 differing outputs and 0 differing exit codes.

Tests added

test what it holds
gen_python_hello_world_parses_and_imports hello_world's artifact passes ast.parse and imports under python3
gen_python_constants_keep_their_values python3 reads back every value the spec declares: int, hex, negative, float, bool, str, 7 / 2 as //, a 1 << 40 masked to u64, bytes, and an enum dict
gen_python_refuses_a_spec_that_does_not_parse_and_prints_nothing negative control: exit 1, empty stdout
gen_python_its_own_spec_states_what_it_prints each of the 10 *_LINE claims in codegen_python.t27 is a line of its artifact; no def /class /import line; python3 reads SAMPLE_HALF=3, SAMPLE_WIDE=1099511627776, SampleLevel={'Low': 0, 'High': 7, 'Top': 8}, __NOT_EMITTED__=[]
gen_python_pinned_a_suffixed_literal_is_announced_not_emitted pinned category: 0xA5A5A5Au32 lands in __NOT_EMITTED__ (3 entries across 2 corpus specs). The fix for that category flips this test on purpose.

The cherry-pick also adds 13 unit tests in codegen_python.rs.

Checks run locally

check result
cargo build --release -p t27c ok
cargo test -p t27c -- python 19 passed, 0 failed (13 unit + 5 gen_python_behaviour + 1 tt_debug)
cargo test -p t27c -- js 49 passed, 0 failed
cargo test -p t27c -- gen_ts 14 passed, 0 failed
cargo test -p t27c -- matrix 1 passed, 0 failed
t27c suite (branch vs master 6765d63, same machine) identical FAIL sets: 661 FAIL lines on both. Both end SOME TESTS FAILED, so these failures are pre-existing on master, not introduced here. The branch run showed one extra catalog gate [emitted-unreadable], caused by the two suites racing on the shared $TMPDIR/t27-catalog-emitted directory. Run alone, t27c catalog-gate gives the same 3 findings on branch and master.
t27c seal --verify on both touched specs all hashes MATCH
t27c test-report codegen_python 2/2 pass + invariant proved; compiler_matrix 6/6 pass
tools/trinity_compiler_matrix.py --self-check PASS
tools/trinity_compiler_matrix.py check 1 finding: "the report was produced under another version of the spec". This is expected because compiler_matrix.t27 changed. The script is not wired into CI.
non-ASCII lines in touched files 0 (the 23 in main.rs are already on master)

Follow-up (after merge)

  • Re-run tools/trinity_compiler_matrix.py run on master, then re-pin NATIVE_REVISION and the report. This PR cannot do it: a squash merge changes the commit the pin would name.
  • gHashTag/trinity vendors compiler_matrix.t27 and may need a re-vendor. Website wiring for Python is out of scope here.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-04 11:03:42 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 45
PRs with All Checks Green 5
READY 3
FAILING 45
PENDING 0
NO CHECKS YET 0

These columns do not partition: 3 + 45 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=d7588f739847 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

gHashTag and others added 2 commits October 4, 2026 18:05
…red value layer

`t27c gen-python <spec>` prints the declarations a .t27 spec holds as a
plain Python module: consts as assignments, enums as dicts with quoted
keys and resuming discriminants, structs as descriptors carrying the
declared t27 field types, fn/test/bench/invariant blocks ANNOUNCED in a
comment and never stubbed (a `def` line here would be a signature this
backend invented rather than read). Supersedes the codegen_python.t27
specification stub -- the data-only contract that gen-js settled on is
the requirement; the stub's class/def sketch is not.

The deciding-generator hole this closes is the one gen-js closed, one
language over: every Python harness around a spec was reading its
constants from a hand-maintained copy, and the copy, not the spec,
decided what the harness believed. Now the module is printed by t27c and
the copy does not exist.

Python's spellings live in the value layer the three backends share,
parametrized by Target rather than duplicated: True/False/None words,
and/or/not, `//` integer division, ==/!=, dict-subscript field access,
always-quoted dict keys, `#` comments, a Python keyword list with
`$` refused, and bitwise ops masked to the DECLARED width at any width
(Python ints are unbounded; the spec's type is not) where the JS path
repairs inside 32 bits and refuses beyond. NotEmitted ships as a plain
list; bound-claim and enum-duplication messages are target-neutral.

Measured, not asserted. Corpus (/tmp/t27-bench, 1099 specs): 998
generate under BOTH backends with identical emitted/announced counts and
every Python artifact passes ast.parse; 101 are refused by both on
identical parse errors (pre-existing, unmodified); zero py-only
refusals, zero invalid artifacts, zero count mismatches. gen-js outputs
diffed against the parent commit's binary over the same corpus: 994 of
the 998 byte-identical, 4 differ ONLY in two refusal-message wordings
(object-literal -> mapping literal; the duplicate-binding message now
names both backends' failure modes) -- no emitted value changed. The
55-test codegen suite passes.

Refs #5983 -- this lands that issue's backend; the next commit closes it.

(cherry picked from commit 774ec4da954560efe46d3e0bb32978a2ff14445e)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…at it prints (Closes #5983)

- codegen_js.rs: the cherry-picked value layer had reworded two JS/TS
  refusals. That wording is now per target, so gen-js and gen-ts print
  byte-identical output to master's t27c on all 1185 specs.
- bootstrap/tests/gen_python_behaviour.rs: hello_world parses and
  imports, and constants keep the values python3 reads back. A spec
  the parser refuses prints nothing. codegen_python.t27 is held to the
  lines it claims. The suffixed-literal category is pinned.
- bootstrap/src/codegen_python.t27: the stub asserted def/class output
  and was BLOCKED in test-report. It now states the data-only contract
  as constants, with ten sample lines the test checks.
- specs/trinity/compiler_matrix.t27: ABSENT_BACKEND is now go, and the
  self-check fixture follows. Both specs are resealed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-04 11:13:41 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 43
PRs with All Checks Green 7
READY 5
FAILING 43
PENDING 0
NO CHECKS YET 0

These columns do not partition: 5 + 43 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=ecf0f8f43791 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

This was referenced Oct 4, 2026

This branch has not been deployed

No deployments
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.

gen-python: land the Python backend that exists only as an unpushed commit

1 participant