Skip to content

feat: t27_dashboard -- session dashboard for the agent and the operator, graded by dashboard.t27 - #19

Merged
gHashTag merged 2 commits into
masterfrom
t27mcp-dashboard
Oct 18, 2026
Merged

gHashTag merged 2 commits into
masterfrom
t27mcp-dashboard

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

What

t27_dashboard is a session dashboard for both the agent and the human operator. It shows:

  • Corpus: the commit, the spec count, and the ok/warn/fail split.
  • This session: calls, errors and the largest reply, per tool.
  • Next step: one line chosen by the spec.
  • Server: version, tool count and site.
  • Not known here: what the server's own data cannot tell (the seal frontier, test receipts, CI state), so that a blank reads as unknown and not as absent.

The grades are ok/unknown/warn/bad, and unknown never adds up to ok.

The logic lives in the spec gHashTag/t27#10249 (specs/t27mcp/dashboard.t27), compiled to wasm/dashboard.wasm, with its tables and templates in wasm/dashboard_table.mjs. dashboard.mjs only counts calls and fills the templates.

Where it shows

  • Claude Code / CLI agents: the tool returns one line, and the path of the HTML page written to tmpdir.
  • Claude desktop chat (MCP Apps): the tool carries _meta.ui.resourceUri = ui://t27/dashboard. The server declares resources, and answers resources/list and resources/read with text/html;profile=mcp-app and a fresh page.

Evidence

  • Stdio smoke against the live manifest. It ran initialize, t27_find, an unknown tool, a t27_spec call that throws, t27_dashboard, resources/list, resources/read and tools/list.
    • Result: 19 tools, _meta present on t27_dashboard, and the failed call counted.
    • Reply line: t27 MCP bad | corpus at 1d9c5960d: 2402 specs, 2032 ok, 257 warn, 113 fail (warn) | session: 2 calls, 1 errors, largest reply 769 bytes (ok) | next: A tool call failed ...
  • The page was rendered and checked in a browser.
  • Spec: 8 of 8 tests pass, 0 vacuous, and six mutants are caught. See the wasm/BUILD record, which carries the sha256 of the source, the wasm and the table.
  • JS added: dashboard.mjs 40 lines, server.mjs +28.

Found on the way, not fixed here: t27_spec with no arguments throws a TypeError ("reading 'toLowerCase'") instead of a typed error.

Refs gHashTag/t27#10066

🤖 Generated with Claude Code

…or, graded by dashboard.t27

The logic lives in gHashTag/t27 specs/t27mcp/dashboard.t27 (gHashTag/t27#10249),
compiled to wasm/dashboard.wasm with its tables in wasm/dashboard_table.mjs. It
grades corpus health, this session's calls and the largest reply, and picks the
next step. dashboard.mjs only counts calls per tool and fills the spec's
templates.

- tools/call records each call's reply bytes, and whether it threw, in the ledger.
- t27_dashboard returns one line for the agent and writes the HTML page to tmpdir
  for the operator.
- The same page is served as the MCP Apps resource ui://t27/dashboard: the tool
  carries _meta.ui.resourceUri, and the server answers resources/list and
  resources/read and declares the resources capability.

Stdio smoke: 19 tools. A failed t27_spec call is counted, and the session is
graded bad with the "a tool call failed" next step.

JS added: dashboard.mjs 40 lines, server.mjs +28.

Refs gHashTag/t27#10066

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tri-claw

tri-claw Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Summary by t27-bees

This PR adds t27_dashboard, a session dashboard tool showing corpus health, per-tool call/error/reply stats, a graded next step, server info, and explicit "not known here" items. The grading logic lives in a WASM module compiled from specs/t27mcp/dashboard.t27; dashboard.mjs only counts calls and fills templates. The server now also implements MCP resources/list and resources/read so MCP Apps hosts can render the same HTML page.

Worth a look

  • dashboard.mjs:11 — Top-level await WebAssembly.instantiate(...) loads dashboard.wasm at module import. If the file is missing, corrupted, or the WASM exports don't match, the entire server fails to start (no graceful fallback).
  • dashboard.mjs:13 — ledger is a module-level Map shared across all sessions/connections. The dashboard presents "this session" data but actually aggregates across the whole process lifetime; concurrent operators see each other's calls.
  • server.mjs:767–780 — Every tools/call is now wrapped in a try/catch that calls noteCall before re-throwing. If noteCall itself throws (e.g., ledger access error), the original tool error is preserved but the dashboard ledger may be left in an inconsistent state.
  • dashboard.mjs:31 — String(m.error) on a caught Error object yields "Error: message", then only <>&' are escaped. The result is embedded in the agent text line (not HTML), so XSS risk is low, but the error text could contain newlines or control characters that break the one-line format.
  • dashboard.mjs:38 — writeFileSync(file, html) to tmpdir() has no error handling. Permission errors, disk full, or path issues will throw uncaught from dashboard(), crashing the tool call and leaving no page for the operator.

Read: 7 files, +156 -5, the whole diff. Head cec86e7. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

…unt before the catch

Review points on #19:
- A manifest that cannot be fetched is shown with its error in the commit field
  ("unknown, manifest: fetch failed ..."). It is no longer a silent unknown.
  The tool and the resource now share one dash() helper.
- The page file name carries the process id, so two servers that share tmpdir
  do not overwrite each other's page.
- A successful call is counted inside the try block, so a reply that cannot be
  measured is counted as a failed call instead of throwing past the ledger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag

Copy link
Copy Markdown
Owner Author

Addressed in cec86e7:

  • Fixed page name: the file is now t27-mcp-dashboard-<pid>.html. Within one server, a newer page of the same session replacing the older one is intended. Two servers sharing tmpdir no longer collide.
  • Swallowed manifest error: the error is now shown in the commit field, for example unknown, manifest: fetch failed (after 3 attempts: ...). I checked this against an unreachable T27_SITE.
  • byteLength after the try: the success count moved inside the try block. A reply that cannot be measured is now counted as a failed call.

Not changed:

  • Ledger growth: noteCall runs only for names found in byName, because an unknown tool throws before it is reached. The ledger therefore holds at most one entry per registered tool (19).
  • The dashboard call itself: its reply size is not known until the page is built, so it cannot count itself. It appears on the next dashboard call, like every other call.

@gHashTag
gHashTag merged commit 76374f4 into master Oct 18, 2026
2 checks passed
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