Repository navigation
fix(backend): lower explicit shared byte literals without widening limits - #68
13 commits merged into
Conversation
|
Corrected the MD-02 representation regression in 0865df4. The independent, closed-expression oracle now compares every embedded artifact byte, including explicit UInt8 literals and local octet sharing; it rejects opaque, unbound, out-of-range, noncanonical, forged, and duplicate definitions. All original MD-02 digest, manifest, theorem, LaTeX, negative, and resource assertions remain. Independent source review, the new rejection test, complete MD-02, formatting, and strict package Clippy passed locally in the pinned tools container. Fresh full CI is required before acceptance; the previous host-matrix failures remain failures, not evidence for this head. |
…tput
The base gained tests/tooling/{commands,core,traversal}, each publishing its
generated tree under its own expected/ directory, after this script was
written. Its scope list and generated-root discovery were constants that
predate them, so the captured patch could not reconstruct the result tree.
Derive the tooling roots the way the example roots are derived.
Rebased onto main and regenerated with the repository own writers rather than the branch original capture: locks for every example project and the compiler, the golden oracles, the calculus modules, the negative fixtures locks (the six protected admission fixtures skipped), the fixtures, and the normalized verification records. The tree is the writers output: check-golden reports every published artifact equal to its oracle, check-calculus reports the embedded modules a fixed point across the second compiler build, check-fixtures reports every fixture equal to its expected files, and the branch own capture harness reports a complete, reconstructible generated tree with no non-generated path changed. Every difference against main is a digest, a digest-bearing name, a position that moved because the rendering grew, or a byte-literal respelling; the only substantive movement is the externals swap the lowering implies (UInt8.instOfNat out, UInt8.ofNat in, one for one).
0865df4 to
c384e62
Compare
|
Recorded under L0.4 of the completion plan #106 (open pull requests reviewed against R3–R6 and merged or closed). Generated by Claude Code |
|
L0.4 of #106: where this PR stands against Not obsolete. What it buys, measured. Before moving language identities for it I timed the two renderings in the pinned Lean 4.32.1 on a scratch file, one
At the default What I need to decide. The PR says its purpose is to unblock PrismPM corpus generation and claims no speedup. If a PrismPM corpus fails today with the old lowering, the reproduction (the corpus or its size and shape, and the error) is what justifies the identity change; with it I will rebase this onto The scratch files and the timings are not committed; they are reproducible from the table above. Generated by Claude Code |
|
Maintainer triage at 18:05Z. This PR (the PrismPM byte-literal lowering) is Generated by Claude Code |
Generated outputs take main's side and are regenerated by the maintainer's sweep; the CI maintenance mode and capture scripts are dropped. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPy3EVAUhMVS5f13tr9Ka
The unit test follows Render's lean_imports field; SM-19's evaluation compiles the shipped runtime the generated module imports. VERIFICATION.md records the red against main's lowerer and the measured Lean timings. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPy3EVAUhMVS5f13tr9Ka
|
Owner decision, 2026-10-17: #68 is completed as part of v0.4, with the other open pull requests. This replaces my triage note of 18:05Z on the 16th (which asked whether PrismPM still needs the lowering); the answer is yes. What that means, concretely (contributor session
Generated by Claude Code |
…both renderings Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014jPy3EVAUhMVS5f13tr9Ka
|
DoD checklist at
Generated by Claude Code |
…icit byte-literal spelling (#68); lowering-size-limit is a wide match; SPEC cost table #68 writes a bytes literal's octets as `UInt8.ofNat (nat_lit n)`. The generated TargetSemantics module therefore compares two byte arrays spelled that way, and the embedded preservation library, which checks a stored equation against the elaborator's, refused the stored `fromOrdering.eq_1` (LLV7014). Its statement now spells the two arrays as the elaborator makes them (twelve nodes inserted before the statement; later ids shifted by thirteen, `lexlean fmt` canonical). Certificates A and B are kernel data, so a repeated type is one node and the chain `g_k<T> = g_{k+1}<(T, T)>` 16 deep, the old `lowering-size-limit`, now verifies (`COSTS_A.type_node` is 0). The fixture is a match on 400 constructors: LLS8002 in lowering, certificate A at least 10,200,437 bytes, 1,205 program nodes, 20 KB of source. SPEC.md §17.17 *Limits* carries the cost table `COSTS_A` and `COSTS_B` state (it still had the text-certificate costs) and says why the chain no longer measures a certificate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY
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
|
Maintainer status: this PR's head This PR merges when #167 does (one gate on the integrated tree). Item 6 remains the owner's adoption gate in PrismPM, as the description says. Generated by Claude Code |
humuhumu33
left a comment
There was a problem hiding this comment.
Content review of #68 at 22663a7 (train member of #167).
The renderer and the independent reader are correct. Every octet is written root.UInt8.ofNat (nat_lit n), the empty array is root.ByteArray.mk #[], and bindings begin at four occurrences in ascending order. The let scope is parenthesized and holds only closed octets, so it can neither capture an outer name nor be captured. Several literals in one definition are covered by SM-19's byteCorpus under Lean. The reader in semantic_ir/bytes.rs shares no code with the renderer and refuses every noncanonical form I tried. Only MD-02's two exact-text byte assertions changed, both into decode-and-compare; nothing else in MD-02 was dropped or weakened.
-
Blocking, to fix on #167: OR-04's plant "a split limit one too small" (crates/conformance/src/cases/oracle.rs:1757-1760, replace_once "let _x_74 = 4;" on Coverage.Prims.text) is anchored to a local name in the oracle's Rust. That Rust is generated from LexLean's Lean, and Coverage.Prims.text contains byte literals this PR respells. CI run 39051756984 (bdd-verification) fails with "the edit does not apply to Coverage.Prims.text"; the same leg passed on main 243f0c7, and this head is 243f0c7 plus the six hand-written files. #167 leaves the plant unchanged (oracle.rs:1759-1761), and its draft CI does not run this leg. Please re-anchor every OR-04 plant on a root whose Lean contains a byte literal, and run conformance_or_04 before #167 is marked ready.
-
Should-fix: VERIFICATION.md:274-277 and 292-305 measure a scratch file with Lean's default heartbeats (and, for the bisection, the default depth). Generated modules set maxRecDepth 100000 and maxHeartbeats 1000000000 (backend/semantic.rs:1866). The text also says SM-19's largest corpus is 1024 bytes, but verify_large_byte_declaration(true) (semantic_ir.rs:57-67, 1087-1088) has 8192-byte literals with all 256 values, and it passes under Lean in CI. So the 6394-byte ceiling and "does not move the largest elaborable literal" describe the scratch file, not LexLean's output. Please name the options used, correct 1024 to 8192, and limit or re-measure the conclusion.
-
Should-fix: VERIFICATION.md:268 and the PR body say "MD-02 applies the same reader to every embedded artifact byte". MD-02 has its own looser decoder (models.rs:541-594): it does not check the four-occurrence rule, binding order, or an octet both shared and inline, and it accepts a binding used twice (models.rs:606). It also decodes only banner and hiddenWeights (models.rs:664, 678) of the six *.bytes definitions in Recognizer.lean. Please reuse bytes::read_expression for every *.bytes definition, or correct the sentence.
-
Should-fix: SPEC.md:2740-2748 (binder hygiene) says the backend writes ByteArray and UInt8 "all without qualification". Byte literals now write root.ByteArray.mk and root.UInt8.ofNat (nat_lit n), and bind __byteN. One sentence would fix it: the spelling, plus why __byteN captures nothing (source names begin with a letter, and the scope holds only closed octets).
-
Should-fix, on #167: CHANGELOG Unreleased has no entry for the lowering or for the lean_backend moves (1.1 9 to 10, 1.2 19 to 20, c245450). It mentions #68 only in the fromOrdering.eq_1 entry.
-
Nit: VERIFICATION.md:286 (4096 bytes: 2.6 s vs 2.3 s) contradicts :296 (2.0 s under both), and :302 then calls the explicit form faster at 4096 on single runs. "By 16-byte steps" cannot produce 6394 and 6409, which are 15 apart: 6394 is the largest size tested that elaborates, and 6395-6408 were not tested.
-
Nit: the RED is a spelling RED only (VERIFICATION.md:271-277). If the reason for the change is that rooted names and nat_lit keep a literal's meaning independent of user names (language 1.1 has no binder-hygiene check), please say so in one line. A 1.1 fixture with a byte literal under a let named ByteArray or UInt8 would give a behavioral RED.
-
Nit: features/suites/semantic-ir.feature:136 is hard to parse, and "byte literals" reads wider than the change, since production/certificate.rs:819 and rust_term.rs:90 keep the old spelling. Suggested: "And the generated Lean writes every byte literal as explicit octets, binding an octet that occurs four or more times once, local to that literal, while the document shows the original decimal numbers and every byte in order".
Item 6 (PrismPM qualification) is the owner's adoption gate outside this repository and is not a merge gate.
This is a comment review now; formal approval will be given on #167's final head once OR-04 passes there.
…llow the data certificates; CHANGELOG names #68; no stale allow-list entry From the integration review on #167 (humuhumu33): - The SP-02 statement said a match on 420 constructors is not refused by the early bound; the bound refuses a 400-constructor match (the new `lowering-size-limit` fixture) and `FITTING_CONSTRUCTORS` is 240. The register, SPEC §31 and the scenario say 240; CONFORMANCE.md regenerated. - SPEC §17.17 said types are not shared and the chain is refused from 14 deep; with certificates A and B as kernel data the chain verifies 16 deep. It also said every cost is half of the greatest; certificate A's are the largest with five percent to spare (as `COSTS_A`'s comment states), B's and E's are half. VERIFICATION.md's chain figures are marked superseded with a pointer. - CHANGELOG gains #68's entry (lean_backend 1.1: 10, 1.2: 20, and the IDs that move); the widening and scaffolding entries no longer say language 1.1 is unchanged in a tree where #68 moves it; stale per-member register counts are dropped; the scaffolding entry says the renderer records effects and derives nothing (#105), as 0dedb4b made true. - The allow-list of Lean-looking literals had an entry for the developer printout removed in cde36cd; SP-17 requires every entry to match, and this one matched nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY
…e's current locals #68's byte-literal spelling moves Lean's LCNF of the text root, so the oracle crate it is compared with numbers its locals differently: the split limit is `_x_67` (was `_x_74`) and the equality test `_x_43` (was `_x_46`). Read from the oracle crate the corpus run builds on this tree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QppGKetUURseXowZun9KY
Purpose
A form change to the Lean spelling of modeled byte literals, with an independent oracle for it. It is not a performance or capacity fix: measurements are in
VERIFICATION.md("explicit byte-literal lowering can fail") and say so.What the lowering changes
_root_.UInt8.ofNat (nat_lit n)(all 256 values), inside_root_.ByteArray.mk #[...]; the empty array is_root_.ByteArray.mk #[].let __byteN, scoped to that literal; no outer generated local is captured.ByteArray.mk #[...]).crates/lexlean/src/backend/semantic.rschanges in the compiler.Tests
Measured (Lean 4.32.1, x86-64 Linux, one run per size, seeded-random bytes with all 256 values)
main's lowerer unchanged,conformance_sm_19fails at its first fixture (the empty array) because the reader rejects the old spelling. It is not a Lean or size failure; the 1024-byte corpus elaborates undermain's rendering at the default depth.maxRecDepth: the largest literal that elaborates is 6394 bytes under both renderings (6409 fails under both). Time at 4096 bytes: 2.0 s both; at 6394 bytes: 4.4 s (main) vs 3.3 s (explicit).maxRecDepth100000: 4096 bytes 3.0 s vs 2.1 s; 16384 bytes 12.7 s vs 11.3 s; 65536 bytes both fail on heartbeats (37.1 s vs 49.2 s).Status
mainonly. Generated outputs are not regenerated here; the maintainer's single sweep (with feat(semantic-ir): byte and fixed-width widening conversions in language 1.2 (SM-32, #114) #151) regenerates them, andcheck-goldenis expected to fail until then.lean_backendidentities that should advance: language 1.1 (9) and 1.2 (19). Language 1.0 does not move (it has no semantic modules; no committed output contains a byte literal). The bump is part of the sweep.just vv) runs in CI on the integrated tree after the sweep.🤖 Generated with Claude Code
https://claude.ai/code/session_014jPy3EVAUhMVS5f13tr9Ka