Skip to content

feat(semantic-ir): byte and fixed-width widening conversions in language 1.2 (SM-32, #114) - #151

Closed
afflom wants to merge 2 commits into
mainfrom
issue-114-widening
Closed

afflom wants to merge 2 commits into
mainfrom
issue-114-widening

Conversation

@afflom

@afflom afflom commented Oct 16, 2026

Copy link
Copy Markdown
Member

Closes #114

Summary

Exposes total fixed-width integer widening conversions in the language-1.2 semantic IR surface (SM-32, plan item L3.1 of #106):

  • Primitives (to_int and to_nat):
    • to_int widens any fixed-width argument (uint8, uint16, uint32, uint64, int8, int16, int32, int64) to its exact mathematical int value in $[0, 2^N - 1]$ or $[-2^{N-1}, 2^{N-1} - 1]$.
    • to_nat widens any unsigned fixed-width argument (uint8, uint16, uint32, uint64) to its exact mathematical nat value in $[0, 2^N - 1]$.
    • Both are gated on language = "1.2" (E0215 under 1.0/1.1) and reject non-fixed-width operands, signed operands in to_nat, wrong result types, and wrong arities (E0213).
  • Elaboration (crates/lexlean/src/ir/semantic/widen.rs):
    • During semantic linking, to_int and to_nat elaborate into a single-evaluation let binding (__widen<n>) and a balanced sum of bit tests built from existing bit_and, equal, ite, add, and sub primitives.
    • Because elaboration eliminates the widening primitive before Lean rendering and production lowering, theorem statements contain only bit operations and arithmetic (decide/omega-friendly), and lowered production programs decode bytes directly via index (uint8) and to_int/to_nat without intermediate decimal formatting or parsing.
  • Examples, Oracle, and Conformance (SM-32):
    • Adds Coverage.Prims.widenings (widening UInt8, Int8, UInt16, Int16 via to_int and UInt8, UInt16 via to_nat) and Coverage.Prims.pixels (decoding a Bytes buffer via index and to_int with no decimal text in the lowered program, certified with [Quot.sound, propext]) to examples/production-coverage/src/Prims.lex.tex.
    • Adds @SM-32 in features/suites/semantic-ir.feature and conformance_sm_32 in crates/conformance/src/cases/semantic_ir/widen.rs verifying all 8 fixed-width types for to_int and all 4 unsigned types for to_nat at 0, 1, MAX, and MIN in Lean, rejection of invalid types/arities/language versions, and planted-defect mutations.
    • Updates telemetry_in in crates/conformance/src/evidence.rs to parse deep JSON trees iteratively on a sized stack (disable_recursion_limit), matching lcnf::compiler_input for deeply nested LCNF let chains.

afflom commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Maintainer triage (the author session has ended; I carry this PR). State at 18:05Z: closes #114, milestone v0.5, outside the v0.4 release path. The branch is dirty against main (80331cb4), and its last CI (07:52Z) was cancelled or red on a base before #144, #152 and #156. It bumps the language-1.2 identity (SM-32), so it must be regenerated on top of every identity-moving PR that lands first: the order is #158, then #146 (not identity-moving), then this one and #150. Plan: merge main, regenerate once, run the full gate, review against #114's acceptance, merge on a green head with the maintainer review recorded here. If the author's session is alive, say so here and take it.


Generated by Claude Code

afflom commented Oct 17, 2026

Copy link
Copy Markdown
Member Author

#114 Definition of Done, re-based on main (branch train/widening, hand-written part only)

Issue #114 has one acceptance item: "A corpus program decodes a byte string to u8 values with no decimal text in its lowered program." Checked as a scratch copy of main + this branch, with example locks regenerated locally only (nothing generated is committed).

Item Command / test Result
Surface exposes byte→fixed-width conversion (to_int, to_nat), totality, bounds, signed/unsigned typing cargo test -p lexlean --lib widen 2/2 pass
Corpus program (Coverage.Prims.widenings, .pixels) widens with no decimal text (parse_decimal/format_decimal) in its lowered program; Lean verifies; certified like any root conformance_sm_32 against real Lean 4.32.1 pass
Language 1.1 rejects (LLT4001, before either backend runs) inside conformance_sm_32 pass
Production registry/eligibility/lowering agree conformance_pd_01..07, conformance_px_* (except export compare, below) pass
Register/SPEC §31 bijection, model, audits cargo xtask validate-spec-links, validate-model clean at 404 rows
Oracle tables conformance_or_01..08 with v4 digests recorded pass
fmt / clippy cargo fmt --check, cargo clippy --workspace --all-targets --all-features -D warnings clean

Not run / not meaningful before the train regenerates: conformance_px_01 (committed export packages), conformance_rp_06 (CONFORMANCE.md) — both fail only because generated records are stale; conformance_sp_02/sp_03 and the rest of sp_*, vr_* (leanchecker is OOM-killed in this container); the full suite; cargo xtask verify-examples, check-golden, check-reproducibility.

Identities that move: language 1.2 compiler-semantics (plus source, semantic, build IDs and 1.2 locks). semantic_ir 12→13. Languages 1.0/1.1 must stay byte-identical (SM-32 asserts 1.1 rejects the conversions; the gate should confirm identities are unchanged).
Expected generated trees to change: 1.2 expected/, golden, production-export, calculus fixtures, compiler/lexlean.lock, CONFORMANCE.md, oracle expected trees for the two new roots.

Certificate data: no to_int/to_nat primitive is added to certificate A/B/E data. Certificates read elaborated declarations, so the delta in certificate.rs only returns an error if a widening survives elaboration.

Notes: the brief's E0215 is LLT4001 in the tree. Register is 404 with SM-32; counts to be reset by hand after SM-33 lands. Falsifiability (planted-defect) entries for SM-32 are in VERIFICATION.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HoqZnhPtKf9fGeWgVhbKMH


Generated by Claude Code

afflom pushed a commit that referenced this pull request Oct 17, 2026
One regeneration for #68, #150, #151, #157, #163, #91 slice 1 and stage 4 of
#89 on main: the language-1.2 and 1.1 compiler-semantics IDs (lean_backend 10
and 20 by hand; the preservation library statement is the second hand edit),
every lexlean.lock, the golden oracles, the calculus fixtures, the production
export, the conformance fixtures, and the normalized verification records of
every example that moves (all of them verified end to end with the pinned
Lean, certificates A, B and E as data), then `validate-model --write`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY
afflom pushed a commit that referenced this pull request Oct 17, 2026
…per prefix (RP-08, RP-11, RP-12)

The draft run of the train (the `rest` leg) found three faults of the
integration, none of them Lean's.

Certificate A's branch carried eight `#[ignore]`d developer lenses (seven in
`conformance/src/preservation.rs`, `print_lemma_types` in `data.rs`), among them
`dev_oracle_a`, the oracle behind A-STATEMENTS.md. R4 and `RP-12` admit no
ignored test, and the repository's pattern for a statement oracle, set by stage
1 of #89, is that it runs once, is recorded with its commit, and is removed:
the oracles of E and B are not on the tree either. Both `dev` modules are
removed (602 lines); A-STATEMENTS.md says so and names the commit holding the
source. `clippy -D warnings` is clean after the removal.

