Skip to content

spec(t27f): spec_graph_view -- the graph view, a deterministic layout of a spec graph (Closes #10034) - #10049

Merged
gHashTag merged 1 commit into
claude/affectionate-mahavira-86b04dfrom
claude/t27f-spec-graph-view
Oct 17, 2026
Merged

gHashTag merged 1 commit into
claude/affectionate-mahavira-86b04dfrom
claude/t27f-spec-graph-view

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #10034

Stacked on #10029 (specs/t27f/spec_graph.t27, the core graph IR, not merged yet): this PR's base is that branch, so the diff shows only the view. Merge #10029 first; GitHub then retargets this PR to master.

What

specs/t27f/spec_graph_view.t27 (module t27f_spec_graph_view) is the first T27F view of a spec's own graph, not of a topic map. A SpecGraph becomes numbers that a host draws, the way reel.t27 gives a host the numbers of a reel frame. Nothing in this PR draws pixels or writes markup.

  • Columns (FR-001). One column per node kind present, in a fixed order: module, use, const, fn, test, invariant, bench, opaque. Empty columns are dropped. The fixture has 7 columns because bench is absent.
  • Label-driven style (FR-002). Width, height, fill, stroke, dash and row order come from the inference label. Exact and derived boxes are 220x44, suggested and unknown 200x36, centred in the column. Only EXACT is drawn solid, with derived, suggested and unknown dashed 6/3/2. A label the view cannot read is drawn as UNKNOWN.
  • UNKNOWN alone (FR-003). UNKNOWN nodes sit in a band 48 px below the deepest known box, and no edge end lands on them. On the fixture, std.testing is at (1610, 408), with 0 edge ends.
  • Source lines (FR-004). Every edge carries a source line. A DERIVED tested_by edge has no line of its own and points at the line of the calls edge it is read back from (79, 84, 89).
  • Widgets (FR-005). Each node's widget is spec_graph's node_widget, unchanged.
  • Verdict (FR-006). The view returns VIEW_OK. A graph that validate_graph refuses keeps that code. An edge with no line to point at is refused with VIEW_ERR_EDGE_NO_LINE = 19, the first code after spec_graph's 0..18.
  • Host entry points (FR-008). 26 scalar fx_* functions, because a wasm export carries scalars only. Fixture 0 is tutorial_08_graph, 1 is with_suggestion, and any other number is the blank graph, which the view refuses. An index past the graph returns 0.

.claude/skills/t27f/SKILL.md ("What exists") and the specs/OWNERS.md t27f row each gain the new row.

Lab numbers (Railway, ~/t27-lanes/fs-lab.sh; nothing built or run on the Mac)

Lab tree: the #10029 head 9d1d2c8, with this file shipped by base64 tar.

Check Result
sha256 local / lab / committed 54ad20408cb50a1f4fbe18981019f7ba4f13b87fa7f6940449e38b4479bf35e6 (3 of 3 equal)
t27c test-report tests 8, pass 8, FAIL 0, BLOCKED 0, vacuous 0 of 8
t27b test --check 8 PASS lines, 0 FAIL
Fixture layout 15 of 15 nodes placed; 16 of 16 edges with a source line; 0 overlapping boxes; 0 edge ends on the UNKNOWN node; canvas 1860 x 484
Spec negative controls edge into the UNKNOWN node -> ERR_EDGE_UNKNOWN_NODE; tested_by with no call behind it passes validate_graph but the view refuses it with 19; blank graph -> ERR_SPEC_PATH

Mutation controls, each run by sed on the lab copy and then restored. The final sha256 equals the original.

# Mutation t27c t27b
1 no UNKNOWN band 4 FAIL 4 FAIL
2 tested_by gets no line from its call BLOCKED (invariant the_fixtures_are_drawn fails at compile time) 5 FAIL
3 style ignores the label 5 FAIL 5 FAIL
4 column order swaps const and fn 4 FAIL 4 FAIL
5 derived drawn with the exact fill BLOCKED (invariant label_styles_are_distinct_and_centred) 1 FAIL

MCP t27f_view glue: measured, not written

t27f_view lives in gHashTag/t27-mcp, not in this repo, and its two PRs (gHashTag/t27-mcp#3, gHashTag/t27-mcp#4) are still open.

I measured what a spec view would take there, in a scratch directory on the lab with nothing committed:

  • t27c gen of this file gives 1039 lines of Zig.
  • With export.zig changed by +2/-1 lines (the module added, the dedupe widened to the second module, a comptime branch quota), zig build-exe ... wasm32-freestanding gives a 16523-byte wasm.
  • The wasm exports all 26 fx_* entry points, and demo_* from reel and deck is still there.
  • A host would then need about 22 lines in a new spec-view.mjs (one rect per node, one line per edge, kind name plus L<start>-<end> as text, because strings cannot cross wasm) and about 6 lines in server.mjs.
  • Total: about 30 added hand-written foreign lines. That is under 40 per file and 80 per PR, with no new logic, since every number comes from this spec.

It is not written. Two rules stop it:

  1. Foreign code only shrinks (specs/policy/own_language.t27, owner rule 2026-10-09). Over the whole diff, foreign files may not gain more lines than they lose. These ~30 lines would delete nothing.
  2. No new hand-written non-t27 code in any gHashTag repo. The rule is to park and report.

Either the owner approves those lines, or they are offset by deleting at least as many hand-written lines, or the host side waits for a generated JS backend that emits bodies (gen-js emits constants only today). Until then there is no SVG of tutorial 08 drawn through the MCP tool.

Not claimed

  • t27c has no graph exporter yet, so the only graphs laid out are spec_graph's two hand-read fixtures.
  • Edges are straight lines with no routing around boxes.
  • No host draws this view yet.

🤖 Generated with Claude Code

… of a spec graph (Closes #10034)

The first T27F view of the core graph IR rather than of a topic map: a
SpecGraph becomes numbers a host draws, as reel.t27 does for a reel frame.
One column per node kind present; size, fill, stroke, dash and row order
from the inference label; UNKNOWN nodes alone in a band with no edge end
on them; every edge with a source line (a derived tested_by edge points at
its call); widgets through spec_graph's node_widget; graphs validate_graph
refuses keep its code, and an edge with no line is refused with code 19.
Scalar fx_* host entry points for the two hand-read fixtures.

Lab (Railway): t27c test-report 8/8, 0 vacuous; t27b --check 8 PASS;
5/5 mutation controls fail on both tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag merged commit 3456f62 into claude/affectionate-mahavira-86b04d Oct 17, 2026
23 of 27 checks passed
gHashTag added a commit that referenced this pull request Oct 17, 2026
… (#10059)

#10049 merged into the already-merged #10029 branch instead of master,
so its files never reached master. This is the same squash commit
(3456f62), cherry-picked cleanly onto current master.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant