diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index 150e47e134..ca9aa3f621 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -416,6 +416,19 @@ card's `PRESETS`; its lab check compares that list to `PRESET_NAMES` byte for by This is Remotion's `random(seed)` applied to style. Any other `PRESET` value is used as given (gHashTag/t27#10803). Test hashes against the published FNV vectors (`""`, `a`, `b`, `foobar`), never against a value the spec computes itself. +- **Prove AUTO on the compiled binary, not only in the interpreter.** For each idea, build it + twice on the lab: once with `PRESET = PRESET_AUTO` and once with the expected preset written in. + md5 the two frame streams (`./f 2>&1 1>fo.txt | md5sum`). They must be SAME, and the idea with a + wrong preset must be DIFF (the control). Then gen and the interpreter agree, and you need no image + analysis: noir, trit and rain backgrounds differ by a few levels, so a colour check is fragile. + The batch in the spec's test (#10815) is five ideas that cover all five presets; render it as the + batch preview. **To find an idea's preset without a print:** a scratch spec with + `assert((preset_of(X) & b) == b)` for b = 1, 2, 4 reads the value off which tests pass. + Build the variants in parallel with `&` and `wait`: 11 builds and renders take about as long as one. + **Trap: never `tee` the frame stream into md5 and ffmpeg at once while several encoders run.** + Five parallel libx264 encoders on the lab failed with "Error while opening encoder", the + pipe closed, and md5 hashed a truncated stream: 3 of 5 read DIFF. Run md5 separately, then + encode one at a time. A DIFF that coincides with an encoder error is the harness, not the code. **Keep it FPGA-shaped.** Use Q8 fixed point. The per-step and per-pixel paths use only add, multiply, compare, table lookup (`kt` kernel ROM, `tt` tone ROM) and power-of-two division. diff --git a/.trinity/seals/t27f_idea_factory.json b/.trinity/seals/t27f_idea_factory.json index 90cd33d12e..f6d9cd564a 100644 --- a/.trinity/seals/t27f_idea_factory.json +++ b/.trinity/seals/t27f_idea_factory.json @@ -15,23 +15,23 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:ddc41e93c87c1268b2d075c6b34fba3208ac77bc2db7992ee9430b219f3aa2f1", - "gen_hash_rust": "sha256:dfb079933e8ffe3343e2360a23e71f9a92bc7c27b20a2e11c6659f95e1562c63", - "gen_hash_verilog": "sha256:029af4d7206071497f23fd5b12d15eb47df379d6f508d2f9a192edfb12337578", - "gen_hash_zig": "sha256:27984b39231077b1f334e7d6fe2f2249667ffb6838f0bf21f4b8e38861e98fd7", + "gen_hash_c": "sha256:bb1ef6081add1e9fa249288e6ebd223bc66be7f13d91210eed6dac48ed4a01aa", + "gen_hash_rust": "sha256:2420620e8b22b844cf0912ec4a21d7358a0045cec3508d8a14c6d8206f169ccb", + "gen_hash_verilog": "sha256:8f8cd1625c7f3d516bc5e597c4860b81f2a4860ce6d6f3cb4b06c2578568a49d", + "gen_hash_zig": "sha256:b4136a42488a6715a58f8a2e2e482871209c94a0009a78cab7a1f357db42c0d2", "module": "idea_factory", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-19T06:20:13Z", + "sealed_at": "2026-10-19T07:20:44Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:26ab3c6cae74c0c62124efb321098e184703f4b05f1e53fc902fa209dd036768", + "spec_hash": "sha256:a68fbc93ea94b32e264ae91b82b149eb7530c3af4e2787c8b457a2eeec0c3482", "spec_path": "specs/t27f/idea_factory.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 13, - "total": 13, + "passed": 14, + "total": 14, "vacuous": 0 }, "toolchain": { diff --git a/specs/t27f/idea_factory.t27 b/specs/t27f/idea_factory.t27 index ca8b8f6ab8..9ce8b39d95 100644 --- a/specs/t27f/idea_factory.t27 +++ b/specs/t27f/idea_factory.t27 @@ -50,6 +50,11 @@ use t27f::scene_raster::green; use t27f::scene_raster::blue; use t27f::particle_ds::ONE; use t27f::particle_ds::PRESETS; +use t27f::particle_ds::P_NOIR; +use t27f::particle_ds::P_NEON; +use t27f::particle_ds::P_TRIT; +use t27f::particle_ds::P_PAPER; +use t27f::particle_ds::P_RAIN; use t27f::particle_ds::BG; use t27f::particle_ds::KEY_COL; use t27f::particle_ds::GRAIN; @@ -704,3 +709,15 @@ test "the 26 one-letter ideas A to Z between them pick every preset" { assert(hit[4] > 0); assert(hit[0] + hit[1] + hit[2] + hit[3] + hit[4] == 26); } + +// ---- a batch: five ideas whose AUTO presets cover all five (gHashTag/t27#10815) ---- +// The lab built each idea twice, once with PRESET = PRESET_AUTO and once with the preset pinned +// here, and the two binaries' frame streams were byte-identical (md5), so the generated code +// picks what the interpreter picks. Idea 1 with preset 1 gave a different stream (the control). +test "a batch of five ideas covers all five presets under PRESET_AUTO" { + assert(preset_of("SPEC IS THE SOURCE|EVERY VIEW DERIVED") == P_NOIR); + assert(preset_of("ONE LAW|MANY SURFACES") == P_NEON); + assert(preset_of("THREE STATES|BEAT TWO") == P_TRIT); + assert(preset_of("THE FPGA RUNS|THE SPEC") == P_PAPER); + assert(preset_of("SEALED|EVERY HASH") == P_RAIN); +}