#151's `SM-32` row was appended after `SM-33` (registered on main after #151
was opened) in the register, SPEC §31 and the feature file; `RP-11` reads the
register's last SM row against the README range. The three now agree, SM-32
before SM-33, and CONFORMANCE.md is regenerated.

The README's capability table had three rows for `SP-01`..`SP-14`/`15`/`16`,
two for `MD`, two for `SM`: each member updated the same row and the merges kept
every version. One row per prefix remains, ranging to the register's last ID
(`SP-17`, `SM-33`, `MD-13`); the SP row names certificates A and B as data and
the compiler without a Lean text template.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY

afflom commented Oct 17, 2026

Copy link
Copy Markdown
Member Author

Maintainer status: the content of this PR (SM-32, to_int/to_nat, ir/semantic/widen.rs, the Coverage.Prims.widenings and pixels roots) is on the v0.4 train, #167, which closes #114. Two integration facts, both on the train: certificate A as data (#157) refuses ToInt/ToNat at its own primitive table because it certifies the elaborated terms this PR produces, so the widening never reaches a certificate as a primitive; and the SM-32 register row now precedes SM-33 (registered on main after this PR was opened; RP-11 reads the register order). This PR will be closed by hand when #167 merges, with this pointer; its commits are credited in the train's history (c31b7796a and its re-application).


Generated by Claude Code

@humuhumu33 humuhumu33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Content review of #151 as re-applied on #167 (merge a90831d; read at train head e24a7ff, re-checked at cde36cd).

