Skip to content

Semantic Output, first phase: test and build readings in their blocks (#386) - #415

Merged
raiseCatError merged 3 commits into
devfrom
feature/v021-semantic
Oct 18, 2026
Merged

raiseCatError merged 3 commits into
devfrom
feature/v021-semantic

Conversation

@raiseCatError

Copy link
Copy Markdown
Owner

Stacked on #414 (/edit) → #413 → #412 → #411. Merge in order.

What

Deterministic, post-completion readings of recognized output (src/output/semantic.ts). Each recognizer accepts only its own unmistakable evidence and fails closed; counts are the ones the tool printed, and items are verbatim lines (at most 20, plus a count).

Recognizer Evidence
Node's test runner spec ℹ tests/pass/fail or TAP # tests/pass/fail; failures from the failing-tests section or not ok (TODO/SKIP excluded)
Jest, Vitest, pytest their own summary lines; ● / FAIL / FAILED items
cargo test test result: lines, summed per binary
go test only from go test; ok / FAIL package lines and --- FAIL: tests
TypeScript, Rust, GCC/Clang their diagnostic formats; only from build commands or failed commands, so a successful rg error is never read as a build

Presentation (semanticRows.ts, derived rows like fold hints)

  • Overview row: one row in the block's output area, e.g. ✔ node --test · 1,772 passed · 0 failed · 25 skipped. Safe glyphs +/x, and readable with NO_COLOR.
  • Details row: shown when failures or diagnostics are listed. It starts open when the raw output is folded (that is what the fold hides) and closed when the output is expanded. Click the row, or use Actions → Show or hide details. The reader's choice is kept per block, independent of Ctrl+O.
  • When nothing is shown: short passing output (under 10 lines), unrecognized output, Ask blocks and agent blocks.
  • Never touched: stored transcript lines, raw folding, find, drag-selection and plain /copy. Derived rows are skipped by find and selection. Readings are cached per record and never persisted; a resumed transcript reads them again lazily.

Copy

  • /copy --raw (default), --semantic and --both. These are mutually exclusive, not allowed with --report or ui, and combine with every selector.
  • --semantic and --both copy directly; without a selection they take the latest output.
  • A record without a reading is copied raw, once, and the note says so.
  • --both puts the raw output and the reading under labelled ── NMSh · … ── separators.

Settings

Settings → Transcript → Semantic Output (On by default). It is also reachable from Setup's Transcript section.

Not in this phase

  • External providers (jc, delta).
  • A fully collapsed raw section.
  • A separate semantic search scope.

These are recorded in the design doc.

Tests

  • semanticOutput.test.ts (10 tests):
    • one realistic fixture per tool, plus fail-closed cases (incomplete summaries, look-alikes from non-build commands, unrelated output);
    • bounds and deduplication, and reading from the end of large output;
    • presentation: rows come before the output, stored lines are unchanged, search ignores them, details follow the raw fold until toggled, and Off draws raw only;
    • the usefulness gate, /copy flag parsing, and the semantic and both payloads.
  • semanticOutputLive.test.ts: a real PTY draws the overview and the listing in the block; /copy --semantic copies the reading and /copy latest the raw output, through a stand-in clipboard.
  • Updated audits: block-action registry, and Setup coverage for the new row. 154 output, settings and copy files plus 37 copy files are green.

Not verified

Physical terminal checks: docs/testing/v021-physical-qa.md, section 4, not run.

Refs #386, #410

…#386)

A completed block whose output a recognizer is sure of gets one overview row
with the counts the tool printed and, when it listed failures or diagnostics,
a details row that opens them (verbatim lines, at most 20 plus a count).
Recognizers: Node's test runner (spec, TAP), Jest, Vitest, pytest, cargo
test, go test, TypeScript, Rust and GCC/Clang diagnostics (diagnostics only
from build commands or failed ones). Short passing output gets nothing.

Readings are derived per record, never stored: the transcript lines, raw
folding, find, selection and plain /copy are unchanged, and derived rows are
skipped by find and selection. Details start open when the raw output is
folded; a click on the details row or Actions -> Show or hide details toggles
them. /copy --semantic and --both copy the reading (raw once for an output
without one, said in the note). Settings -> Transcript -> Semantic Output.
A security review found patterns that could backtrack quadratically on
crafted output (trailing-whitespace stripping, the Jest summary, TAP
directives, GCC/TypeScript location prefixes), and recognition runs when a
block is first drawn. Lines over 2,048 characters are no longer read, trailing
whitespace is removed with trimEnd, and those formats are parsed with string
operations and end-anchored bounded patterns. A test runs eight adversarial
outputs (up to 2 MB each) and bounds each one's time; behavior is unchanged.
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