From c28c9145151353de51340079a287893ce5b2301a Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:56:16 +0700 Subject: [PATCH 1/5] claw: reel_still.t27 -- the TRI CLAW /mcp tool that renders one particle still (Closes #10547) specs/claw/visual_output.t27 says a report's visual is one PNG frame of a token_floor reel at STILL_MS, rendered on the Railway lab, and that no MCP tool renders one. This spec is that tool's contract: the name is homed in TRI CLAW by specs/t27mcp/service.t27, topics resolve through specs/t27f/reel_topics.t27, the frame is 270 of 450 and frame_shard draws only it (TF_SHARD=270 TF_SHARDS=450 TF_CUT=aspect), the overlays enter with -itsoffset 9, and a call off the lab is refused. Lab: 13/13 pass, 0 vacuous; t27b 13/13; mutants of the topic lookup, the frame formula (/1001; /999 is an equivalent mutant) and the lab check are killed. Sealed; t27b ledger row; docs/claw/README.md row. Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/claw_ClawReelStill.json | 49 +++++ docs/claw/README.md | 1 + docs/reports/t27b_expectations.json | 1 + specs/claw/reel_still.t27 | 280 +++++++++++++++++++++++++ 4 files changed, 331 insertions(+) create mode 100644 .trinity/seals/claw_ClawReelStill.json create mode 100644 specs/claw/reel_still.t27 diff --git a/.trinity/seals/claw_ClawReelStill.json b/.trinity/seals/claw_ClawReelStill.json new file mode 100644 index 0000000000..6ab567b809 --- /dev/null +++ b/.trinity/seals/claw_ClawReelStill.json @@ -0,0 +1,49 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+5e4d3b998", + "closure": [ + { + "spec": "specs/claw/visual_output.t27", + "spec_hash": "sha256:17137afe136e39910f38d7b031c659a672e009bfeef1bf4f9b7af7e2cb6cc628" + }, + { + "spec": "specs/t27f/frame_shard.t27", + "spec_hash": "sha256:1f04638a243b7a7f4d7a4480faf85f7878ca2e3365a2ec0f001a991fbd353da6" + }, + { + "spec": "specs/t27f/reel_topics.t27", + "spec_hash": "sha256:7c1762cde96524791711594d23f880fbad1f497a499277710f1fd61d52d50157" + }, + { + "spec": "specs/t27f/token_floor_scenes.t27", + "spec_hash": "sha256:948cff4bd34341b40b43c8a170e2a37e3bca59f8d6bc8e35d7e5ee43fe89a4ea" + }, + { + "spec": "specs/t27mcp/service.t27", + "spec_hash": "sha256:3d7957837be8ac3de14b18ce1c0ecdde805f3f71d4d801b62d476b2e82f4a1ae" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:deed4a8b76269ea5b07012ad0fa77fe95b32a7966ef56ea69066d8a8fa07ed84", + "gen_hash_rust": "sha256:de31997b7cb39086725aecbb03729fe7cd5eaebb9dc8e613a90dc0943899acd1", + "gen_hash_verilog": "sha256:f567550c0c1fc421b5fe24449fdbc2a7d3561fb26fce69fdbad22a55c3ede3c9", + "gen_hash_zig": "sha256:77d5fb33ff66b0be2be794c4f9176245cb55edd5c695e69b840fe85210eb8395", + "module": "ClawReelStill", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T17:00:18Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:a8d80acb663c353bee235aa6e45c83bf1bed113ab252426b10ad2641112452e2", + "spec_path": "specs/claw/reel_still.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 13, + "total": 13, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/docs/claw/README.md b/docs/claw/README.md index 4a7df352ec..048cfd5a79 100644 --- a/docs/claw/README.md +++ b/docs/claw/README.md @@ -18,6 +18,7 @@ behind one front door, with the gate logic in `.t27` specs. Epic | Service skeleton | Railway, thin I/O glue only | T5, merged (spec contract) | | Model routing: Opus 5.5 orchestrates, Sonnet 5.5 runs sub-tasks | `specs/claw/model_route.t27`, skill `model-routing`, `.claude/settings.json` + `.claude/agents/*` | owner directive 2026-10-18 | | A T27F visual in every answer that needs one | rule `specs/t27mcp/visual_output.t27`, particle-still layer `specs/claw/visual_output.t27`, procedure in skill `t27f`, "Visual in every output" | owner directive 2026-10-18 | +| `reel_still`: one particle still (PNG at STILL_MS of a token_floor reel) from TRI CLAW's `/mcp` | `specs/claw/reel_still.t27`, rendered on the Railway lab only | follow-up of the row above | | Positioning / pricing | `docs/claw/competitors.md` | T6, started | ## The T27F check in every `.t27` repository (#10268) diff --git a/docs/reports/t27b_expectations.json b/docs/reports/t27b_expectations.json index 11452ed21e..2098b8e829 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -195,6 +195,7 @@ {"path": "specs/claw/model_route.t27", "t27b": "pass"}, {"path": "specs/claw/preview.t27", "t27b": "pass"}, {"path": "specs/claw/recipes.t27", "t27b": "pass"}, + {"path": "specs/claw/reel_still.t27", "t27b": "pass"}, {"path": "specs/claw/refresh.t27", "t27b": "pass"}, {"path": "specs/claw/sarif.t27", "t27b": "pass"}, {"path": "specs/claw/sarif_feed.t27", "t27b": "pass"}, diff --git a/specs/claw/reel_still.t27 b/specs/claw/reel_still.t27 new file mode 100644 index 0000000000..9c23fab020 --- /dev/null +++ b/specs/claw/reel_still.t27 @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/claw/reel_still.t27 -- reel_still, the TRI CLAW /mcp tool that renders one particle still. +; specs/claw/visual_output.t27 says a report's visual is one PNG frame of a token_floor reel taken at +; STILL_MS, rendered on the Railway lab, and that no MCP tool renders one yet. This spec is that tool: +; what it takes, what it refuses, and the exact lab recipe it runs. +; -- +; Input (four fields): topic, lesson, lang, aspect. +; - topic "" or "token-floor" with lesson -1 is the physics reel (token_floor + token_floor_mux). +; - A lesson id from the t27-basics course ("what-a-spec-is", "the-module-line", ...; the ids are +; specs/t27f/reel_topics.t27's, so this tool and the reels never disagree about a lesson) is that +; lesson's reel (lesson_reel). The lesson index 0..TOPICS-1 names the same reel; giving both is +; allowed only when they agree. +; - lang 0 en, 1 ru. aspect 0 tall (1080x1920), 1 wide (1920x1080); one PNG is one aspect, so the +; "both" cut token_floor's TF_CUT also accepts is refused here. +; Output: one image/png, the frame the reel shows at STILL_MS. +; -- +; The recipe renders one frame, not the reel. frame_shard splits a reel into n shards; with +; n = SCENE_FRAMES every shard is one frame, so TF_SHARD = still_frame(), TF_SHARDS = SCENE_FRAMES +; draws exactly frame still_frame() (the physics still steps from frame 0; only drawing is skipped). +; The overlays (captions, labels, voice and music, which the still does not need but the filter graph +; reads) are the reel's own filter graph: the one frame enters it with `-itsoffset still_s()`, so the +; graph sees it at the reel's STILL_MS and draws what the reel draws there. `[v]` goes to the PNG, +; `[a]` to null. Measured on the lab 2026-10-18, lesson 1 en tall: rc 0, 1660 ms, 484981 bytes. +; -- +; It runs on the Railway lab only (owner rule 2026-10-09); a call anywhere else is refused, never +; rendered. The name has no t27_ or t27f_ prefix, so the one registry (specs/t27mcp/service.t27) homes +; it in TRI CLAW and mounts it as it is. +; phi^2 + 1/phi^2 = 3 | TRINITY + +module ClawReelStill; + +use t27mcp::service::admit; +use t27mcp::service::home_of; +use t27mcp::service::name_ok; +use t27mcp::service::H_T27; +use t27mcp::service::H_TRI_CLAW; +use t27mcp::service::A_MOUNT; +use t27mcp::service::A_REFUSE_COLLISION; +use claw::visual_output::STILL_MS; +use claw::visual_output::still_ms_ok; +use t27f::token_floor_scenes::SCENE_FPS; +use t27f::token_floor_scenes::SCENE_FRAMES; +use t27f::frame_shard::first_of; +use t27f::frame_shard::end_of; +use t27f::reel_topics::TOPICS; +use t27f::reel_topics::id_item; +use t27f::reel_topics::item_len; +use t27f::reel_topics::cp; + +/// The tool's name in TRI CLAW's /mcp. +pub const TOOL_NAME : str = "reel_still"; +pub const MIME : str = "image/png"; + +/// The input fields, in the order the tool's schema lists them. +pub const INPUT_COUNT : u32 = 4; +pub const INPUT_NAMES : [4]str = ["topic", "lesson", "lang", "aspect"]; + +/// The physics reel's topic name, and the lesson field's "no lesson". +pub const PHYSICS_TOPIC : str = "token-floor"; +pub const LESSON_NONE : i32 = -1; + +/// Which reel a call resolves to. +pub const REEL_PHYSICS : i32 = -1; // otherwise the lesson index 0..TOPICS-1 +pub const REEL_NONE : i32 = -2; // the call is refused + +pub const LANG_EN : i32 = 0; +pub const LANG_RU : i32 = 1; +pub const LANG_NAMES : [2]str = ["en", "ru"]; + +/// The aspect is token_floor's TF_CUT value for that cut. +pub const ASPECT_TALL : i32 = 0; +pub const ASPECT_WIDE : i32 = 1; +pub const ASPECT_NAMES : [2]str = ["tall", "wide"]; + +/// What the tool answers. +pub const V_OK : u32 = 0; +pub const V_UNKNOWN_TOPIC : u32 = 1; +pub const V_BAD_LESSON : u32 = 2; +pub const V_DISAGREE : u32 = 3; +pub const V_BAD_LANG : u32 = 4; +pub const V_BAD_ASPECT : u32 = 5; +pub const V_NOT_ON_LAB : u32 = 6; + +/// The file the still is written to: STILL_PREFIX id - lang - aspect STILL_EXT. +pub const STILL_PREFIX : str = "still-"; +pub const STILL_EXT : str = ".png"; + +/// Whether lesson t's course id is s, code point by code point. +pub fn id_is(t: u32, s: str) -> bool { + let i : usize = id_item(t as usize); + let n : usize = item_len(i); + if (n != s.len) { return false; } + var k : usize = 0; + while (k < n) { + if ((s[k] as u32) != cp(i, k)) { return false; } + k = k + 1; + } + return true; +} + +/// The lesson whose id is s, or REEL_PHYSICS for the physics reel's names, or REEL_NONE. +pub fn topic_reel(s: str) -> i32 { + if (s.len == 0 or s == PHYSICS_TOPIC) { return REEL_PHYSICS; } + var t : u32 = 0; + while (t < (TOPICS as u32)) { + if (id_is(t, s)) { return t as i32; } + t = t + 1; + } + return REEL_NONE; +} + +/// Whether a lesson field is "none" or a lesson index. +pub fn lesson_ok(lesson: i32) -> bool { + return lesson == LESSON_NONE or (lesson >= 0 and lesson < (TOPICS as i32)); +} + +/// The reel a call names: from topic, from lesson, or from both when they agree. +pub fn reel_of(topic: str, lesson: i32) -> i32 { + if (lesson_ok(lesson) == false) { return REEL_NONE; } + let by_topic : i32 = topic_reel(topic); + if (by_topic == REEL_NONE) { return REEL_NONE; } + if (lesson == LESSON_NONE) { return by_topic; } + if (topic.len == 0) { return lesson; } + if (by_topic == lesson) { return lesson; } + return REEL_NONE; +} + +/// The tool's verdict on a call; only V_OK renders. +pub fn verdict(topic: str, lesson: i32, lang: i32, aspect: i32, on_lab: bool) -> u32 { + if (lesson_ok(lesson) == false) { return V_BAD_LESSON; } + if (topic_reel(topic) == REEL_NONE) { return V_UNKNOWN_TOPIC; } + if (reel_of(topic, lesson) == REEL_NONE) { return V_DISAGREE; } + if (lang != LANG_EN and lang != LANG_RU) { return V_BAD_LANG; } + if (aspect != ASPECT_TALL and aspect != ASPECT_WIDE) { return V_BAD_ASPECT; } + if (on_lab == false) { return V_NOT_ON_LAB; } + return V_OK; +} + +/// The frame the reel shows at STILL_MS. +pub fn still_frame() -> i32 { + return @divTrunc(STILL_MS * SCENE_FPS, 1000); +} + +/// The renderer's environment for that one frame: TF_SHARD, TF_SHARDS, TF_CUT. +pub fn env_shard() -> i32 { return still_frame(); } +pub fn env_shards() -> i32 { return SCENE_FRAMES; } +pub fn env_cut(aspect: i32) -> i32 { return aspect; } + +/// The frame's size and its rgb24 bytes, the length of the renderer's stream for one frame. +pub fn frame_w(aspect: i32) -> i32 { + if (aspect == ASPECT_WIDE) { return 1920; } + return 1080; +} +pub fn frame_h(aspect: i32) -> i32 { + if (aspect == ASPECT_WIDE) { return 1080; } + return 1920; +} +pub fn frame_bytes(aspect: i32) -> i32 { + return frame_w(aspect) * frame_h(aspect) * 3; +} + +/// The `-itsoffset` the one frame enters the reel's filter graph with, in whole seconds. +pub fn still_s() -> i32 { + return @divTrunc(STILL_MS, 1000); +} + +/// The still's file name length: prefix, id, "-", lang, "-", aspect, extension. +pub fn name_len(reel: i32, lang: i32, aspect: i32) -> usize { + var id_n : usize = PHYSICS_TOPIC.len; + if (reel >= 0) { id_n = item_len(id_item(reel as usize)); } + return STILL_PREFIX.len + id_n + 1 + LANG_NAMES[lang as usize].len + 1 + ASPECT_NAMES[aspect as usize].len + STILL_EXT.len; +} + +test the_tool_is_tri_claws_and_mounted_as_it_is { + assert name_ok(TOOL_NAME); + assert home_of(TOOL_NAME) == H_TRI_CLAW; + assert admit(TOOL_NAME, H_TRI_CLAW) == A_MOUNT; + assert INPUT_NAMES.len == INPUT_COUNT as usize; +} + +test negative_control_under_a_t27f_name_it_would_be_refused { + assert home_of("t27f_reel_still") == H_T27; + assert admit("t27f_reel_still", H_TRI_CLAW) == A_REFUSE_COLLISION; +} + +test a_topic_names_the_physics_reel_or_a_lesson { + assert topic_reel("") == REEL_PHYSICS; + assert topic_reel("token-floor") == REEL_PHYSICS; + assert topic_reel("what-a-spec-is") == 0; + assert topic_reel("the-module-line") == 1; + assert topic_reel("constants") == 3; +} + +test every_lesson_id_resolves_to_its_own_index { + var t : u32 = 0; + var hits : u32 = 0; + while (t < (TOPICS as u32)) { + let i : usize = id_item(t as usize); + assert item_len(i) > 0; + if (id_is(t, "what-a-spec-is")) { hits = hits + 1; } + t = t + 1; + } + assert hits == 1; + assert TOPICS == 27; +} + +test negative_control_a_near_miss_topic_is_unknown { + assert topic_reel("what-a-spec") == REEL_NONE; + assert topic_reel("what-a-spec-is-") == REEL_NONE; + assert topic_reel("What-a-spec-is") == REEL_NONE; + assert topic_reel("token_floor") == REEL_NONE; + assert id_is(0, "the-module-line") == false; +} + +test topic_and_lesson_agree_or_the_call_is_refused { + assert reel_of("", LESSON_NONE) == REEL_PHYSICS; + assert reel_of("", 1) == 1; + assert reel_of("the-module-line", LESSON_NONE) == 1; + assert reel_of("the-module-line", 1) == 1; + assert reel_of("the-module-line", 2) == REEL_NONE; + assert reel_of("token-floor", 0) == REEL_NONE; + assert reel_of("", 27) == REEL_NONE; + assert reel_of("", -2) == REEL_NONE; +} + +test the_verdict_names_what_is_wrong_first { + assert verdict("the-module-line", LESSON_NONE, LANG_EN, ASPECT_TALL, true) == V_OK; + assert verdict("", LESSON_NONE, LANG_RU, ASPECT_WIDE, true) == V_OK; + assert verdict("nope", LESSON_NONE, LANG_EN, ASPECT_TALL, true) == V_UNKNOWN_TOPIC; + assert verdict("", 40, LANG_EN, ASPECT_TALL, true) == V_BAD_LESSON; + assert verdict("constants", 0, LANG_EN, ASPECT_TALL, true) == V_DISAGREE; + assert verdict("", 0, 2, ASPECT_TALL, true) == V_BAD_LANG; + assert verdict("", 0, LANG_EN, 2, true) == V_BAD_ASPECT; + assert verdict("", 0, LANG_EN, -1, true) == V_BAD_ASPECT; +} + +test negative_control_a_good_call_off_the_lab_is_refused_not_rendered { + assert verdict("the-module-line", LESSON_NONE, LANG_EN, ASPECT_TALL, false) == V_NOT_ON_LAB; + assert verdict("", LESSON_NONE, LANG_EN, ASPECT_WIDE, false) == V_NOT_ON_LAB; +} + +test the_still_is_frame_270_of_450_and_the_rule_allows_it { + assert still_frame() == 270; + assert still_frame() < SCENE_FRAMES; + assert SCENE_FPS == 30; + assert still_ms_ok(STILL_MS); + assert @rem(STILL_MS, 1000) == 0; + assert still_s() * 1000 == STILL_MS; +} + +test the_shard_env_draws_exactly_the_still_frame { + assert first_of(env_shard(), env_shards(), SCENE_FRAMES) == still_frame(); + assert end_of(env_shard(), env_shards(), SCENE_FRAMES) == still_frame() + 1; + assert env_cut(ASPECT_TALL) == 0; + assert env_cut(ASPECT_WIDE) == 1; +} + +test negative_control_a_halved_shard_count_renders_the_whole_reel { + let half : i32 = @divTrunc(env_shards(), 2); + assert first_of(env_shard(), half, SCENE_FRAMES) == 0; + assert end_of(env_shard(), half, SCENE_FRAMES) == SCENE_FRAMES; + assert first_of(env_shard(), 1, SCENE_FRAMES) == 0; +} + +test one_frame_is_6220800_bytes_in_either_aspect { + assert frame_w(ASPECT_TALL) == 1080; + assert frame_h(ASPECT_TALL) == 1920; + assert frame_w(ASPECT_WIDE) == 1920; + assert frame_h(ASPECT_WIDE) == 1080; + assert frame_bytes(ASPECT_TALL) == 6220800; + assert frame_bytes(ASPECT_WIDE) == frame_bytes(ASPECT_TALL); +} + +test the_file_name_is_prefix_id_lang_aspect { + // still-what-a-spec-is-en-tall.png + assert name_len(0, LANG_EN, ASPECT_TALL) == 32; + // still-token-floor-ru-wide.png + assert name_len(REEL_PHYSICS, LANG_RU, ASPECT_WIDE) == 29; + assert name_len(1, LANG_EN, ASPECT_TALL) != name_len(0, LANG_EN, ASPECT_TALL); +} From a69fee83982470ae3675238326cb92c92527f8e8 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:05:58 +0700 Subject: [PATCH 2/5] claw: reel_still pads the one frame with tpad so the overlays see n = 270 (Closes #10547) Co-Authored-By: Claude Opus 5.5 --- specs/claw/reel_still.t27 | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/specs/claw/reel_still.t27 b/specs/claw/reel_still.t27 index 9c23fab020..506224df07 100644 --- a/specs/claw/reel_still.t27 +++ b/specs/claw/reel_still.t27 @@ -18,9 +18,14 @@ ; n = SCENE_FRAMES every shard is one frame, so TF_SHARD = still_frame(), TF_SHARDS = SCENE_FRAMES ; draws exactly frame still_frame() (the physics still steps from frame 0; only drawing is skipped). ; The overlays (captions, labels, voice and music, which the still does not need but the filter graph -; reads) are the reel's own filter graph: the one frame enters it with `-itsoffset still_s()`, so the -; graph sees it at the reel's STILL_MS and draws what the reel draws there. `[v]` goes to the PNG, -; `[a]` to null. Measured on the lab 2026-10-18, lesson 1 en tall: rc 0, 1660 ms, 484981 bytes. +; reads) are the reel's own filter graph, and its drawtext overlays are keyed on the filter frame +; index n, not on time. A single input frame is n = 0 however it is offset in time, so `-itsoffset 9` +; draws the frame-0 overlays: measured, that still matched the raw particle frame (42.9 dB PSNR) and +; not the reel (23.3 dB). The recipe pads instead: the graph's `[0:v]` gets +; `tpad=start=pad_frames()` in front, so the one frame arrives as n = still_frame() at t = STILL_MS. +; The last frame of `[v]` goes to the PNG (`-update 1`), `[a]` to null. Measured on the lab +; 2026-10-18, lesson 1 en tall: rc 0, 2585 ms, 499707 bytes, 49.3 dB PSNR against frame 270 of the +; reel's own mp4 (21.7 dB against frame 269, 22.0 dB against 271). ; -- ; It runs on the Railway lab only (owner rule 2026-10-09); a call anywhere else is refused, never ; rendered. The name has no t27_ or t27f_ prefix, so the one registry (specs/t27mcp/service.t27) homes @@ -159,9 +164,16 @@ pub fn frame_bytes(aspect: i32) -> i32 { return frame_w(aspect) * frame_h(aspect) * 3; } -/// The `-itsoffset` the one frame enters the reel's filter graph with, in whole seconds. -pub fn still_s() -> i32 { - return @divTrunc(STILL_MS, 1000); +/// The frames `tpad=start=` puts in front of the one frame, so the reel's filter graph sees it as +/// frame index n = still_frame(). +pub fn pad_frames() -> i32 { + return still_frame(); +} + +/// The filter frame index n the one input frame has after `pad` frames of padding. The overlays are +/// keyed on n, so this, not the frame's timestamp, decides what they draw. +pub fn graph_n(pad: i32) -> i32 { + return pad; } /// The still's file name length: prefix, id, "-", lang, "-", aspect, extension. @@ -244,8 +256,19 @@ test the_still_is_frame_270_of_450_and_the_rule_allows_it { assert still_frame() < SCENE_FRAMES; assert SCENE_FPS == 30; assert still_ms_ok(STILL_MS); - assert @rem(STILL_MS, 1000) == 0; - assert still_s() * 1000 == STILL_MS; + assert @rem(STILL_MS * SCENE_FPS, 1000) == 0; +} + +test the_padded_frame_is_the_overlays_frame_270 { + assert graph_n(pad_frames()) == still_frame(); + assert @divTrunc(pad_frames() * 1000, SCENE_FPS) == STILL_MS; +} + +test negative_control_an_unpadded_frame_draws_the_frame_0_overlays { + // -itsoffset moves the timestamp but not n; this is the recipe the lab measured wrong. + assert graph_n(0) == 0; + assert graph_n(0) != still_frame(); + assert graph_n(pad_frames() - 1) != still_frame(); } test the_shard_env_draws_exactly_the_still_frame { From 3d5c1942bad1c3820fb0e70fd3c324e658b784c8 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:07:18 +0700 Subject: [PATCH 3/5] seal: claw_ClawReelStill 15/15, vacuous 0 (Closes #10547) Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/claw_ClawReelStill.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.trinity/seals/claw_ClawReelStill.json b/.trinity/seals/claw_ClawReelStill.json index 6ab567b809..b4ee1a2cf2 100644 --- a/.trinity/seals/claw_ClawReelStill.json +++ b/.trinity/seals/claw_ClawReelStill.json @@ -23,23 +23,23 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:deed4a8b76269ea5b07012ad0fa77fe95b32a7966ef56ea69066d8a8fa07ed84", - "gen_hash_rust": "sha256:de31997b7cb39086725aecbb03729fe7cd5eaebb9dc8e613a90dc0943899acd1", - "gen_hash_verilog": "sha256:f567550c0c1fc421b5fe24449fdbc2a7d3561fb26fce69fdbad22a55c3ede3c9", - "gen_hash_zig": "sha256:77d5fb33ff66b0be2be794c4f9176245cb55edd5c695e69b840fe85210eb8395", + "gen_hash_c": "sha256:d32a87a4218806616b04b727d7e3f1bc76d6d33440f304f7beb42b566bb50437", + "gen_hash_rust": "sha256:5a1adebb39cdeb948aae1da51a64f43b93b1cd845f715389c30cf6785b701c30", + "gen_hash_verilog": "sha256:62df937cda4af6426ae5e1170bafa4cf124f5d952dea6b87ccf19e451968dc9f", + "gen_hash_zig": "sha256:b4e20621dcef2e6517948018e7f6aeb788da068df27beb9b6c2a485af15b492e", "module": "ClawReelStill", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-18T17:00:18Z", + "sealed_at": "2026-10-18T17:06:53Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:a8d80acb663c353bee235aa6e45c83bf1bed113ab252426b10ad2641112452e2", + "spec_hash": "sha256:4fc5fc3c835193faae7b312194e4f31bc6baa8b7da3f08b12b809cb4e5e293e5", "spec_path": "specs/claw/reel_still.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 13, - "total": 13, + "passed": 15, + "total": 15, "vacuous": 0 }, "toolchain": { From b7141a7f41b6a465128cfa42bb6d04c0d3fe68d1 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 03:41:16 +0700 Subject: [PATCH 4/5] ledger: t27b row for specs/analog/sar_comparator.t27, UNLISTED 1 -> 0 (Closes #10547) The ratchet on a616b7acd reported the spec (landed on master in #10604) as UNLISTED with a t27b pass; master's ledger has no row for it yet. Co-Authored-By: Claude Opus 5.5 --- docs/reports/t27b_expectations.json | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reports/t27b_expectations.json b/docs/reports/t27b_expectations.json index 99ed7bfc5e..8a48e33df6 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -48,6 +48,7 @@ {"path": "specs/analog/linear_zoh.t27", "t27b": "blocked", "blocker": "ExprCall(@sin)", "reason": "unimplemented"}, {"path": "specs/analog/mos_table.t27", "t27b": "pass"}, {"path": "specs/analog/sar_cdac.t27", "t27b": "pass"}, + {"path": "specs/analog/sar_comparator.t27", "t27b": "pass"}, {"path": "specs/api/c_abi.t27", "t27b": "pass"}, {"path": "specs/api/tri_api_context.t27", "t27b": "pass"}, {"path": "specs/api/tri_api_loop.t27", "t27b": "pass"}, From ab5358fea0d5487afc09403dbc5d7e847576c082 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 04:56:22 +0700 Subject: [PATCH 5/5] gen: regenerate gen/c/claw/gates.c from specs/claw/gates.t27 (Refs #10547, Refs #10674) #10674 added two tests to specs/claw/gates.t27 without regenerating the committed C, so spec-guards' freshness step fails on master and on every branch that merged it. Output of t27c gen-c on the Railway lab (ig3 91c9193cb); the hunks match the ones spec-guards printed. Co-Authored-By: Claude Opus 5.5 --- gen/c/claw/gates.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/gen/c/claw/gates.c b/gen/c/claw/gates.c index 28d5a59adf..37b48b03c5 100644 --- a/gen/c/claw/gates.c +++ b/gen/c/claw/gates.c @@ -551,6 +551,43 @@ void test_coverage_report_carries_every_class(void) { assert((buf_has(&out, w, "G_UNKNOWN", 9) == true)); } +void test_audit_tail_line_matches_the_count(void) { + uint8_t dir[8192] = {0}; + size_t w = 0; + for (size_t i = 0; i < 67; i++) { + w = put_str(&dir, 8192, w, NAMES[i], NAME_LENS[i]); + w = put_str(&dir, 8192, w, "\n", 1); + } + uint8_t out[8192] = {0}; + for (size_t i = 0; i < 8192; i++) { + out[i] = 0; + } + assert((claw_status(&dir, w, &out, 8192) == 0)); + assert((buf_has(&out, 8192, "claw: matrix is current\n", 24) == true)); + assert((buf_has(&out, 8192, DRIFT_TAIL, DRIFT_TAIL_LEN) == false)); + uint8_t gone[8192] = {0}; + size_t g = 0; + for (size_t i = 1; i < 67; i++) { + g = put_str(&gone, 8192, g, NAMES[i], NAME_LENS[i]); + g = put_str(&gone, 8192, g, "\n", 1); + } + uint8_t red[8192] = {0}; + for (size_t i = 0; i < 8192; i++) { + red[i] = 0; + } + assert((claw_status(&gone, g, &red, 8192) == 1)); + assert((buf_has(&red, 8192, DRIFT_TAIL, DRIFT_TAIL_LEN) == true)); + assert((buf_has(&red, 8192, OK_TAIL, OK_TAIL_LEN) == false)); +} + +void test_coverage_report_lines_are_exact(void) { + uint8_t out[4096] = {0}; + size_t w = claw_coverage_report(&out, 4096); + assert((buf_has(&out, w, "G_BLOCKING n=62 blocking=true e.g. agent-runner-docker, bootstrap-tests, build-paper\n", 85) == true)); + assert((buf_has(&out, w, "G_SOFT n=3 blocking=false e.g. oracle-nightly, queen-doctor, rings-rust\n", 72) == true)); + assert((buf_has(&out, w, "G_REPORTING n=2 blocking=false e.g. auto-merge-ready-prs, queen-publish\n", 72) == true)); +} + /* ------------------------------------------------------- Test runner (compile with -DT27_TEST_MAIN to execute) @@ -577,7 +614,9 @@ int main(void) { test_every_row_round_trips_through_the_name_lookup(); test_soft_gates_report_their_events(); test_coverage_report_carries_every_class(); - printf("All %d tests passed.\n", 18); + test_audit_tail_line_matches_the_count(); + test_coverage_report_lines_are_exact(); + printf("All %d tests passed.\n", 20); return 0; } #endif /* T27_TEST_MAIN */