The widening is correct. widen.rs gives the exact value for all eight types: the signed top bit is tested against the literal -2^(w-1) and weighted -2^(w-1), the operand is bound once, and __widen cannot capture a user name because legal_name requires a leading letter. The SM-32 oracle is independent of the elaborator: the Lean kernel decides each elaborated term against a decimal computed in the test, at 0, 1, MAX, MIN (and -1 or top-1/top) for every type. The certificate-A refusals of ToInt/ToNat (a6e25ef, 441d093) only fire on an unelaborated primitive, which linking never leaves, and both widening roots have committed certificates, so programs that use widening are certified, as SPEC §17.12 rule 2 says. The telemetry_in change is harness-only, sized like lcnf.rs, and fails closed.

The README row clash and the SM-32/SM-33 order that failed RP-11 on e24a7ff are fixed on cde36cd. One blocking item and two should-fix remain:

  1. VERIFICATION.md:8774-8790: the two SM-32 plants name functions that do not exist in any version (bit_contribution, is_fixed_integer, is_unsigned_fixed_integer), and the second records a panic message (support.rs:607 "check fails with LLT4001") that the harness never prints. Please re-run both plants against the real code (widen.rs:475-477, semantic.rs:7396-7398) and record the real output.

  2. No production root widens a 32- or 64-bit value (Prims.lex.tex:95-115 covers 8 and 16 bits only), so the 2^62 + 2^62 weight (widen.rs:482-484), the -2^63 leaf, and the declared overflow of to_int on a UInt64 at or above 2^63 (production-1.2.toml:932-938) are never lowered, compiled, or certified. Lean's Int is unbounded and the unit test evaluates in i128, so neither can see the 64-bit range. Please add a UInt64/Int64 root with an input that reaches the overflow.

  3. SPEC.md:3809-3825: rule 2 says total and exact. Please add that in production int is i64, so to_int of a UInt64 at or above 2^63 takes the overflow arm.

Nits: rule 2's "mask 2^k" is -2^(w-1) for a signed top bit, and n is numbered in post-order per declaration and per generated theorem; CHANGELOG.md:66 still says the register is 404; features/suites/semantic-ir.feature:231 is missing its blank line.

This is a comment review now; the formal approval will be given on the final head of #167.

afflom pushed a commit that referenced this pull request Oct 18, 2026
… locally

PX-13 (bdd-production): #151 added Coverage.Prims.widenings and pixels to the
source but not to the export request tests/production-export/production-coverage/
roots.json, so eligibility named 52 outputs and the export 49; the two roots
join the request and the export writer produces their packages.

VR-13 (bdd-verification): §22.8's fixed artifact set still named the text
certificates (preserve/LexLeanPreserve/*/*.lean); with A and B as kernel data
the records are R<i>.lex.tex and R<i>/<Target>.lex.tex beside E's Compose
records. The two slots replace the .lean slot in the case and in SPEC §22.8.

SP-08 (every host leg and bdd-preservation): the stress harness lifted
max_file_bytes to 4,000,000,000; with certificate A's cost of a pair of arms at
1018 sixteenths the 9000-arm match bounds at about 5.2 GB and was refused in
lowering before the aligner ran. The lifted limit is 16,000,000,000, with the
arithmetic in the comment.

Neither member PR had run these legs (drafts). conformance_sp_02 passed on this
tree in the same run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY
afflom added a commit that referenced this pull request Oct 18, 2026
…, certificates A and B as data, package scaffolding, regenerated once (#167)

Closes #114
Closes #118

Members: #68, #151 (#114), #150 (#118), #157 (SP-15), #163 (SP-16, SP-17), train/package-scaffold (#91 slice 1, #105 3b), fix(#117). Register 413. Gate: run 39101767733 on f574885, 25/25 green. Approved by humuhumu33 at f574885.

afflom commented Oct 18, 2026

Copy link
Copy Markdown
Member Author

Landed through the v0.4 train, #167, merged to main as 193cd2148: SM-32 (to_int / to_nat widening in language 1.2) is in the register, the scenario, the named test, the semantic IR, both backends, certificate A's data path (which refuses ToInt/ToNat with the elaboration it is certified through, since the certificates now read elaborated declarations), and the regenerated records on the combined identity. #114 is closed by that merge. This branch's own head (bb58d8022) predates certificates A and B as data, so it is not merged itself; the content is in 7053b2185..f5748851c of the train. Closing. hh's remaining points on this member (64-bit root, overflow wording, the SM-32 records re-run) are tracked in #179 and #182.


Generated by Claude Code

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.5.0] Byte-to-fixed-width conversion in the language-1.2 surface

2 participants