From d6f9478d69918eedc6affc1143d44f0dc773a702 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 22:32:10 +0700 Subject: [PATCH 01/11] spec(t27mcp): visual_output.t27 -- every answer carries a T27F visual, by host, readable or redrawn One rule for the t27 MCP server's instructions and TRI CLAW's chat prompt: needs_visual, answer_channel (desktop inline widget, TRI CLAW image URL, markdown table fallback), inline_readable (font * 680 >= 11 * width), inline_source (embed or redraw from t27f_outline), answer_verdict. Lab: t27c test-report 9/9, 0 vacuous; a mutant readability rule fails 3. Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/t27mcp_T27mcpVisualOutput.json | 28 ++ specs/t27mcp/visual_output.t27 | 243 ++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 .trinity/seals/t27mcp_T27mcpVisualOutput.json create mode 100644 specs/t27mcp/visual_output.t27 diff --git a/.trinity/seals/t27mcp_T27mcpVisualOutput.json b/.trinity/seals/t27mcp_T27mcpVisualOutput.json new file mode 100644 index 0000000000..53bca11e6d --- /dev/null +++ b/.trinity/seals/t27mcp_T27mcpVisualOutput.json @@ -0,0 +1,28 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9448ab4be", + "closure": [], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:076a0683dcc4e8487922bd6ff561422a1dfa707069e639fffaafea9d70ad8e2d", + "gen_hash_rust": "sha256:6267998500edaecfe3378c6ff7ed7482d1b0c239e1b8480fa697a8fd05b0d7b8", + "gen_hash_verilog": "sha256:241e62e3030919b4f540ff38480f8d726a4cc8301fbc30443369e7978adbbb1b", + "gen_hash_zig": "sha256:e7446390463513c4496f484f375ef59ae2f260172c8e46326f21008d84860411", + "module": "T27mcpVisualOutput", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T15:31:37Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:06c1c5e73142e2f79fa5d7be037eace63c1f20597a6e33274ebf8e1b428b7584", + "spec_path": "specs/t27mcp/visual_output.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 9, + "total": 9, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/specs/t27mcp/visual_output.t27 b/specs/t27mcp/visual_output.t27 new file mode 100644 index 0000000000..95a2fd98a1 --- /dev/null +++ b/specs/t27mcp/visual_output.t27 @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/t27mcp/visual_output.t27 -- every answer about a spec, a flow, numbers or a piece of work carries +; one visual, and the visual is the T27F way: drawn from tool rows, labelled, with the file it came from. +; Where it is drawn depends on the host. The rule is said to Claude Code through the MCP server's +; `instructions` (gHashTag/t27-mcp) and to TRI CLAW's chat agent through its prompt +; (gHashTag/999-multibots-telegraf, apps/vibee-editor/render): both read RULE_* from this spec, so the rule +; has one home. See the epic #10066 and T27F, gHashTag/trinity#1648. +; -- +; What was measured (2026-10-18, t27-mcp db98153): +; - t27f_graph of the reel fixture: an SVG 1860 wide, text at 13 px, 5923 bytes. Shown inline at 680 px it +; scales to 0.37, so its text is about 4.75 px: unreadable. t27f_view deck-evidence-wide: 1280 wide, body +; text 26 px (13.8 px inline, readable), a caption at 15 px (8 px inline, not readable). +; - The Claude Code desktop app draws an inline SVG or HTML visual with its visual tool (show_widget), at a +; container 680 wide, text at least 11 px. The CLI draws no image; it renders markdown tables. +; - An MCP server's `instructions` (the initialize result) reach the client model's system prompt; a tool +; result does not reach the user as an image on these hosts (reel.t27 header, 2026-10-17). +; - TRI CLAW's chat shows an image for an https URL ending in .svg on its own line or for ![title](url) +; (player/src/components/Chat/ChatAssets.tsx IMAGE_RE). The t27f tools write their SVG to the server's +; temporary directory, so TRI CLAW serves that directory by URL. +; -- +; Hosts 0..3 carry the numbers of reel.t27's HOST_*, and channels 0..3 its CHANNEL_*; this spec adds TRI +; CLAW, the inline widget, the image URL and the markdown table. reel.t27 channel_for() stays the channel +; of a reel still; answer_channel() here is the channel of an answer's visual. +; Readability: a drawing of width W shown at INLINE_W shows a font of F px at F * INLINE_W / W px, so it is +; readable when F * INLINE_W >= MIN_FONT_PX * W for its smallest text. A tool SVG is embedded as it is only +; when readable and at most INLINE_MAX_BYTES (the model re-emits it, so its bytes are output); otherwise it +; is redrawn at INLINE_W from t27f_outline rows. +; phi^2 + 1/phi^2 = 3 | TRINITY + +module T27mcpVisualOutput; + +/// Hosts. 0..3 are reel.t27's numbers. +pub const HOST_CLAUDE_CODE_CLI : u32 = 0; +pub const HOST_CLAUDE_CODE_DESKTOP : u32 = 1; +pub const HOST_MCP_APPS : u32 = 2; +pub const HOST_SITE : u32 = 3; +pub const HOST_TRI_CLAW : u32 = 4; +pub const HOST_COUNT : u32 = 5; + +/// Channels. 0..3 are reel.t27's numbers. +pub const CH_FILE_PATH : u32 = 0; +pub const CH_FILE_AND_PANE : u32 = 1; +pub const CH_UI_RESOURCE : u32 = 2; +pub const CH_LIVE_PLAYER : u32 = 3; +pub const CH_INLINE_WIDGET : u32 = 4; +pub const CH_IMAGE_URL : u32 = 5; +pub const CH_MARKDOWN_TABLE : u32 = 6; +pub const CHANNEL_NAME : [7]str = [ + "file path", + "file and pane", + "ui resource", + "live player", + "inline widget", + "image url", + "markdown table" +]; + +/// Answer kinds. The first four carry a visual. +pub const K_SPEC : u32 = 0; +pub const K_FLOW : u32 = 1; +pub const K_NUMBERS : u32 = 2; +pub const K_REPORT : u32 = 3; +pub const K_ONE_SENTENCE : u32 = 4; +pub const K_QUESTION : u32 = 5; + +/// The inline container and the smallest text it may show. +pub const INLINE_W : u32 = 680; +pub const MIN_FONT_PX : u32 = 11; +pub const INLINE_MAX_BYTES : u32 = 16384; + +/// Where a tool SVG's drawing comes from. +pub const SRC_EMBED : u32 = 0; +pub const SRC_REDRAW : u32 = 1; + +/// The T27F labels, as t27f_outline gives them. +pub const LABEL_NAMES : [4]str = ["exact", "derived", "suggested", "unknown"]; + +/// answer_verdict() answers. +pub const V_OK : u32 = 0; +pub const V_NO_VISUAL : u32 = 1; +pub const V_INVENTED : u32 = 2; +pub const V_NO_LEGEND : u32 = 3; +pub const V_NO_SOURCE : u32 = 4; +pub const V_UNREADABLE : u32 = 5; +pub const VERDICT_TEXT : [6]str = [ + "ok", + "no visual: this answer needs one", + "invented: a node no tool row backs", + "no legend: labels drawn without their key", + "no source: the file or URL the drawing came from is not given", + "unreadable: its smallest text is under 11 px where it is shown" +]; + +/// The rule as Claude Code reads it, from the t27 MCP server's `instructions`. ASCII, one line each. +pub const RULE_CLAUDE_CODE : [7]str = [ + "Visual output (specs/t27mcp/visual_output.t27):", + "- Every answer that explains a spec, a flow, numbers or a piece of work carries one visual. Only a one-sentence reply or a question back goes without.", + "- In the Claude Code desktop app, draw it inline with your visual tool (show_widget) when you have one; else give the SVG path, which the app opens. In the CLI, give the path, or a markdown table when there is no SVG.", + "- Draw from tool rows, never from memory: t27f_outline, t27f_graph, t27f_view, t27_spec. Nothing is drawn that a row does not back.", + "- Label every node exact, derived, suggested or unknown as its row says, and show the legend.", + "- Embed a tool SVG as it is only when its smallest font_px * 680 >= 11 * its width and it is at most 16384 bytes; else redraw it 680 wide from t27f_outline rows.", + "- Always name the file the drawing came from: the file is the record, the drawing is a view of it." +]; + +/// The rule as TRI CLAW's chat agent reads it, from its prompt. ASCII, one line each. +pub const RULE_TRI_CLAW : [6]str = [ + "Visual output (specs/t27mcp/visual_output.t27):", + "- Every answer that explains a spec, a flow, numbers or a piece of work carries one visual. Only a one-sentence reply or a question back goes without.", + "- When a t27f tool answered, show its drawing as an image: its https URL ending in .svg on a line of its own, or ![title](url). Never paste SVG source into the chat.", + "- With no drawing, show the rows as a markdown table, not as prose.", + "- Draw from tool rows, never from memory. Label every item exact, derived, suggested or unknown as its row says, and give the legend.", + "- Name where the drawing came from: the tool and its file or URL." +]; +pub const RULE_CLAUDE_CODE_LINES : u32 = 7; +pub const RULE_TRI_CLAW_LINES : u32 = 6; + +/// Whether an answer of kind `kind` carries a visual. +pub fn needs_visual(kind: u32) -> bool { + return kind <= K_REPORT; +} + +/// How an answer's visual reaches the user on `host`. `inline_tool`: the client has a visual tool +/// (show_widget). `svg`: a t27f tool produced a drawing for this answer. +pub fn answer_channel(host: u32, inline_tool: bool, svg: bool) -> u32 { + if (host == HOST_CLAUDE_CODE_DESKTOP) { + if (inline_tool) { return CH_INLINE_WIDGET; } + if (svg) { return CH_FILE_AND_PANE; } + return CH_MARKDOWN_TABLE; + } + if (host == HOST_MCP_APPS) { return CH_UI_RESOURCE; } + if (host == HOST_SITE) { return CH_LIVE_PLAYER; } + if (host == HOST_TRI_CLAW) { + if (svg) { return CH_IMAGE_URL; } + return CH_MARKDOWN_TABLE; + } + if (svg) { return CH_FILE_PATH; } + return CH_MARKDOWN_TABLE; +} + +/// Whether text of `font_px` in a drawing `view_w` wide is at least MIN_FONT_PX when shown INLINE_W wide. +pub fn inline_readable(view_w: u32, font_px: u32) -> bool { + if (view_w == 0) { return false; } + return font_px * INLINE_W >= MIN_FONT_PX * view_w; +} + +/// Whether a tool SVG goes inline as it is or is redrawn from t27f_outline rows. `min_font_px` is its +/// smallest text. +pub fn inline_source(view_w: u32, min_font_px: u32, bytes: u32) -> u32 { + if (inline_readable(view_w, min_font_px) == false) { return SRC_REDRAW; } + if (bytes > INLINE_MAX_BYTES) { return SRC_REDRAW; } + return SRC_EMBED; +} + +/// The verdict on an answer. `drawn`: nodes in its visual; `backed`: those a tool row backs. +/// `label_kinds`: how many of the four labels it draws. `view_w` / `min_font_px`: the drawing's width +/// and its smallest text, in its own units (0 width when it is not shown inline). +pub fn answer_verdict(kind: u32, has_visual: bool, drawn: u32, backed: u32, label_kinds: u32, legend: bool, source: bool, view_w: u32, min_font_px: u32) -> u32 { + if (needs_visual(kind) == false) { return V_OK; } + if (has_visual == false) { return V_NO_VISUAL; } + if (drawn > backed) { return V_INVENTED; } + if (label_kinds > 0) { + if (legend == false) { return V_NO_LEGEND; } + } + if (source == false) { return V_NO_SOURCE; } + if (view_w > 0) { + if (inline_readable(view_w, min_font_px) == false) { return V_UNREADABLE; } + } + return V_OK; +} + +test "the tables are the size they say" { + assert CHANNEL_NAME[CH_INLINE_WIDGET] == "inline widget"; + assert CHANNEL_NAME[CH_MARKDOWN_TABLE] == "markdown table"; + assert LABEL_NAMES[3] == "unknown"; + assert VERDICT_TEXT[V_OK] == "ok"; + assert RULE_CLAUDE_CODE[0] == "Visual output (specs/t27mcp/visual_output.t27):"; + assert RULE_TRI_CLAW[0] == "Visual output (specs/t27mcp/visual_output.t27):"; + assert RULE_CLAUDE_CODE[1] == "- Every answer that explains a spec, a flow, numbers or a piece of work carries one visual. Only a one-sentence reply or a question back goes without."; + assert RULE_TRI_CLAW[1] == "- Every answer that explains a spec, a flow, numbers or a piece of work carries one visual. Only a one-sentence reply or a question back goes without."; +} + +test "needs_visual: spec, flow, numbers and a report carry one; one sentence and a question do not" { + assert needs_visual(K_SPEC); + assert needs_visual(K_FLOW); + assert needs_visual(K_NUMBERS); + assert needs_visual(K_REPORT); + assert needs_visual(K_ONE_SENTENCE) == false; + assert needs_visual(K_QUESTION) == false; +} + +test "answer_channel: the desktop app draws inline, TRI CLAW shows an image URL" { + assert answer_channel(HOST_CLAUDE_CODE_DESKTOP, true, true) == CH_INLINE_WIDGET; + assert answer_channel(HOST_CLAUDE_CODE_DESKTOP, true, false) == CH_INLINE_WIDGET; + assert answer_channel(HOST_TRI_CLAW, false, true) == CH_IMAGE_URL; + assert answer_channel(HOST_TRI_CLAW, true, true) == CH_IMAGE_URL; +} + +test "answer_channel: with no inline tool or no drawing, a path or a markdown table" { + assert answer_channel(HOST_CLAUDE_CODE_DESKTOP, false, true) == CH_FILE_AND_PANE; + assert answer_channel(HOST_CLAUDE_CODE_DESKTOP, false, false) == CH_MARKDOWN_TABLE; + assert answer_channel(HOST_CLAUDE_CODE_CLI, false, true) == CH_FILE_PATH; + assert answer_channel(HOST_CLAUDE_CODE_CLI, false, false) == CH_MARKDOWN_TABLE; + assert answer_channel(HOST_TRI_CLAW, false, false) == CH_MARKDOWN_TABLE; + assert answer_channel(HOST_MCP_APPS, false, true) == CH_UI_RESOURCE; + assert answer_channel(HOST_SITE, false, true) == CH_LIVE_PLAYER; + assert answer_channel(HOST_COUNT, false, true) == CH_FILE_PATH; +} + +test "inline_readable: the measured drawings" { + assert inline_readable(1860, 13) == false; + assert inline_readable(1280, 26); + assert inline_readable(1280, 15) == false; + assert inline_readable(680, 11); + assert inline_readable(680, 10) == false; + assert inline_readable(340, 6); +} + +test "inline_source: embed a small readable SVG, redraw the rest" { + assert inline_source(680, 12, 5923) == SRC_EMBED; + assert inline_source(1860, 13, 5923) == SRC_REDRAW; + assert inline_source(680, 12, INLINE_MAX_BYTES) == SRC_EMBED; + assert inline_source(680, 12, INLINE_MAX_BYTES + 1) == SRC_REDRAW; +} + +test "answer_verdict: a backed, labelled, sourced, readable drawing is ok" { + assert answer_verdict(K_SPEC, true, 12, 12, 3, true, true, 680, 12) == V_OK; + assert answer_verdict(K_REPORT, true, 4, 4, 0, false, true, 680, 11) == V_OK; + assert answer_verdict(K_ONE_SENTENCE, false, 0, 0, 0, false, false, 0, 0) == V_OK; + assert answer_verdict(K_NUMBERS, true, 5, 5, 1, true, true, 0, 0) == V_OK; +} + +test "negative control: a spec answer with no visual, or with a node no row backs" { + assert answer_verdict(K_SPEC, false, 0, 0, 0, false, false, 0, 0) == V_NO_VISUAL; + assert answer_verdict(K_FLOW, false, 0, 0, 0, false, true, 0, 0) == V_NO_VISUAL; + assert answer_verdict(K_SPEC, true, 13, 12, 3, true, true, 680, 12) == V_INVENTED; +} + +test "negative control: labels without a legend, a drawing without its source, unreadable text" { + assert answer_verdict(K_SPEC, true, 12, 12, 2, false, true, 680, 12) == V_NO_LEGEND; + assert answer_verdict(K_SPEC, true, 12, 12, 2, true, false, 680, 12) == V_NO_SOURCE; + assert answer_verdict(K_SPEC, true, 12, 12, 2, true, true, 1860, 13) == V_UNREADABLE; + assert inline_readable(0, 13) == false; +} From 2cdfd981b097a45a33479ee4eace5f4521d954c8 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 22:37:17 +0700 Subject: [PATCH 02/11] claw: visual_output.t27 -- a T27F visual in every output that did work (Closes #10508) Owner order 2026-10-18: every Claude Code output carries a visual, built on the T27F visualizer and its MCP tools, written into the TRI CLAW rules. The T27F meant here is the particle video (token_floor reels). - specs/claw/visual_output.t27: which output kind carries which visual (particle still by default, reel, spec graph, check-run link), lab vs MCP host rendering, session-folder placement through T27fReel.channel_for, EXPORTED/FOLDED/MANUAL graph labels at the t27f_graph caps, and report_ok: every needed visual is made or reported missing. 8/8, 0 vacuous on the lab. - Seal written by t27c seal --save; spec_hash matches. - Skill t27f: "Visual in every output" steps pointing to the law; the particle reels are T27F too. - docs/claw/README.md: one row pointing to the law. Co-Authored-By: Claude Opus 5.5 --- .claude/skills/t27f/SKILL.md | 19 ++ .trinity/seals/claw_ClawVisualOutput.json | 41 ++++ docs/claw/README.md | 1 + specs/claw/visual_output.t27 | 232 ++++++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 .trinity/seals/claw_ClawVisualOutput.json create mode 100644 specs/claw/visual_output.t27 diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index 187a88c8ab..447d835169 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -49,6 +49,11 @@ executable visual diagrams"). as a navigable program, linked to source, tests, issues and real task status; each cell is both a spec and a learning entry point. +**The particle video is T27F too** (owner, 2026-10-18: "t27f is the particle video, the thing you +were doing"). The token_floor reels (`specs/t27f/token_floor*.t27`, `lesson_reel.t27`) are the +form of T27F the owner means when asking for a visual. The graph IR below is the inspectable form. +Both are T27F; neither replaces the other. + **What T27F is not:** it is not the topic-to-value engine. gHashTag/trinity#1677 (topic or client brief -> 27-lesson map -> Bee -> verified artifact) is an *application* built on T27F, and so are the reels. Describing T27F as #1677 is the error this section exists to stop (owner correction, @@ -93,6 +98,20 @@ is not progress on the core. Anything the rules do not reach (SUGGESTED explanations, call-result flow, anything larger) is still a manual reading, and no host runs either pass yet. Name that gap rather than hide it. +## Visual in every output (Claude Code and TRI CLAW) + +**The law is `specs/claw/visual_output.t27`.** This section is the order of steps; which output +carries which visual, where it is made and where the file goes are the spec's, not repeated here. + +1. Decide the output's kind (`OUT_*`). Only a reply that just talks goes without a visual. +2. Particle still or reel: render on the Railway lab (never the Mac), take the still at `STILL_MS` + with `ffmpeg -ss 9 -frames:v 1`, and bring it into the session folder (`out-reels/`, gitignored, + never `git add`). Open it in the Browser pane as `file://`, so the user sees it. +3. Spec output: also `mcp__t27__t27f_graph` on the spec. If the corpus answers 404, say it is a + manual reading (`GRAPH_MANUAL`); if it is over the caps, fold it, never cut it. +4. `t27f_view` stills: at most two headline lines per slide; pass `out` inside the session folder. +5. Anything not made: say which and why in the answer. Never show an older file as this turn's. + ## Application: topic map (gHashTag/trinity#1677) Use this part when the user gives a topic or a client brief, not a spec. diff --git a/.trinity/seals/claw_ClawVisualOutput.json b/.trinity/seals/claw_ClawVisualOutput.json new file mode 100644 index 0000000000..08e216f34b --- /dev/null +++ b/.trinity/seals/claw_ClawVisualOutput.json @@ -0,0 +1,41 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9448ab4be", + "closure": [ + { + "spec": "specs/t27f/deck.t27", + "spec_hash": "sha256:bd8ef9fc155365c805ba716d97155bed1e4017c378dbc335e252bcb244512147" + }, + { + "spec": "specs/t27f/reel.t27", + "spec_hash": "sha256:c47b21cea1d7169da6528e321cf2d2c513d3f552c0cd04fe9d37bbd5314ccacf" + }, + { + "spec": "specs/t27f/reel_marketing.t27", + "spec_hash": "sha256:ab07f6476d900cc0e089ba1d851f0b610a77b778f00fd906d1b98a29281941c7" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:2bded953aa3eb3d347630c52244a46152cbd24305f9cad12cf4e73ac0e11cc54", + "gen_hash_rust": "sha256:68e06b627cadee1d253df6776e5c5de04a9a01beef31d3d8662f8d63c05ea577", + "gen_hash_verilog": "sha256:96c0a56fe36c322ba2b59439a2e848975007626a66bf28cfbfdc609d9fa462de", + "gen_hash_zig": "sha256:6abdb83ec1646b9c5d3f6146a19d329149f8c5478b92c1aed04ea8014b105729", + "module": "ClawVisualOutput", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T15:35:23Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:2cbf82c0dad4bc18171b46d1e90bd2451c4f5fc5b3dbc83198389e55fa42571d", + "spec_path": "specs/claw/visual_output.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 8, + "total": 8, + "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 989fe8ff50..82752902e3 100644 --- a/docs/claw/README.md +++ b/docs/claw/README.md @@ -17,6 +17,7 @@ behind one front door, with the gate logic in `.t27` specs. Epic | Suggestion review on a pull request | `specs/claw/suggest_feed.t27` over `specs/claw/suggest.t27` and `specs/tri/fmt_source.t27`, the `claw-suggest` job of `gate-topology.yml` | #10365, live once the owner steps below are done | | 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 output that did work (particle still by default) | `specs/claw/visual_output.t27`, procedure in skill `t27f`, "Visual in every output" | owner directive 2026-10-18 | | Positioning / pricing | `docs/claw/competitors.md` | T6, started | ## The T27F check in every `.t27` repository (#10268) diff --git a/specs/claw/visual_output.t27 b/specs/claw/visual_output.t27 new file mode 100644 index 0000000000..6b03f6d9ba --- /dev/null +++ b/specs/claw/visual_output.t27 @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/claw/visual_output.t27 -- every TRI CLAW output that did work carries a T27F visual, as law. +; Owner order 2026-10-18: study the T27F visualizer through the MCP tools, take the best practices, +; make the output in Claude Code always carry a visual, and write that into the TRI CLAW rules. The +; owner's T27F here is the particle video: the token_floor world (specs/t27f/token_floor.t27, +; token_floor_scenes.t27, token_floor_mux.t27, lesson_reel.t27), rendered as a reel. +; -- +; The rule, each row tested below: +; - a reply that only talks (a short answer, a question back) needs no visual. Every other output +; needs one: a turn that changed files or ran commands, a spec added or explained, a status report, +; a reel, a TRI CLAW check-run on a pull request. +; - The default visual is a particle STILL: one PNG frame of a rendered token_floor reel, taken at +; STILL_MS, after the hook has written its statement and before the CTA hold. A reel output carries +; the reel itself (tall and wide) plus its still. A spec output also carries the spec's T27F GRAPH. +; A check-run carries a LINK (claw/t27f and the T27F preview already post one). +; - Particle frames are rendered on the Railway lab, never on the owner's Mac (owner rule +; 2026-10-09). The MCP stills (t27f_graph, t27f_view) are SVG the MCP host draws. +; - Where it goes is T27fReel.channel_for (specs/t27f/reel.t27), imported, not copied. On the +; desktop Code tab the file sits inside the session's folder (a gitignored out dir of the +; worktree): the file pane opens only files there, and the Browser pane shows a file outside the +; project folder only as a static snapshot (measured 2026-10-18). +; - Honesty: a visual that could not be made is reported missing, with the reason. It is never +; skipped silently, and an older file is never shown as this turn's. A spec graph is EXPORTED only +; when the MCP corpus served the spec and it fits the tool's caps. A larger one is FOLDED +; (specs/t27f/spec_graph_fold.t27), never truncated. An unserved one is a MANUAL reading and is +; called that. +; - A slide headline longer than T27fDeck.MAX_HEADLINE_LINES is split over more slides, not cut. +; -- +; Measured 2026-10-18 through the MCP tools (gHashTag/t27-mcp): +; - t27f_outline and t27f_graph read the published corpus at t27.ai/t27/files/. +; specs/tutorial/08_modules_and_arrays.t27 is served (14 nodes, 9 edges, exact only). But +; specs/t27f/*.t27 and specs/claw/*.t27 answer 404, so the visualizer cannot yet draw its own +; specs or TRI CLAW's: GRAPH_MANUAL until they are published. +; - t27f_view refuses a 3-line headline ("split it into a second slide"). It writes to the temp +; directory unless `out` names a path, and on the desktop that temp path is outside the session. +; - No MCP tool renders a particle still. The lab recipe (render the reel, then +; `ffmpeg -ss -frames:v 1`) is the only path today; a reel_still tool in TRI CLAW's /mcp is +; the follow-up. +; The caps GRAPH_NODE_CAP / GRAPH_EDGE_CAP are the t27f_graph tool's own (its description, +; 2026-10-18), not a spec's; the exporter itself reaches 1024 / 4096. +; phi^2 + 1/phi^2 = 3 | TRINITY + +module ClawVisualOutput; + +use t27f::reel::channel_for; +use t27f::reel::HOST_CLAUDE_CODE_CLI; +use t27f::reel::HOST_CLAUDE_CODE_DESKTOP; +use t27f::reel::HOST_MCP_APPS; +use t27f::reel::HOST_SITE; +use t27f::reel::CHANNEL_FILE_AND_PANE; +use t27f::deck::MAX_HEADLINE_LINES; +use t27f::reel_marketing::REEL_HOOK_MS; +use t27f::reel_marketing::REEL_CTA_MIN_MS; +use t27f::reel_marketing::REEL_MIN_MS; + +/// What an output is. +pub const OUT_TALK : u8 = 0; // a short answer, a question back, conversation +pub const OUT_WORK : u8 = 1; // a turn that changed files or ran commands +pub const OUT_SPEC : u8 = 2; // a .t27 spec added, changed or explained +pub const OUT_STATUS : u8 = 3; // a status or progress report +pub const OUT_REEL : u8 = 4; // the output is a reel +pub const OUT_CHECK : u8 = 5; // a TRI CLAW check-run on a pull request +pub const OUT_KINDS : u8 = 6; + +/// What it carries, one bit each, so one output can carry several. +pub const VIS_STILL : u8 = 1; // particle still, PNG, one frame of a token_floor reel +pub const VIS_REEL : u8 = 2; // the reel, tall and wide mp4 +pub const VIS_GRAPH : u8 = 4; // the spec's T27F graph, SVG, from t27f_graph +pub const VIS_LINK : u8 = 8; // a link in the check-run summary + +/// Where a visual is made. +pub const RENDER_LAB : u8 = 0; // the Railway lab +pub const RENDER_HOST : u8 = 1; // the MCP host + +/// Where the file is put. +pub const PLACE_ANY : u8 = 0; // any path, printed in the answer +pub const PLACE_SESSION : u8 = 1; // inside the session's folder + +/// How a spec graph is labelled. +pub const GRAPH_EXPORTED : u8 = 0; +pub const GRAPH_FOLDED : u8 = 1; +pub const GRAPH_MANUAL : u8 = 2; +pub const GRAPH_NODE_CAP : u32 = 192; +pub const GRAPH_EDGE_CAP : u32 = 254; + +/// The still is this frame of a reel: past the hook's decision window, before the CTA hold. +pub const STILL_MS : i32 = 9000; + +pub fn has(v: u8, bit: u8) -> bool { + return @mod(v / bit, 2) == 1; +} + +/// The visuals an output of this kind carries. A kind this law does not know gets the default +/// still: a reader that waves through an unknown kind with no visual is not a rule. +pub fn visuals_for(kind: u8) -> u8 { + if (kind == OUT_TALK) { + return 0; + } + if (kind == OUT_SPEC) { + return VIS_STILL + VIS_GRAPH; + } + if (kind == OUT_REEL) { + return VIS_STILL + VIS_REEL; + } + if (kind == OUT_CHECK) { + return VIS_LINK; + } + return VIS_STILL; +} + +pub fn needs_visual(kind: u8) -> bool { + return visuals_for(kind) != 0; +} + +/// Particle frames come from the lab; SVG from the MCP host. +pub fn render_place(bit: u8) -> u8 { + if (bit == VIS_STILL or bit == VIS_REEL) { + return RENDER_LAB; + } + return RENDER_HOST; +} + +/// The file goes inside the session folder wherever the host opens it in a pane. +pub fn place_for(host: u8) -> u8 { + if (channel_for(host) == CHANNEL_FILE_AND_PANE) { + return PLACE_SESSION; + } + return PLACE_ANY; +} + +pub fn graph_label(served: bool, nodes: u32, edges: u32) -> u8 { + if (served == false) { + return GRAPH_MANUAL; + } + if (nodes > GRAPH_NODE_CAP or edges > GRAPH_EDGE_CAP) { + return GRAPH_FOLDED; + } + return GRAPH_EXPORTED; +} + +/// An output is honest when every visual it needs was made this turn or is reported missing. +pub fn report_ok(kind: u8, made: u8, said_missing: u8) -> bool { + const need = visuals_for(kind); + var ok = true; + var bit : u8 = 1; + while (bit <= VIS_LINK) { + if (has(need, bit) and has(made, bit) == false and has(said_missing, bit) == false) { + ok = false; + } + bit = bit * 2; + } + return ok; +} + +/// A still frame shows the statement, not the hook still writing it and not the CTA hold. +pub fn still_ms_ok(ms: i32) -> bool { + return ms > REEL_HOOK_MS and ms < REEL_MIN_MS - REEL_CTA_MIN_MS; +} + +/// Slides a headline of this many lines takes: split, never cut. +pub fn slides_for(lines: i32) -> i32 { + return (lines + MAX_HEADLINE_LINES - 1) / MAX_HEADLINE_LINES; +} + +test only_talk_goes_without_a_visual { + assert needs_visual(OUT_TALK) == false; + var k : u8 = 1; + while (k < OUT_KINDS) { + assert needs_visual(k); + k = k + 1; + } + assert visuals_for(OUT_KINDS) == VIS_STILL; + assert visuals_for(200) == VIS_STILL; +} + +test each_kind_carries_its_visuals { + assert visuals_for(OUT_WORK) == VIS_STILL; + assert visuals_for(OUT_STATUS) == VIS_STILL; + assert has(visuals_for(OUT_SPEC), VIS_STILL) and has(visuals_for(OUT_SPEC), VIS_GRAPH); + assert has(visuals_for(OUT_REEL), VIS_REEL) and has(visuals_for(OUT_REEL), VIS_STILL); + assert has(visuals_for(OUT_REEL), VIS_GRAPH) == false; + assert visuals_for(OUT_CHECK) == VIS_LINK; +} + +test particle_frames_come_from_the_lab { + assert render_place(VIS_STILL) == RENDER_LAB; + assert render_place(VIS_REEL) == RENDER_LAB; + assert render_place(VIS_GRAPH) == RENDER_HOST; +} + +test the_desktop_file_sits_in_the_session_folder { + assert place_for(HOST_CLAUDE_CODE_DESKTOP) == PLACE_SESSION; + assert place_for(HOST_CLAUDE_CODE_CLI) == PLACE_ANY; + assert place_for(HOST_MCP_APPS) == PLACE_ANY; + assert place_for(HOST_SITE) == PLACE_ANY; +} + +test a_graph_says_how_it_was_read { + // tutorial 08, as t27f_outline served it on 2026-10-18 + assert graph_label(true, 14, 9) == GRAPH_EXPORTED; + assert graph_label(true, 192, 254) == GRAPH_EXPORTED; + // the largest spec in specs/ after derive: 775 nodes, 3194 edges + assert graph_label(true, 775, 3194) == GRAPH_FOLDED; + assert graph_label(true, 193, 9) == GRAPH_FOLDED; + // specs/claw/*.t27 answered 404 + assert graph_label(false, 14, 9) == GRAPH_MANUAL; +} + +test a_missing_visual_is_said_never_skipped { + assert report_ok(OUT_TALK, 0, 0); + assert report_ok(OUT_WORK, VIS_STILL, 0); + assert report_ok(OUT_WORK, 0, 0) == false; + assert report_ok(OUT_WORK, 0, VIS_STILL); + assert report_ok(OUT_SPEC, VIS_STILL, 0) == false; + assert report_ok(OUT_SPEC, VIS_STILL, VIS_GRAPH); + assert report_ok(OUT_REEL, VIS_STILL + VIS_REEL, 0); + assert report_ok(OUT_CHECK, VIS_STILL, 0) == false; +} + +test the_still_is_past_the_hook_and_before_the_cta { + assert still_ms_ok(STILL_MS); + assert still_ms_ok(REEL_HOOK_MS) == false; + assert still_ms_ok(1000) == false; + assert still_ms_ok(14000) == false; +} + +test a_long_headline_takes_more_slides { + assert slides_for(1) == 1; + assert slides_for(2) == 1; + assert slides_for(3) == 2; + assert slides_for(5) == 3; +} From 9e9d57d401309d5259f8dc9d22d11522c790bc3c Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 22:50:40 +0700 Subject: [PATCH 03/11] ledger: specs/claw/visual_output.t27 passes t27b (Closes #10508) The t27b-native ratchet reported the new spec as UNLISTED: the reference passes it and the ledger did not name it. A pass row; max_not_pass is unchanged. 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 09b79809ce..c5bc8a31e0 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -202,6 +202,7 @@ {"path": "specs/claw/t27f_gate.t27", "t27b": "pass"}, {"path": "specs/claw/t27f_gate_pins.t27", "t27b": "pass"}, {"path": "specs/claw/text.t27", "t27b": "pass"}, + {"path": "specs/claw/visual_output.t27", "t27b": "pass"}, {"path": "specs/compiler/c_array_repeat_wrapper.t27", "t27b": "pass"}, {"path": "specs/compiler/c_fixed_array_return.t27", "t27b": "pass"}, {"path": "specs/compiler/codegen_conformance.t27", "t27b": "pass"}, From fb64113d8b564f87921abce59b443735ba36b32c Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:11:05 +0700 Subject: [PATCH 04/11] ledger: specs/analog/linear.t27 passes t27b (Closes #10508) It landed on master without a ledger row, so the t27b-native ratchet reports it UNLISTED on every branch. A pass row; max_not_pass unchanged. 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 c5bc8a31e0..8a76efd6da 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -43,6 +43,7 @@ {"path": "specs/agents/x.t27", "t27b": "pass"}, {"path": "specs/agents/y.t27", "t27b": "pass"}, {"path": "specs/agents/z.t27", "t27b": "pass"}, + {"path": "specs/analog/linear.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 2759272a223bf868152b14279f37c6298c6f2201 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:22:53 +0700 Subject: [PATCH 05/11] ledger: specs/analog/mos_table.t27 passes t27b (Closes #10508) 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 8a76efd6da..61f30b1327 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -44,6 +44,7 @@ {"path": "specs/agents/y.t27", "t27b": "pass"}, {"path": "specs/agents/z.t27", "t27b": "pass"}, {"path": "specs/analog/linear.t27", "t27b": "pass"}, + {"path": "specs/analog/mos_table.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 c39c5c5ebc7d465a650fd200ad9fa11e558a38c2 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:37:31 +0700 Subject: [PATCH 06/11] ledger: specs/analog/bench.t27 passes t27b (Closes #10508) 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 61f30b1327..0509a6a681 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -43,6 +43,7 @@ {"path": "specs/agents/x.t27", "t27b": "pass"}, {"path": "specs/agents/y.t27", "t27b": "pass"}, {"path": "specs/agents/z.t27", "t27b": "pass"}, + {"path": "specs/analog/bench.t27", "t27b": "pass"}, {"path": "specs/analog/linear.t27", "t27b": "pass"}, {"path": "specs/analog/mos_table.t27", "t27b": "pass"}, {"path": "specs/api/c_abi.t27", "t27b": "pass"}, From 63c53fc9b27f31156a5a6c61532b1b6348395b03 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:43:21 +0700 Subject: [PATCH 07/11] claw: visual_output.t27 keeps only the particle-still layer, imports the rule from t27mcp::visual_output (#10504) (Closes #10508) The owner picked specs/t27mcp/visual_output.t27 as the single home of the visual-output rule. The claw spec now imports needs_visual, answer_channel and the K_/HOST_/CH_ numbers from it and adds only takes_still, still_channel, place_for, still_ms_ok and still_report_ok. Lab: 6/6, 0 vacuous; t27mcp spec 9/9, 0 vacuous. Resealed. Ledger row for specs/t27mcp/visual_output.t27 (t27b pass, per #10504's own ratchet run). Co-Authored-By: Claude Opus 5.5 --- .claude/skills/t27f/SKILL.md | 24 +- .trinity/seals/claw_ClawVisualOutput.json | 28 +-- docs/claw/README.md | 2 +- docs/reports/t27b_expectations.json | 1 + specs/claw/visual_output.t27 | 266 +++++++--------------- 5 files changed, 112 insertions(+), 209 deletions(-) diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index 447d835169..d154176949 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -100,17 +100,19 @@ is not progress on the core. ## Visual in every output (Claude Code and TRI CLAW) -**The law is `specs/claw/visual_output.t27`.** This section is the order of steps; which output -carries which visual, where it is made and where the file goes are the spec's, not repeated here. - -1. Decide the output's kind (`OUT_*`). Only a reply that just talks goes without a visual. -2. Particle still or reel: render on the Railway lab (never the Mac), take the still at `STILL_MS` - with `ffmpeg -ss 9 -frames:v 1`, and bring it into the session folder (`out-reels/`, gitignored, - never `git add`). Open it in the Browser pane as `file://`, so the user sees it. -3. Spec output: also `mcp__t27__t27f_graph` on the spec. If the corpus answers 404, say it is a - manual reading (`GRAPH_MANUAL`); if it is over the caps, fold it, never cut it. -4. `t27f_view` stills: at most two headline lines per slide; pass `out` inside the session folder. -5. Anything not made: say which and why in the answer. Never show an older file as this turn's. +**The rule is `specs/t27mcp/visual_output.t27`** (its `RULE_CLAUDE_CODE` and `RULE_TRI_CLAW` lines +are what each host reads). **Its particle-still layer is `specs/claw/visual_output.t27`.** This +section is the order of steps; which answer carries which visual and how it reaches each host are +the specs', not repeated here. + +1. Decide the answer's kind (`K_*` in the t27mcp spec). A one-sentence reply or a question back + goes without a visual. +2. Spec, flow or numbers: draw from t27f tool rows (`t27f_outline`, `t27f_graph`, `t27f_view`), + labelled, with the legend and the source file, as `answer_verdict` checks. +3. A report of a piece of work: a particle still (`takes_still`). Render the reel on the Railway lab + (never the Mac), take the frame at `STILL_MS` with `ffmpeg -ss 9 -frames:v 1`, and bring it into + the session folder (`out-reels/`, gitignored, never `git add`). +4. Anything not made: say which and why in the answer. Never show an older file as this turn's. ## Application: topic map (gHashTag/trinity#1677) diff --git a/.trinity/seals/claw_ClawVisualOutput.json b/.trinity/seals/claw_ClawVisualOutput.json index 08e216f34b..3556c08782 100644 --- a/.trinity/seals/claw_ClawVisualOutput.json +++ b/.trinity/seals/claw_ClawVisualOutput.json @@ -1,37 +1,33 @@ { "built_by": "t27c-bootstrap@0.5.2+9448ab4be", "closure": [ - { - "spec": "specs/t27f/deck.t27", - "spec_hash": "sha256:bd8ef9fc155365c805ba716d97155bed1e4017c378dbc335e252bcb244512147" - }, - { - "spec": "specs/t27f/reel.t27", - "spec_hash": "sha256:c47b21cea1d7169da6528e321cf2d2c513d3f552c0cd04fe9d37bbd5314ccacf" - }, { "spec": "specs/t27f/reel_marketing.t27", "spec_hash": "sha256:ab07f6476d900cc0e089ba1d851f0b610a77b778f00fd906d1b98a29281941c7" + }, + { + "spec": "specs/t27mcp/visual_output.t27", + "spec_hash": "sha256:06c1c5e73142e2f79fa5d7be037eace63c1f20597a6e33274ebf8e1b428b7584" } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:2bded953aa3eb3d347630c52244a46152cbd24305f9cad12cf4e73ac0e11cc54", - "gen_hash_rust": "sha256:68e06b627cadee1d253df6776e5c5de04a9a01beef31d3d8662f8d63c05ea577", - "gen_hash_verilog": "sha256:96c0a56fe36c322ba2b59439a2e848975007626a66bf28cfbfdc609d9fa462de", - "gen_hash_zig": "sha256:6abdb83ec1646b9c5d3f6146a19d329149f8c5478b92c1aed04ea8014b105729", + "gen_hash_c": "sha256:195d1b6aa754842316d3c8becc34ce6a0a90e5f7d4ddaebd490823103ed06c33", + "gen_hash_rust": "sha256:93ecd121c7efadf95e4ca54e1e750fb5c7a8159284cebe1cbb61d7065d1b7875", + "gen_hash_verilog": "sha256:794e86d5753efad530cd7732b2638ad3c3a5c4e6d8c9a851bd686663aa097282", + "gen_hash_zig": "sha256:d6204f6e99bc281a0163177b92ee4abf096ea32cb23cb3b817913d16c8d072b1", "module": "ClawVisualOutput", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-18T15:35:23Z", + "sealed_at": "2026-10-18T16:42:30Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:2cbf82c0dad4bc18171b46d1e90bd2451c4f5fc5b3dbc83198389e55fa42571d", + "spec_hash": "sha256:17137afe136e39910f38d7b031c659a672e009bfeef1bf4f9b7af7e2cb6cc628", "spec_path": "specs/claw/visual_output.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 8, - "total": 8, + "passed": 6, + "total": 6, "vacuous": 0 }, "toolchain": { diff --git a/docs/claw/README.md b/docs/claw/README.md index 82752902e3..4a7df352ec 100644 --- a/docs/claw/README.md +++ b/docs/claw/README.md @@ -17,7 +17,7 @@ behind one front door, with the gate logic in `.t27` specs. Epic | Suggestion review on a pull request | `specs/claw/suggest_feed.t27` over `specs/claw/suggest.t27` and `specs/tri/fmt_source.t27`, the `claw-suggest` job of `gate-topology.yml` | #10365, live once the owner steps below are done | | 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 output that did work (particle still by default) | `specs/claw/visual_output.t27`, procedure in skill `t27f`, "Visual in every output" | 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 | | 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 0509a6a681..11452ed21e 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -1478,6 +1478,7 @@ {"path": "specs/t27mcp/spec_brief.t27", "t27b": "pass"}, {"path": "specs/t27mcp/telegram.t27", "t27b": "pass"}, {"path": "specs/t27mcp/tool_schema.t27", "t27b": "codegen", "blocker": "t27b: unsupported construct FnDecl(frame or branch range) at line 0 (fn the round trip fixtures: a tuple, arrays, a boolean, nested objects: conditional branch out of range (function too large))", "reason": "unimplemented"}, + {"path": "specs/t27mcp/visual_output.t27", "t27b": "pass"}, {"path": "specs/ternary/activation_quantizer.t27", "t27b": "pass"}, {"path": "specs/ternary/bitnet_layer.t27", "t27b": "pass"}, {"path": "specs/ternary/bitnet_majority.t27", "t27b": "pass"}, diff --git a/specs/claw/visual_output.t27 b/specs/claw/visual_output.t27 index 6b03f6d9ba..c275dc4276 100644 --- a/specs/claw/visual_output.t27 +++ b/specs/claw/visual_output.t27 @@ -1,220 +1,123 @@ // SPDX-License-Identifier: Apache-2.0 -; specs/claw/visual_output.t27 -- every TRI CLAW output that did work carries a T27F visual, as law. -; Owner order 2026-10-18: study the T27F visualizer through the MCP tools, take the best practices, -; make the output in Claude Code always carry a visual, and write that into the TRI CLAW rules. The -; owner's T27F here is the particle video: the token_floor world (specs/t27f/token_floor.t27, -; token_floor_scenes.t27, token_floor_mux.t27, lesson_reel.t27), rendered as a reel. +; specs/claw/visual_output.t27 -- the particle-still layer of TRI CLAW's visual-output rule. +; Owner order 2026-10-18: every output in Claude Code carries a T27F visual, written into the TRI +; CLAW rules, and the T27F meant here is the particle video: the token_floor world +; (specs/t27f/token_floor.t27, token_floor_scenes.t27, token_floor_mux.t27, lesson_reel.t27). ; -- -; The rule, each row tested below: -; - a reply that only talks (a short answer, a question back) needs no visual. Every other output -; needs one: a turn that changed files or ran commands, a spec added or explained, a status report, -; a reel, a TRI CLAW check-run on a pull request. -; - The default visual is a particle STILL: one PNG frame of a rendered token_floor reel, taken at -; STILL_MS, after the hook has written its statement and before the CTA hold. A reel output carries -; the reel itself (tall and wide) plus its still. A spec output also carries the spec's T27F GRAPH. -; A check-run carries a LINK (claw/t27f and the T27F preview already post one). -; - Particle frames are rendered on the Railway lab, never on the owner's Mac (owner rule -; 2026-10-09). The MCP stills (t27f_graph, t27f_view) are SVG the MCP host draws. -; - Where it goes is T27fReel.channel_for (specs/t27f/reel.t27), imported, not copied. On the -; desktop Code tab the file sits inside the session's folder (a gitignored out dir of the -; worktree): the file pane opens only files there, and the Browser pane shows a file outside the -; project folder only as a static snapshot (measured 2026-10-18). -; - Honesty: a visual that could not be made is reported missing, with the reason. It is never -; skipped silently, and an older file is never shown as this turn's. A spec graph is EXPORTED only -; when the MCP corpus served the spec and it fits the tool's caps. A larger one is FOLDED -; (specs/t27f/spec_graph_fold.t27), never truncated. An unserved one is a MANUAL reading and is -; called that. -; - A slide headline longer than T27fDeck.MAX_HEADLINE_LINES is split over more slides, not cut. -; -- -; Measured 2026-10-18 through the MCP tools (gHashTag/t27-mcp): -; - t27f_outline and t27f_graph read the published corpus at t27.ai/t27/files/. -; specs/tutorial/08_modules_and_arrays.t27 is served (14 nodes, 9 edges, exact only). But -; specs/t27f/*.t27 and specs/claw/*.t27 answer 404, so the visualizer cannot yet draw its own -; specs or TRI CLAW's: GRAPH_MANUAL until they are published. -; - t27f_view refuses a 3-line headline ("split it into a second slide"). It writes to the temp -; directory unless `out` names a path, and on the desktop that temp path is outside the session. -; - No MCP tool renders a particle still. The lab recipe (render the reel, then -; `ffmpeg -ss -frames:v 1`) is the only path today; a reel_still tool in TRI CLAW's /mcp is -; the follow-up. -; The caps GRAPH_NODE_CAP / GRAPH_EDGE_CAP are the t27f_graph tool's own (its description, -; 2026-10-18), not a spec's; the exporter itself reaches 1024 / 4096. +; The rule itself has one home, specs/t27mcp/visual_output.t27 (owner pick 2026-10-18): which answers +; carry a visual (needs_visual), how it reaches each host (answer_channel), and the verdict on a +; drawing made from t27f tool rows (answer_verdict). This spec imports those and adds only what is +; particular to a particle still: +; - Which answer's visual is a still: a report of a piece of work (K_REPORT). A spec, a flow or +; numbers are drawn from t27f tool rows, as the t27mcp law says; a still backs no row, so it is +; not their visual. +; - The still is one PNG frame of a rendered token_floor reel, taken at STILL_MS: after the hook has +; written its statement and before the CTA hold. +; - It is rendered on the Railway lab, never on the owner's Mac (owner rule 2026-10-09). No MCP tool +; renders one yet; the lab recipe (render the reel, then `ffmpeg -ss -frames:v 1`) is the only +; path, and a reel_still tool in TRI CLAW's /mcp is the follow-up. +; - It is a file, not an inline widget, so its channel is answer_channel for a drawing on a host with +; no visual tool. On the desktop Code tab that is the file pane, which opens only files inside the +; session's folder (measured 2026-10-18), so the PNG goes there. +; - A still that could not be made is reported missing, with the reason; an older file is never shown +; as this turn's. +; Not measured: whether TRI CLAW's chat shows a PNG URL (the t27mcp header measured .svg only). ; phi^2 + 1/phi^2 = 3 | TRINITY module ClawVisualOutput; -use t27f::reel::channel_for; -use t27f::reel::HOST_CLAUDE_CODE_CLI; -use t27f::reel::HOST_CLAUDE_CODE_DESKTOP; -use t27f::reel::HOST_MCP_APPS; -use t27f::reel::HOST_SITE; -use t27f::reel::CHANNEL_FILE_AND_PANE; -use t27f::deck::MAX_HEADLINE_LINES; +use t27mcp::visual_output::needs_visual; +use t27mcp::visual_output::answer_channel; +use t27mcp::visual_output::K_SPEC; +use t27mcp::visual_output::K_FLOW; +use t27mcp::visual_output::K_NUMBERS; +use t27mcp::visual_output::K_REPORT; +use t27mcp::visual_output::K_ONE_SENTENCE; +use t27mcp::visual_output::K_QUESTION; +use t27mcp::visual_output::HOST_CLAUDE_CODE_CLI; +use t27mcp::visual_output::HOST_CLAUDE_CODE_DESKTOP; +use t27mcp::visual_output::HOST_MCP_APPS; +use t27mcp::visual_output::HOST_TRI_CLAW; +use t27mcp::visual_output::CH_FILE_PATH; +use t27mcp::visual_output::CH_FILE_AND_PANE; +use t27mcp::visual_output::CH_UI_RESOURCE; +use t27mcp::visual_output::CH_IMAGE_URL; use t27f::reel_marketing::REEL_HOOK_MS; use t27f::reel_marketing::REEL_CTA_MIN_MS; use t27f::reel_marketing::REEL_MIN_MS; -/// What an output is. -pub const OUT_TALK : u8 = 0; // a short answer, a question back, conversation -pub const OUT_WORK : u8 = 1; // a turn that changed files or ran commands -pub const OUT_SPEC : u8 = 2; // a .t27 spec added, changed or explained -pub const OUT_STATUS : u8 = 3; // a status or progress report -pub const OUT_REEL : u8 = 4; // the output is a reel -pub const OUT_CHECK : u8 = 5; // a TRI CLAW check-run on a pull request -pub const OUT_KINDS : u8 = 6; - -/// What it carries, one bit each, so one output can carry several. -pub const VIS_STILL : u8 = 1; // particle still, PNG, one frame of a token_floor reel -pub const VIS_REEL : u8 = 2; // the reel, tall and wide mp4 -pub const VIS_GRAPH : u8 = 4; // the spec's T27F graph, SVG, from t27f_graph -pub const VIS_LINK : u8 = 8; // a link in the check-run summary - -/// Where a visual is made. -pub const RENDER_LAB : u8 = 0; // the Railway lab -pub const RENDER_HOST : u8 = 1; // the MCP host - -/// Where the file is put. -pub const PLACE_ANY : u8 = 0; // any path, printed in the answer -pub const PLACE_SESSION : u8 = 1; // inside the session's folder - -/// How a spec graph is labelled. -pub const GRAPH_EXPORTED : u8 = 0; -pub const GRAPH_FOLDED : u8 = 1; -pub const GRAPH_MANUAL : u8 = 2; -pub const GRAPH_NODE_CAP : u32 = 192; -pub const GRAPH_EDGE_CAP : u32 = 254; - /// The still is this frame of a reel: past the hook's decision window, before the CTA hold. pub const STILL_MS : i32 = 9000; -pub fn has(v: u8, bit: u8) -> bool { - return @mod(v / bit, 2) == 1; -} - -/// The visuals an output of this kind carries. A kind this law does not know gets the default -/// still: a reader that waves through an unknown kind with no visual is not a rule. -pub fn visuals_for(kind: u8) -> u8 { - if (kind == OUT_TALK) { - return 0; - } - if (kind == OUT_SPEC) { - return VIS_STILL + VIS_GRAPH; - } - if (kind == OUT_REEL) { - return VIS_STILL + VIS_REEL; - } - if (kind == OUT_CHECK) { - return VIS_LINK; - } - return VIS_STILL; -} +/// Where the still's file is put. +pub const PLACE_ANY : u32 = 0; // any path, printed in the answer +pub const PLACE_SESSION : u32 = 1; // inside the session's folder -pub fn needs_visual(kind: u8) -> bool { - return visuals_for(kind) != 0; +/// Whether an answer of this kind shows a particle still as its visual. +pub fn takes_still(kind: u32) -> bool { + return kind == K_REPORT; } -/// Particle frames come from the lab; SVG from the MCP host. -pub fn render_place(bit: u8) -> u8 { - if (bit == VIS_STILL or bit == VIS_REEL) { - return RENDER_LAB; - } - return RENDER_HOST; +/// How the still reaches the user: a drawn file on a host with no inline visual tool. +pub fn still_channel(host: u32) -> u32 { + return answer_channel(host, false, true); } /// The file goes inside the session folder wherever the host opens it in a pane. -pub fn place_for(host: u8) -> u8 { - if (channel_for(host) == CHANNEL_FILE_AND_PANE) { +pub fn place_for(host: u32) -> u32 { + if (still_channel(host) == CH_FILE_AND_PANE) { return PLACE_SESSION; } return PLACE_ANY; } -pub fn graph_label(served: bool, nodes: u32, edges: u32) -> u8 { - if (served == false) { - return GRAPH_MANUAL; - } - if (nodes > GRAPH_NODE_CAP or edges > GRAPH_EDGE_CAP) { - return GRAPH_FOLDED; - } - return GRAPH_EXPORTED; -} - -/// An output is honest when every visual it needs was made this turn or is reported missing. -pub fn report_ok(kind: u8, made: u8, said_missing: u8) -> bool { - const need = visuals_for(kind); - var ok = true; - var bit : u8 = 1; - while (bit <= VIS_LINK) { - if (has(need, bit) and has(made, bit) == false and has(said_missing, bit) == false) { - ok = false; - } - bit = bit * 2; - } - return ok; -} - /// A still frame shows the statement, not the hook still writing it and not the CTA hold. pub fn still_ms_ok(ms: i32) -> bool { return ms > REEL_HOOK_MS and ms < REEL_MIN_MS - REEL_CTA_MIN_MS; } -/// Slides a headline of this many lines takes: split, never cut. -pub fn slides_for(lines: i32) -> i32 { - return (lines + MAX_HEADLINE_LINES - 1) / MAX_HEADLINE_LINES; +/// An answer is honest about its still when the still was made this turn or is said missing. +pub fn still_report_ok(kind: u32, made: bool, said_missing: bool) -> bool { + if (takes_still(kind) == false) { + return true; + } + return made or said_missing; } -test only_talk_goes_without_a_visual { - assert needs_visual(OUT_TALK) == false; - var k : u8 = 1; - while (k < OUT_KINDS) { - assert needs_visual(k); - k = k + 1; - } - assert visuals_for(OUT_KINDS) == VIS_STILL; - assert visuals_for(200) == VIS_STILL; +test only_a_report_takes_a_still { + assert takes_still(K_REPORT); + assert takes_still(K_SPEC) == false; + assert takes_still(K_FLOW) == false; + assert takes_still(K_NUMBERS) == false; + assert takes_still(K_ONE_SENTENCE) == false; + assert takes_still(K_QUESTION) == false; } -test each_kind_carries_its_visuals { - assert visuals_for(OUT_WORK) == VIS_STILL; - assert visuals_for(OUT_STATUS) == VIS_STILL; - assert has(visuals_for(OUT_SPEC), VIS_STILL) and has(visuals_for(OUT_SPEC), VIS_GRAPH); - assert has(visuals_for(OUT_REEL), VIS_REEL) and has(visuals_for(OUT_REEL), VIS_STILL); - assert has(visuals_for(OUT_REEL), VIS_GRAPH) == false; - assert visuals_for(OUT_CHECK) == VIS_LINK; +test every_still_is_an_answer_the_t27mcp_law_gives_a_visual { + var k : u32 = 0; + var stills : u32 = 0; + while (k <= K_QUESTION) { + if (takes_still(k)) { + assert needs_visual(k); + stills = stills + 1; + } + k = k + 1; + } + assert stills == 1; } -test particle_frames_come_from_the_lab { - assert render_place(VIS_STILL) == RENDER_LAB; - assert render_place(VIS_REEL) == RENDER_LAB; - assert render_place(VIS_GRAPH) == RENDER_HOST; +test the_still_is_a_file_not_a_widget { + assert still_channel(HOST_CLAUDE_CODE_DESKTOP) == CH_FILE_AND_PANE; + assert still_channel(HOST_CLAUDE_CODE_CLI) == CH_FILE_PATH; + assert still_channel(HOST_MCP_APPS) == CH_UI_RESOURCE; + assert still_channel(HOST_TRI_CLAW) == CH_IMAGE_URL; } test the_desktop_file_sits_in_the_session_folder { assert place_for(HOST_CLAUDE_CODE_DESKTOP) == PLACE_SESSION; assert place_for(HOST_CLAUDE_CODE_CLI) == PLACE_ANY; assert place_for(HOST_MCP_APPS) == PLACE_ANY; - assert place_for(HOST_SITE) == PLACE_ANY; -} - -test a_graph_says_how_it_was_read { - // tutorial 08, as t27f_outline served it on 2026-10-18 - assert graph_label(true, 14, 9) == GRAPH_EXPORTED; - assert graph_label(true, 192, 254) == GRAPH_EXPORTED; - // the largest spec in specs/ after derive: 775 nodes, 3194 edges - assert graph_label(true, 775, 3194) == GRAPH_FOLDED; - assert graph_label(true, 193, 9) == GRAPH_FOLDED; - // specs/claw/*.t27 answered 404 - assert graph_label(false, 14, 9) == GRAPH_MANUAL; -} - -test a_missing_visual_is_said_never_skipped { - assert report_ok(OUT_TALK, 0, 0); - assert report_ok(OUT_WORK, VIS_STILL, 0); - assert report_ok(OUT_WORK, 0, 0) == false; - assert report_ok(OUT_WORK, 0, VIS_STILL); - assert report_ok(OUT_SPEC, VIS_STILL, 0) == false; - assert report_ok(OUT_SPEC, VIS_STILL, VIS_GRAPH); - assert report_ok(OUT_REEL, VIS_STILL + VIS_REEL, 0); - assert report_ok(OUT_CHECK, VIS_STILL, 0) == false; + assert place_for(HOST_TRI_CLAW) == PLACE_ANY; } test the_still_is_past_the_hook_and_before_the_cta { @@ -224,9 +127,10 @@ test the_still_is_past_the_hook_and_before_the_cta { assert still_ms_ok(14000) == false; } -test a_long_headline_takes_more_slides { - assert slides_for(1) == 1; - assert slides_for(2) == 1; - assert slides_for(3) == 2; - assert slides_for(5) == 3; +test a_missing_still_is_said_never_skipped { + assert still_report_ok(K_REPORT, true, false); + assert still_report_ok(K_REPORT, false, true); + assert still_report_ok(K_REPORT, false, false) == false; + assert still_report_ok(K_SPEC, false, false); + assert still_report_ok(K_ONE_SENTENCE, false, false); } From 0b1e46dba3de59bb7769d4c37428cd433b8e4254 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 23:44:59 +0700 Subject: [PATCH 08/11] skill t27f: move the particle-video note to the T27F definition PR (Closes #10508) Co-Authored-By: Claude Opus 5.5 --- .claude/skills/t27f/SKILL.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index d154176949..33368e43d5 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -49,11 +49,6 @@ executable visual diagrams"). as a navigable program, linked to source, tests, issues and real task status; each cell is both a spec and a learning entry point. -**The particle video is T27F too** (owner, 2026-10-18: "t27f is the particle video, the thing you -were doing"). The token_floor reels (`specs/t27f/token_floor*.t27`, `lesson_reel.t27`) are the -form of T27F the owner means when asking for a visual. The graph IR below is the inspectable form. -Both are T27F; neither replaces the other. - **What T27F is not:** it is not the topic-to-value engine. gHashTag/trinity#1677 (topic or client brief -> 27-lesson map -> Bee -> verified artifact) is an *application* built on T27F, and so are the reels. Describing T27F as #1677 is the error this section exists to stop (owner correction, From c6ef98856157637b078fd4189cc9b8ee9ef73f6c Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:09:14 +0700 Subject: [PATCH 09/11] ledger: specs/analog/linear_zoh.t27 is t27b-blocked on ExprCall(@sin); master merged it without a row (Closes #10508) 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 11452ed21e..c01b519451 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -45,6 +45,7 @@ {"path": "specs/agents/z.t27", "t27b": "pass"}, {"path": "specs/analog/bench.t27", "t27b": "pass"}, {"path": "specs/analog/linear.t27", "t27b": "pass"}, + {"path": "specs/analog/linear_zoh.t27", "t27b": "blocked", "blocker": "ExprCall(@sin)", "reason": "unimplemented"}, {"path": "specs/analog/mos_table.t27", "t27b": "pass"}, {"path": "specs/api/c_abi.t27", "t27b": "pass"}, {"path": "specs/api/tri_api_context.t27", "t27b": "pass"}, From e992354b5750dd25fee2fd242cc74eb95adc914c Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 01:07:46 +0700 Subject: [PATCH 10/11] ledger: name the five specs master merged without a row (app-tabs, systolic, kill_rule, preflight, reset_queue); cap 134 -> 136 for the two blocked ones (Closes #10508) Evidence: the t27b-native-ratchet job of master run 90f624876 (fresh t27b built from master) lists these as UNLISTED with verdicts: app-tabs, systolic, preflight, reset_queue pass; kill_rule is blocked on ExprCall(undeclared fn). specs/analog/linear_zoh.t27 (blocked on ExprCall(@sin)) was already added on this branch; with kill_rule the non-pass rows are 136, so max_not_pass equals reality (the loop-tools-tracked check). Merged origin/master first, which also brings the Ring -> RingPeak rename (911166fc2) that clears the Corpus ratchet NEW conflict. Co-Authored-By: Claude Opus 5.5 --- docs/reports/t27b_expectations.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/reports/t27b_expectations.json b/docs/reports/t27b_expectations.json index c01b519451..39972900a9 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -12,7 +12,7 @@ "reference-bug": "the reference passes it for the wrong reason; t27b is right not to", "n/a": "outside what t27b is for (say why in the PR that sets it)" }, - "max_not_pass": 134, + "max_not_pass": 136, "entries": [ {"path": "specs/a/b_c.t27", "t27b": "pass"}, {"path": "specs/a_b/c.t27", "t27b": "pass"}, @@ -65,6 +65,7 @@ {"path": "specs/automation/agent-neuro-kie.t27", "t27b": "pass"}, {"path": "specs/automation/agent-provider-chain.t27", "t27b": "pass"}, {"path": "specs/automation/agent-spec-bank.t27", "t27b": "pass"}, + {"path": "specs/automation/app-tabs.t27", "t27b": "pass"}, {"path": "specs/automation/ball-board.t27", "t27b": "pass"}, {"path": "specs/automation/ball-grants.t27", "t27b": "pass"}, {"path": "specs/automation/blog-share.t27", "t27b": "pass"}, @@ -369,6 +370,7 @@ {"path": "specs/fpga/secded.t27", "t27b": "pass"}, {"path": "specs/fpga/simulator.t27", "t27b": "pass"}, {"path": "specs/fpga/stdlib.t27", "t27b": "pass"}, + {"path": "specs/fpga/systolic.t27", "t27b": "pass"}, {"path": "specs/fpga/ternary_isa.t27", "t27b": "pass"}, {"path": "specs/fpga/ternary_link.t27", "t27b": "pass"}, {"path": "specs/fpga/testbench/assembler_tb.t27", "t27b": "pass"}, @@ -442,7 +444,9 @@ {"path": "specs/igla/coder/benchmark.t27", "t27b": "blocked", "blocker": "ExprIdentifier(undeclared)", "reason": "unimplemented"}, {"path": "specs/igla/coder/dataset.t27", "t27b": "blocked", "blocker": "ExprIdentifier(undeclared)", "reason": "unimplemented"}, {"path": "specs/igla/coder/eval.t27", "t27b": "blocked", "blocker": "ExprIdentifier(undeclared)", "reason": "unimplemented"}, + {"path": "specs/igla/coder/kill_rule.t27", "t27b": "blocked", "blocker": "ExprCall(undeclared fn)", "reason": "unimplemented"}, {"path": "specs/igla/coder/pipeline.t27", "t27b": "blocked", "blocker": "ConstDecl(slice)", "reason": "unimplemented"}, + {"path": "specs/igla/coder/preflight.t27", "t27b": "pass"}, {"path": "specs/igla/coder/prm.t27", "t27b": "pass"}, {"path": "specs/igla/coder/ternary_gemm_gpu.t27", "t27b": "pass"}, {"path": "specs/igla/coder/tokenizer.t27", "t27b": "pass"}, @@ -1107,6 +1111,7 @@ {"path": "specs/port/trinity/src/wasm_stubs/auto_shard_stub.t27", "t27b": "pass"}, {"path": "specs/port/trios-railway/bin/seed-agent/src/main.t27", "t27b": "pass"}, {"path": "specs/port/trios-railway/crates/trios-igla-race/src/asha.t27", "t27b": "pass"}, + {"path": "specs/port/trios-railway/crates/trios-igla-race/src/bin/reset_queue.t27", "t27b": "pass"}, {"path": "specs/port/trios-railway/crates/trios-igla-race/src/ema.t27", "t27b": "pass"}, {"path": "specs/port/trios-railway/crates/trios-igla-race/src/invariants.t27", "t27b": "pass"}, {"path": "specs/port/trios-railway/crates/trios-igla-race/src/race.t27", "t27b": "pass"}, From 94e05184cf7f6f3e2908c48d4b0d63f732e966b0 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 03:51:37 +0700 Subject: [PATCH 11/11] ledger: t27b row for specs/analog/sar_comparator.t27, UNLISTED 1 -> 0 (Refs #10649) Same row as #10650 on master, so this PR's ratchet goes green first. 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 3cea06144b..6b9fd7ba0d 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"},