# Test plan, coverage and verification record

## Verification record for 0.6.10

Local run: **2026-10-12**, macOS, Node **26.8.2**, Pi **1.1.0**, Claude Code
**2.1.296**, with tmux available. `npm run test:all`: **1,013 Node tests passed,
0 failed, 0 skipped**, followed by **48 native Claude plugin tests passed,
0 failed**. Plugin validation and generated shared-copy parity passed. Every
model response came from a synthetic local fixture; no paid model calls or
private prompt history were used.

`npm run test:coverage` also passed all **1,013 tests**, with no failures/skips:
**96.31% lines, 90.04% branches, 93.22% functions** for its configured CLI,
shared/Pi `.mjs`, bridge and script file set. These totals do not instrument the
native Mods `.js` or Pi's TypeScript entry point. A local documentation checker
passed **207 relative links/anchors** and all four reciprocal README language
pairs.

Verified offline regression coverage:

- Both input and output use the same preflight literal spans for language
  decisions and request masking. Certain bare Chinese filenames, paths and
  literal-like identifiers/settings/mentions must reach the translator as
  placeholders and restore with exact source bytes and occurrence counts.
- Literal-only input/output skips before translation calls and logs, including
  bare `报告.md`, `./文档/报告.md`, `用户表_v2`, `LABEL=中文` and `@张三`.
  Ambiguous prose remains model-visible, quoted Chinese prose takes the input
  translation path, plain `OK` output translates, and the existing Chinese
  technical-label skips remain intact. Verify this through Pi, both Claude
  backends and the generated in-plugin scanner.
- Each fresh input translation or output part needing translation gets one
  completion, without an AI audit or repair call. Completed/nonempty fixture responses with remaining
  Chinese input or no Han in output must not be rejected for language, including
  native Claude and joined long answers. Literal content must never cause a
  language rejection. This acceptance is not evidence of semantic quality.
- Structural failures still block input and leave original answers intact:
  incomplete/empty responses, missing/duplicate native terminal markers,
  missing/damaged/duplicate placeholders and reordered protected input blocks.
  Long-part failure stops sibling work; cancellation prevents late publication.
- Cache keys remain exact source plus scanner/prompt contract; the bumped
  contract isolates old versioned entries. Nonempty current and unversioned
  candidates receive source-literal byte/count checks only, not order, language
  or semantic checks. Literal-changing entries cause a fresh translation.
- Successful Pi originals remain journal/cache-only until real user-message
  delivery, then appear once after the user row. Exercise delayed-tool steer and
  follow-up queues, duplicate prompts/events, exact images, ambiguous originals,
  bypassed input, discard, navigation/reload, immediate failures and persistent
  ordering. No display entry may inject context or request another turn.
- Claude's real TUI is driven through tmux: Up/Down restore Chinese across
  multiple history entries, plugin reload, resume and a new session. Unchanged
  recall replays the saved English with no translation call even with automatic
  cache off; editing the source makes one fresh call. Typed English that happens
  to match a translation is untouched. Main requests contain no display originals.
  Pure matching tests cover ambiguity, intervening edits, bounds and replay
  selection; bridge tests cover older contracts, no-persistence mode, Input off,
  cancellation, current language suffixes and source-literal integrity.
- Generated shared-copy parity and both adapters' failure/cancellation and
  display/context boundaries pass. Claude's already synchronized prompt-row
  display remains unchanged; only Pi's early original-card timing changed.

The [documented reproduction commands](#reproduce) remain the release check.
`node --test scripts/release-policy.test.mjs` passed **24 tests**; `bash -n
Hooks/translator/install.sh` and `git diff --check` passed. Candidate/merged
release-policy validation and archive integrity are recorded in the release PR.

### Evidence boundaries

The Pi queue fixture uses a real SDK delayed tool while steer/follow-up prompts
wait, checking event and persisted row/card ordering, images, duplicate events,
discard, reload and ambiguous originals. Pi exposes no queue-item correlation
ID: conflicting sources/bypasses or host-normalized content omit a card rather
than guessing. Older cards are not retroactively moved.

The Claude terminal fixture exercises native arrow navigation, source editing,
replay, typing, mid-turn messages and reload/resume against the real 2.1.296 TUI.
The composer API has no history-navigation event: restoration uses a short local
poll only while a terminal draft and known originals exist, without replacing
arrow bindings. Missing/ambiguous original records remain unchanged. The test
verifies programmatically delivered tmux keys, not a person's terminal setup.

LSP diagnostics were **tree-sitter syntax only**, not TypeScript type checking.
The Node and native plugin suites provide runtime/host evidence. No live-model
quality evaluation, minimum-host-version retest, or manual
mobile/desktop visual acceptance is claimed for this release.

## Verification record for 0.6.9

Local run: **2026-10-11**, macOS, Node **26.10.0**, Pi **1.1.0**, Claude Code
**2.1.296**. `npm run test:all`: **860 Node tests passed, 0 failed, 1 skipped**
(the real Claude terminal test: tmux is not installed), plus **47 native Claude
tests passed**. Plugin validation and generated shared-copy parity passed.

- The initial focused regressions reproduced **12 failures** with the previous
  output-name rules. The new `language-gates.test.mjs` passes **51 tests** for
  Chinese artifact/storage summaries, exact technical labels, real English
  counterexamples, input bypass, unchanged literal protection and long near-matches.
- The real Pi SDK and real Claude binary (both backends) run with **input and
  output enabled**: the synthetic English input is sent unchanged with no suffix,
  Chinese deliveries make no translation request, and input/output journals stay
  byte-identical. Adding an English sentence still translates. Claude's native
  tests also cover the skipped-answer fallback with `OK`, `Mermaid` and `Token`
  as the final text row.
- `npm run test:coverage`: **860 passed, 0 failed, 1 skipped**; raw V8 coverage
  **93.65% lines, 90.06% branches, 93.26% functions**, with the jiti attribution
  caveat described below.
- Release-policy unit tests: **24 passed**. `bash -n install.sh`,
  `git diff --check`, and **207 local documentation links/anchors** across the
  Translator and repository guides passed. `npm pack --dry-run` includes **44
  files**, matching package/plugin versions, and no tests or private runtime data.

These are local checks, not CI or hosted-model quality measurements. No paid
model calls were made. Unknown plain-word names remain conservative translation
triggers; this patch adds a bounded, case-sensitive output exception, not a
universal language classifier. Input cache contracts and literal masking are
unchanged. GitHub publication does not imply npm registry publication or an
upgrade of an already installed/running extension.

## Verification record for 0.6.8

Local run: **2026-10-11**, macOS, Node **26.10.0**, Pi **1.1.0**, Claude Code
**2.1.296**. `npm run test:all`: **809 Node tests passed, 0 failed, 1 skipped**
(the tmux-dependent Claude terminal test), plus **47 native Claude tests passed**;
plugin validation and shared-copy parity passed. The new real-Pi gateway bypass
regression fails on the previous entry point (`Prompt NOT sent`) and passes with
the process opt-out. Release-policy unit tests: **24 passed**. `bash -n install.sh`,
`git diff --check` and `npm pack --dry-run` passed (44 files, no runtime data).
These are local release checks, not live service or phone acceptance. This
GitHub release does not include npm registry publication. No paid calls or real
WeChat messages were used.

## Verification record for 0.6.7

Local run: **2026-10-10**, macOS (Darwin), Node **26.8.2**, Pi **1.1.0** and Claude
Code **2.1.296**.

| Check | Result |
|---|---|
| `npm run test:all` | **809 Node tests + 47 native Claude tests passed, 0 failed, 0 skipped**; plugin validation and shared-copy parity passed. This includes the real Pi SDK integration, now with a long answer whose parts reach the local model at the same time, and the real `claude` binary with both backends |
| `npm run test:coverage` | 809 passed; raw V8 report: **96.58% lines, 89.91% branches, 93.26% functions** |
| Regression evidence | On 0.6.6 a local model whose response time grows with its text cannot translate a 6,669-character answer within a 400 ms `timeoutMs` (`Translation timed out`, one request); 0.6.7 translates it in four parts at once. Both Pi status checks in `pi-output.test.mjs` fail on 0.6.6: the status line stayed on |
| Real answers | The two answers that timed out in local Pi journals (7,035 and 21,543 characters) cut into 4 and 11 parts of at most 2,000 characters, and each joins back byte for byte |
| `node --test scripts/release-policy.test.mjs` | 24 passed |
| `bash -n install.sh`, `git diff --check` | Passed |
| Packed npm tarball | `npm pack --dry-run`: 44 files with matching 0.6.7 manifests; no tests, config or history |
| Documentation | Local links and anchors in the Translator documents (141 links) and the repository's root documents (70 links) checked |

Only the shared core, the Pi output handler, their tests and the documents changed;
Claude Code's native backend still translates an answer in one request. The Pi
tests were not repeated on Pi 1.0.4, nor the Claude host tests on Claude Code
2.1.292. How fast a hosted model translates parts was not measured, and
`npm run eval:live` was **not** run because it makes paid calls.

All model responses in automated tests are **local fixtures**, not hosted model
calls. The real installed host binaries/SDK are used, but their model requests go
to local HTTP servers. Fixtures supply dummy keys; tests do not parse or copy
credential files.

### Earlier records

| Date | State | Hosts | Result |
|---|---|---|---|
| 2026-10-10 | 0.6.6 release (drawing in the Claude Code desktop app) | Pi 1.1.0, Claude Code 2.1.296 (whole suite also on 2.1.293, desktop test on 2.1.294) | 797 Node + 47 native tests passed, none skipped; raw coverage 85.3% lines, 89.8% branches, 93.2% functions; the packed tarball held 44 files and installed into a temporary prefix and home |
| 2026-10-10 | 0.6.5 release (the `pi-package` npm keyword only) | Recorded in [PR #21](https://github.com/Orbit-Labs-AI/orbit-tools/pull/21) | 795 Node + 39 native tests passed, none skipped; the packed tarball held 44 files with matching 0.6.5 manifests |
| 2026-10-09 | 0.6.4 release | Pi 1.1.0 (Pi tests also on 1.0.4), Claude Code 2.1.295 | 795 Node + 39 native tests passed; raw coverage 90.6% lines, 89.6% branches, 93.0% functions; a real Pi 1.1.0 terminal showed single-language Markdown cards; the packed npm tarball installed into a temporary prefix and home |
| 2026-10-09 | 0.6.3 release | Pi 1.1.0, Claude Code 2.1.295 | 788 Node + 39 native tests passed; raw coverage 84.3% lines (V8 jiti attribution), 89.8% branches, 92.7% functions; 45 of the 788 updated tests failed on 0.6.2; both language checks stayed under about 80 ms on 100,000-character inputs; the packed npm tarball installed into a temporary prefix and home |
| 2026-10-09 | 0.6.2 release | Pi 1.1.0 (Pi tests also on 1.0.4), Claude Code 2.1.294 (Claude tests also on 2.1.292) | 763 Node + 39 native tests passed; raw coverage 83.6% lines, 89.7% branches, 92.4% functions (V8 merged the jiti-loaded Pi panel poorly; 93.9% lines without the two new real-host files); the packed npm tarball installed into a temporary prefix and home |
| 2026-10-09 | 0.6.1 release | Pi 1.1.0 (Pi tests also on 1.0.4), Claude Code 2.1.294 (Claude tests also on 2.1.292) | 751 Node + 34 native tests passed; coverage 90.05% lines, 89.69% branches, 92.58% functions; the packed npm tarball installed into a temporary prefix and home |
| 2026-10-08 | 0.6.0 release (then `prompt-translate`) | Pi 1.0.4, Claude Code 2.1.292 | 546 Node + 30 native tests passed; coverage 92.20% lines, 88.68% branches, 93.16% functions; the packed npm tarball installed into a temporary prefix and home |
| 2026-10-08 | 0.6.1 in development: unified settings, compact Pi panel, literal whitelist | Pi 1.1.0 (Pi tests also on 1.0.4), Claude Code 2.1.294 | 594 + 33, then 604 + 34, then 751 + 34 tests passed |

Review findings from those runs were reproduced with failing tests before they
were fixed. The Pi panel's shifted `?`, a search that reset a pinned model and
an offset in mouse edits are examples, as is invalidating Pi translations before
a branch change and withdrawing Claude cancellation before publication.

## Reproduce

From `Hooks/translator/`:

```sh
npm test
npm run test:claude
npm run test:all
npm run test:coverage
npm run check:shared
bash -n install.sh
```

There are no npm runtime dependencies to install. Tests use temporary directories,
HOME/config overrides, local HTTP servers and fake executables. Claude may
regenerate its ignored `.claude-plugin/types/` declarations. Tests do not alter
personal translation config/history or register hooks in the real user's home.
Read-only smoke checks additionally confirm that existing local registrations
need no changes; package installation checks use isolated temporary homes.

Pi integration normally discovers its managed SDK; set `PI_SDK_PATH` to the
installed `dist/index.js` if needed. Claude integration requires `claude` on PATH.
Missing hosts cause **explicit skips** in the Node suite: a skipped host must not
be claimed as tested. `test:claude` / `test:all` need Claude actually installed.

`KEEP_TRANSLATION_TEST=1 node --test test/claude-integration.test.mjs` keeps the
temporary transcripts/debug logs for investigation. They contain only fixture
prompts/responses but should still not be committed.

## Coverage scope and interpretation

The coverage command includes:

- `shared/*.mjs`;
- `pi/*.mjs`;
- `claude-code/bridge.mjs`;
- `scripts/*.mjs`;
- public `cli.mjs`, `control.mjs`, `import-history.mjs`.

The reload-safe Pi entry now evaluates local implementations through jiti. V8's
path-based report combines native modules and jiti-transformed scripts with the
same filenames; these are raw script metrics, not fully source-mapped coverage.
Individual percentages can also fluctuate between runs (notably the widget), so
they are not directly comparable to the earlier native-import-only percentages.
The live-upgrade TUI test additionally runs a temporary copy of the source, which
is outside the original-path coverage scope.

Selected raw V8 line figures from the 0.6.1 run:

| Module | Lines |
|---|---:|
| Shared translation core | 97.26% |
| Shared literal scanner | 93.55% |
| Shared feature names, defaults and parsing | 91.53% |
| Shared file-update helpers | 100% |
| Shared history | 96.97% |
| Pi history / trace / subprocess backend / model selection | 100% each |
| Pi input handler / output handler | 96.51% / 97.17% |
| Pi settings panel | 98.73% |
| Pi controls / toggle widget (jiti raw-script caveat above) | 68.16% / 8.22% |
| Claude Node worker | 98.99% |
| Public CLI / history importer | 100% each |
| Public config command | 92.31% |
| Installer implementation | 88.15% |

The Pi controls and widget line figures are raw-script numbers affected by the
jiti caveat above; the same run reports 77.00% and 100% of their branches.

Coverage is **not** a percentage of all host behavior. Pi's TypeScript entry and
Claude's sandboxed JS are validated by real-host/native tests outside these V8
module metrics. Installer CLI tests execute a copied checkout in a temporary
home, so those executions are not attributed to the original source path's
coverage. The numbers are neither a translation-quality score nor proof of
exhaustively testing all external API / operating-system failures.

## Functional test matrix

For 0.6.10 this matrix is a **behavior contract and test-location map**, not a new
verification result. Changed preflight, completion, long-part and cache checks
remain pending as listed above; earlier passing runs do not prove the new
expectations. Unchanged host scenarios below describe the existing fixture scope.

### Shared translation and data protection

| Behavior / failure | Test locations (0.6.10 results pending) |
|---|---|
| Chinese input and mixed answers are translated; entirely English input, entirely Chinese output, empty text and extension input bypass | `core.test.mjs` |
| Literal-only input and output, including certain bare Chinese filenames, paths, identifiers/settings/mentions, skip without translation calls or logs; English input that only names Chinese resources passes through; quoted Chinese prose remains translatable | `core.test.mjs`, `bridge.test.mjs`, `literals.test.mjs`, `literal-edge-cases.test.mjs`, adapter/native tests and real-host fixtures |
| Whitelist only: a masked span never swallows prose (glued URLs and paths, closing tags, `和/或`, a lone slash after Chinese as in `项目/Orbit`); uncertain spans go to the translator | `literals.test.mjs`, `literal-edge-cases.test.mjs`, `hard-prompts.test.mjs` |
| One completion per input/output part; no AI audit or repair call and no language or semantic recheck of drafts/restored text; completed/nonempty fixture echoes or output without Han are accepted if literal safety holds; literal content cannot trigger language rejection | `core.test.mjs`, `bridge.test.mjs`, `literals.test.mjs`, `output-parts.test.mjs`, native Claude tests and both real-host integrations |
| Hard corpus: Chinese mixed with URLs, paths, code, formulas, symbols, JSON, HTML, tables, quoted UI strings and an injection, through every host path | `hard-prompts.test.mjs` (all cases), `corpus-hosts.test.mjs` (real Pi SDK and `claude` CLI sample) |
| Preflight skips output with no English prose to translate, including literal-only output; English prose, including slash-joined words and `_emphasis_`, still translates; acronyms, camelCase names, flags, versions, dotfiles, mentions, links/paths and exact technical labels (`Markdown`, `Mermaid`, `Downloads`, `Token`, `Tokens`) do not make an otherwise Chinese answer English; plain `OK`, `Mermaid` or `Token` output still translates; literal-only input bypasses even unreadable config | `core.test.mjs`, `literals.test.mjs`, `language-gates.test.mjs`, `pi-input.test.mjs`, `pi-output.test.mjs`, `bridge.test.mjs`, native Claude tests and both real-host integrations |
| Synthetic Chinese artifact deliveries and storage summaries, including Markdown links/tables, labels, CRLF, long text and punctuation, skip with no completion/config/history/trace/UI work; exact spelling only, no arbitrary Titlecase or Chinese-ratio shortcut; appended English still translates; both modes enabled in real Pi and both Claude backend fixtures, with unchanged English input, unchanged Chinese output and byte-identical journals; Claude's last-row fallback does not retry a skipped answer whose last row alone reads as English | `language-gates.test.mjs`, `fixtures/language-gates.mjs`, adapter tests, native Claude tests and both real-host integrations |
| Shared preflight leaves ambiguous prose visible: Han glued to Latin letters or tied to names by `：` or `、`, ambiguous Han-ending links/paths, sentence-length mentions, Chinese email local parts and slash/`#`-joined prose are not swallowed as one literal; conservative matching and long-input performance remain regression requirements | `literals.test.mjs`, `hard-prompts.test.mjs`, `language-gates.test.mjs` |
| Exact non-overlapping preflight spans shared by both directions' gates and masking; byte-for-byte restoration of certain code, filenames (including bare Chinese), paths, Markdown targets, math and literal-like identifiers/settings/mentions; uncertain content stays model-visible | `literals.test.mjs`, `literal-edge-cases.test.mjs`, `bridge.test.mjs`, adapter and real-host fixtures |
| Fullwidth path brackets, apostrophes/angle destinations, next-line reference titles, deeper indented code, quoted prose and custom/self-closing HTML tags | `literal-edge-cases.test.mjs` |
| Claude uses the same scanner without forbidden cross-plugin imports; stale generated mirrors fail tests | `layout.test.mjs`, `npm run check:shared`, native Claude tests |
| Spelling/grammar/typo and unambiguous-fragment correction policy; no rephrasing/guessing | Prompt-contract assertions in `core.test.mjs` |
| Exact code, fences, inline code, CRLF, URLs and paths; same-line triple-backtick spans do not consume later prose | `core.test.mjs`, `cli.test.mjs`, `bridge.test.mjs`, `audit-regressions.test.mjs` |
| Missing, duplicated or damaged literal markers, reordered code blocks, identical repeated literals, Unicode/escape mutations and fabricated markers; inline literals may move for English word order | `core.test.mjs`, `literals.test.mjs`, `bridge.test.mjs` |
| Empty, incomplete, tool-only or failed responses are rejected; remaining Chinese in input or missing Han in output alone is not a failure | `core.test.mjs`, `bridge.test.mjs` |
| Deadlines and cancellation, including providers ignoring AbortSignal | `core.test.mjs`, `pi-output.test.mjs`, `output-parts.test.mjs`, `backend.test.mjs` |
| Long answers use up to four concurrent parts, each needing translation gets one completion/deadline; short answers keep one untrimmed request; cuts preserve blocks, lines, masked literals, spacing and indentation; preflight skips source parts with no English prose, including literal-only parts; response/placeholder failure stops siblings and names the part without repair; cancellation stops all parts; joined output has restoration safety but no language/semantic requirement or audit call; usage adds up | `output-parts.test.mjs`, `pi-output.test.mjs`, real Pi SDK and Claude Pi-backend fixtures |
| Config types/ranges/model pairs/backend selection/thinking levels | `core.test.mjs`, `bridge.test.mjs` |
| Translator follows the current session or a branch/session/file pin; independent thinking applies to both directions; explicit follow clears file pins; a missing model blocks uncached input | `bridge.test.mjs`, `claude-code/tests/translation.test.ts`, `pi-input.test.mjs`, `pi-output.test.mjs`, `backend.test.mjs`, both real-host integrations |
| No source execution, tools, main history or hidden thinking in translation | Core assertions, backend tests and both real-host integrations |
| Display control-character sanitizing; complete bilingual text in previews, only the Chinese in Pi's cards | `preview.test.mjs`, `pi-card.test.mjs`, real Pi renderer assertions |

The correction-policy assertions prove that the intended prompt is supplied.
They deliberately do **not** pretend that mocked completions demonstrate a real
model's ability to detect every linguistic mistake.

### Cache, controls, persistence and CLI

| Behavior / failure | Test locations (0.6.10 results pending) |
|---|---|
| Exact whitespace-sensitive matching and rule-version isolation; model/thinking/backend choice remains outside the cache key | `features.test.mjs`, `shared/history.mjs` cache contract |
| Cross-store refresh, no double-counted usage, suffix applied after reuse | `features.test.mjs`, `bridge.test.mjs` |
| Failed/empty/obsolete entries rejected; equality to source alone is not a rejection reason; torn and non-record JSON recovery | `control.test.mjs`, `audit-regressions.test.mjs`, `features.test.mjs` |
| Legacy import idempotence and original session bytes unchanged | `features.test.mjs`, `entrypoints.test.mjs` |
| Nonempty current and unversioned cache candidates receive only source-literal byte/count integrity checks, not order, language or semantic rechecks; a literal-changing result triggers fresh translation and an accepted replacement is reusable; the bumped scanner/prompt contract isolates old versioned entries | `literals.test.mjs`, `literal-edge-cases.test.mjs`, `features.test.mjs`, `bridge.test.mjs` |
| Pi active branch, abandoned branch exclusion, no-session memory | `features.test.mjs`, Pi integration |
| Every global mode: on/off/toggle/default/status, unknown fields/permissions | `control.test.mjs` |
| Concurrent control processes retain independent changes and toggle order, including config symlink aliases | `control.test.mjs`, `file-update.test.mjs` |
| Invalid global command arguments do not modify config | `control.test.mjs` |
| Language suffix, input/output independence, branch/session settings restoration, new-session defaults and unchanged shared config | Both real-host integrations, `features.test.mjs`, `pi-controls.test.mjs`, `claude-safety-regression.test.mjs` |
| Only `/translator` registered; no-argument native five-option panel; strict status/help, switch, model and thinking subcommands; no cancellation command | `pi-controls.test.mjs`, `pi-widget-integration.test.mjs`, `claude-safety-regression.test.mjs`, native Claude tests |
| Write-ahead original before request, durable failed first input | `trace.test.mjs`, real Pi integration, `bridge.test.mjs` |
| New journal/cache file permissions and no-persistence behavior | `trace.test.mjs`, `features.test.mjs`, `bridge.test.mjs` |
| CLI help, JSON/plain output separation, exit codes, no fallback text | `cli.test.mjs`, `entrypoints.test.mjs` |
| Public modules import from stdin/eval without executing main or resolving `-` as a file | `audit-regressions.test.mjs` |
| Source through stdin, all isolation flags, model override, no shell evaluation; real CLI wire excludes synthetic global APPEND_SYSTEM and ancestor instructions | `backend.test.mjs`, `fixtures/fake-pi.mjs` |
| Subprocess stderr privacy, invalid protocol, oversized output, process abort | `backend.test.mjs` |

The audit also tightened `translator status`: stray arguments now fail
instead of being silently accepted.

### Pi-specific functionality

- Process-local automation bypass (`pi-gateway.test.mjs`): real JSON/print CLI,
  synthetic task/cron/peer prompts and a localhost provider that rejects any
  translation. Enabled saved branch overrides, unavailable translation pins and
  malformed config cannot block the original task or delay its English answer.
  Another extension still runs; settings and prior branch records remain intact;
  no translation journal/cache is created. With the bypass absent or `0`, the
  same gateway-looking input is still translated and fails closed. This checks
  the Translator contract, not the live WeChat service or phone delivery.
- Real SDK loads **the installer-generated registration**, following its stable
  source symlink, with no duplicate extension.
- Input replaces only submitted text, preserves images and queue behavior, and
  leaves original text exclusively in non-context records/previews.
- TUI cards show only what the transcript lacks, collapsed or expanded: the
  original after a delivered translated user row (never the English sent), the Chinese
  after an answer (never the English answer), and the reason plus the original
  for a blocked prompt. Rendered with Pi's own components and Markdown theme,
  links, code and lists are drawn as Markdown and every line keeps the card
  background (`pi-card.test.mjs`, `pi-integration.test.mjs`). RPC shows the
  bilingual notification; headless output goes to stderr.
- A three-switch bar mounts below the editor only in TUI mode. Real raw SGR
  press/release/drag sequences run through Pi's fullscreen renderer and actual
  chat-dock layout with an in-memory terminal. A completed click appends exactly
  one mode entry, keeps editor focus/draft, and does not call a model or add
  model-visible messages. The bar stays fixed while the transcript scrolls.
- The only registered slash command is `/translator`. No arguments open the
  native five-option `SettingsList` in TUI mode; RPC/JSON/print report status/help
  without mounting terminal components. Direct input/instruction/output controls,
  model follow/pin and all five thinking values are validated before persistence.
- Panel/command/shortcut/click state stays synchronized without remounting the
  existing bar. Ctrl+Alt+T/L/Y retain their toggles, including inside the panel.
  Native components are exercised for model search, selection, focus/IME cursor,
  requested/effective thinking feedback, compact/default versus contextual-help
  layouts, CSI-u question marks, search selection stability, prompt mouse editing,
  Unicode, theme changes, narrow widths and dismissal back to the editor without
  draft mutation. The panel mounts in the production-style editor slot for raw
  mouse/resize checks. Real tree navigation, reload and disk resume
  restore branch settings; navigation closes the panel and rejects stale callbacks.
- Branch state uses field patches over file defaults, including atomic model
  pairs and explicit null/null follow. Malformed persisted patches are ignored;
  invalid direct arguments and unavailable new pins leave state unchanged.
  Persisted unavailable pins are reported rather than silently replaced.
- Live-upgrade regression: first load a legacy controller via native `.mjs`
  imports, replace the installed source in a temporary checkout, then `/reload`
  in the same SDK process. The new bar must mount despite the old native ESM
  cache. A second source edit/reload must update the widget, controller and nested
  shared defaults. This covers changing code during a running session, rather
  than merely reloading already-current code.
  Tests cover narrow widths/resizing, regular-mode keyboard hints, theme
  invalidation, modified/right clicks, dragging, padding and stale hit targets.
- Environment-disabled input is visibly locked while other modes work. Config
  errors disable stale controls; persistence failures do not optimistically
  change their state. Global defaults refresh at input/agent boundaries. Disposal
  and session replacement invalidate old widgets and callbacks. RPC retains text
  status; JSON/print install no widget.
- Translator model/thinking overrides never change the main model, its thinking
  or shared config. The real SDK inspects isolated input/output requests using a
  pinned reasoning model, requested `max` clamped to `xhigh`, a non-reasoning pin
  with no reasoning option, and follow with `low`; the main request retains its
  own model/level. Pins survive disk resume. Provider, storage, UI, config and
  session-switch failures cannot fail open to the original Chinese prompt.
- Default-follow checks use the session's current model, read per request, at
  translator `thinkingLevel`. The real SDK fixture uses a reasoning-capable model with
  the session at `max`: translation requests carry `reasoning_effort: "medium"`
  while main requests keep the session's own level (`max`, clamped to `high` for
  that model). Unit tests cover clamping and models without reasoning.
- Steering and follow-up input sent while Pi works is translated but has no
  successful display entry or notification while queued. `pi-queue-regression.test.mjs`
  uses a real SDK delayed tool to check both queue modes, once-per-user-row event
  and persistent ordering, cache reuse, discard, reload and ambiguous originals.
  `pi-input.test.mjs` covers exact image bytes, duplicate events, Input off and
  extension bypasses, session/branch invalidation, immediate failures and
  post-delivery display errors. Another real SDK regression steers input during
  a running turn to check cancellation.
- Complete output only: no tool chatter, hidden thinking, non-assistant messages,
  aborted/unfinished turns, duplicate delivery or original-answer mutation.
- 0.6.10 long-answer checks: each part needing translation gets one
  isolated completion, with one record for the answer and a cleared status when
  it ends (`pi-output.test.mjs`, `pi-integration.test.mjs`). Parts reach the local
  fixture concurrently, cut between paragraphs/lines and preserve masked
  literals. Placeholder failure stops siblings without a repair call; neither
  parts nor joined output receive a language or semantic check.
- 0.6.10 preflight checks: the shared scanner excludes the same certain
  literal spans from language decisions and masks them in both directions'
  requests. Literal-only input/output and answers with no English prose to
  translate skip before config, branch history, model, trace or UI work. Real
  SDK fixtures must cover bare Chinese filenames, paths, identifiers/settings/
  mentions, quoted Chinese prose, ambiguous prose and plain `OK` output, plus
  exact filename/link/code restoration. Chinese resources or hidden thinking
  must not suppress translation of English prose. Accepted literal content must
  never trigger a post-translation language rejection.
- Output failure, missing model, cancellation, session switch or UI/storage loss
  retains the already-completed main answer.
- Actual provider requests are inspected before and **after reopening the native
  session file**: neither the original Chinese prose from translated prompts nor
  display-only output notices leak into subsequent model context. Literal bytes
  deliberately remain unchanged, including Han in filenames and paths.
- Failed **first** input is journaled even when Pi never creates a native session.
- Real SDK pending-input tests suspend a local translator response, then reload,
  dispose or replace the runtime. No main request or late entry reaches the new
  context. Getter exceptions in cleanup cannot escape the input handler.
- The registered **Ctrl+Alt+C** shortcut cancels actual translation HTTP requests
  for input, output and both simultaneously. Cancelled input never reaches the
  main model; cancelled output retains the completed answer; subsequent
  translations remain usable. The panel also routes the shortcut while focused.
  Signal-ignoring providers cannot publish late successes. Output cleanup covers
  tree/session identity changes, throwing getters, reload and disposal without
  stale entries, notifications or status clears.
- A separate ordinary `session.abort()` regression, originally named for Pi
  1.0.4, documents the idle-input abort gap rather than successful cancellation.
  Focused evidence is on the installed 1.1.0 SDK; neither test establishes
  physical Escape-key behavior.

Files: `pi-input.test.mjs`, `pi-output.test.mjs`, `pi-integration.test.mjs`,
`pi-controls.test.mjs`, `pi-settings.test.mjs`, `pi-widget-integration.test.mjs`, `features.test.mjs`,
`trace.test.mjs`, `pi-lifecycle-regression.test.mjs`, `pi-queue-regression.test.mjs`.

### Claude-specific functionality

Two real-host end-to-end paths are tested:

1. `claudeBackend: "pi"`: real Claude main requests use an HTTP fixture, while an
   isolated fake Pi executable verifies the legacy translation subprocess flags.
2. `claudeBackend: "native"`: **Pi is explicitly unavailable**. The actual Claude
   completion API makes isolated HTTP requests and the plugin is discovered
   through the **installer-created user skills link**, not `--plugin-dir`.

Both verify prompt rewriting, native system-notice persistence, unchanged main
answers, independently enabled output, cache reuse after resume, failure blocking,
slash-command behavior and absence of bilingual notices from main wire context.
Native requests contain one source message and no tools/history. Default-follow
checks use the session's `--model`, `output_config.effort: "medium"` and a
32000-token cap; the fake Pi executable checks `--thinking medium` by default.
The added real-host settings path pins a different translator and `high` thinking
for both input and output, verifies the actual native requests / Pi worker traces,
then restores follow. It checks unchanged main-model requests and config bytes,
settings restored on resume, and file defaults in a new session.

Worker tests additionally cover session-model selection, file and session pins,
all five thinking overrides in both directions, explicit follow clearing a file
pin, native versus Pi-default follow semantics, malformed session settings and
environment-lock precedence. They also cover fail-closed input without any model,
a restart message for a mod loaded before the update, the original translator
recorded on cache reuse, preparation/finalization, JSON-round-tripped literal
state, per-request terminal markers, missing/duplicate markers, native
API failure/cancellation, expiry, obsolete contracts, wrong sessions, no-persist,
cache-off and global-disable precedence. The 0.6.10 cases additionally
assert one native completion followed by a final `finish` result or failure,
with no second prepared request, language audit or repair call; literal-only
cache integrity must accept nonempty candidates regardless of language.

Claude-native test-kit cases cover malformed/truncated/nonzero worker output,
unknown statuses, six fail-closed input paths, session-model forwarding (including
a switch and an unavailable model), unified command validation, per-session
settings, memory-only settings, subagent/interruption bypass, the native five-option
Pane and its alias/full-ID input, all three retained button actions and declared
hotkeys, native completion dispatch, and output failure with an unavailable UI.
The pane, commands and band are exercised together for immediate synchronization,
model follow and invalid-input rejection without any main-model turn. Pending-only
key 4 is tested on native input and output completions, rejecting late replies
without invoking finish or publishing a translation. Output warnings are
best-effort: even a failed toast cannot break or retry the completed answer.

The 0.6.10 checks exercise preflight with output explicitly enabled:
answers without English prose to translate, including literal-only answers, skip
before model/mode reads or worker startup; mixed prose and plain `OK` translate.
Both backends and the native test kit must cover literal-only input/output with
no translation call/log, quoted Chinese input, ambiguous prose and skipped
`turn.step` answers marked handled even if `turn.complete` carries only a last
row that alone reads as English (`OK`). Both real backend fixtures must inspect
masked requests and exact restoration for certain bare Chinese filenames,
paths, identifiers/settings/mentions, Markdown targets and code in both
directions. Completed/nonempty replies are not language-checked after restoring
those bytes; structural failures still block input or leave the answer intact.

Real HTTP fixtures also return multiple text blocks: their stored message UUIDs
are checked against display-state keys. Native
and Node regression fixtures prove that repeated last rows cannot associate one
answer's whole translation with another, and synthetic fallback uses no text key.

Settings controls are tested with deterministic overlapping panel, command and
button operations in persistent and memory-only modes, failed config/store/
refresh calls, environment locks, invalid syntax and session switches. Per-session
queues retain independent changes, unblock after failure, and never replace the
active session's status or settings through a stale pane/band callback. Evidence:
`claude-safety-regression.test.mjs`, native test kit and real integration.

Cancellation Node regressions cover input/output during worker preparation,
native completion and finish, plus host dispatch signals, `turn.abort` and session
refresh. They check signal propagation, closed worker streams, discarded late
results, no submitted input or drawn/appended output, and no fallback retry.
`claude-cancellation.test.mjs` adds real **2.1.294** output-abort fixtures for both
backends: a test mod calls the supported `$.turn.abort` API while translation is
pending. The original answer remains, no translated output is published, the
native HTTP exchange closes, and the optional Pi child exits when its bridge
stream closes. This tests native abort integration, not physical key routing or
real-host input-stage Escape behavior. No custom global Ctrl binding is installed.

The native test kit's `$.session.append` stub gap was documented on 2.1.292;
real-binary HTTP integration tests cover actual notices and resume instead.

Display rows are tested end to end. The kit tests that the prompt-hint status
and the original drawn under a prompt row come from mod state, never from the
stored row. The real-binary integration checks that the journal's `linkedRow`
for a translated prompt matches the transcript's stored prompt row, and that
`--resume` in a new process draws both the original prompts and the Chinese
answers again.

The desktop app's drawing is tested at three levels. Worker tests read a fixture
transcript under a temporary `CLAUDE_CONFIG_DIR`: an answer's text row gets both
`<message id>-t<n>` counts (its message's text blocks and all its blocks, a row
written twice counted once, an assistant line without a message skipped), a
`queued_command` row its `source_uuid`, a prompt row and any other attachment no
id, and a row the transcript does not hold yet is reported missing. Of two copies
of a transcript the newer is read, also through a linked workspace. Native kit
cases mount rows on the `desktop` surface: a row showing the original is handed
the prompt as sent, while a terminal row, a row already showing the English and a
longer prompt are left alone; an answer under the app's id is drawn only under
the block showing exactly the linked row's text, not under one whose text is part
of it; the first remote draw asks for the journal's rows once and the terminal
never asks; rows restored with a remote surface attached get its ids then, with
no second pass; a failed pass is tried again by a draw 30 seconds later; with a
remote surface attached, a folded prompt and an answer are asked for as soon as
they are linked, and again after 500 ms while the transcript does not hold the
row, while a prompt stored as its own row is not asked for.
`claude-desktop.test.mjs` runs the real binary in the SDK's stream-json form,
attaches as `desktop` and asks for rows with the props and ids the app uses, live
and after `--resume`, a folded prompt drawn both from the English and from the
app's Chinese copy. On 0.6.5 it fails at its first check: the app's prompt row
comes back as the Chinese.

Prompts sent mid-turn and reloads of the mod are tested at three levels. Node
regressions load two copies of the module against one fake host, the way Claude
Code reloads it: a step in the old copy and `turn.complete` in the new one
translate an answer once and draw it under the reply row the new copy stored; a
copy replaced before it translated still gets its answer drawn; a reply row of an
earlier turn is never used; waiting originals and memory-only settings survive.
They also cover a waiting translation matched only on whole lines, suppression
of an unlinked/queued UI row even when its text matches, and a dropped prompt
being forgotten. Success notices wait for the stored row too; failure notices
remain immediate. Native kit
cases raise the real `queued_command` row by doors `delivery` and `attachment`,
and a prompt row stored after its turn began. `claude-live-session.test.mjs` and
`claude-tui.test.mjs` run the real binary, as described in the verification
record.

### Installer and directory structure

| Scenario | Expected result / test |
|---|---|
| Neither host present | Nonzero error; no config, registration, directory or backup writes |
| Only Pi / only Claude present | Automatic selection; other agent's directories remain absent |
| Both present | Interactive Pi/Claude/both/cancel choices; non-TTY requires explicit choice |
| `--agent pi`, `claude`, `both`; `--yes` | Selected available hosts only; missing requested host fails |
| Old/unknown versions; invalid flags/choices | Reject before applying changes |
| Managed executable paths and non-executable files | Proper discovery; shell-visible broken install is not silently bypassed |
| Help / dry run | No installation writes, including personal config and backups |
| Paths containing spaces / unrelated CWD | Node and shell entry points work |
| Custom config dirs and alternate/shared Claude skills | Honor CLI/env locations; preserve directory symlinks |
| Existing symlinked Pi settings | Update target, keep link, retain unrelated settings |
| Existing config/history/extensions | Preserve content/preferences; backup exact old settings bytes |
| Reinstall | No duplicate entries, no extra backups or operations |
| Legacy Pi root paths | Migrate/deduplicate to `pi/index.ts`; no root hook shim |
| Conflicting files/directories/dangling links | Preflight abort; neither selected host partially installed |
| Invalid settings/config schemas | Error without replacing original bytes |
| Late filesystem exception | Roll back this run's links/files/settings/empty directories |
| Settings changed after planning or while preparing temp/backup files | Late baseline comparison rejects detected changes instead of overwriting them |
| Pi settings lock compatibility, including symlinked settings | Real Pi 1.0.4 FileSettingsStorage interoperability with deterministic process barriers |
| Rollback fails due to an external write | Preserve external content and the original backup; report its exact recovery path |
| Missing Node | Shell entry reports dependency error, no modifications |
| Layout invariants | Pi/Claude sibling directories, one Pi manifest entry, valid relative imports, clone config stays put |
| npm packaging | Stable external data directory, npx-cache refusal, every runtime helper/scanner included, no personal data/tests/generated host declarations |

Files: `install.test.mjs`, `layout.test.mjs`, `package.test.mjs`, plus both real-host integrations.

## Explicitly not claimed as verified

- Real hosted-model translation quality, typo detection, ambiguous intent or
  guaranteed resistance to all prompt injection. Those require curated live
  evaluations and may incur model charges. Latency and cost of particular session
  models at a given `thinkingLevel` are likewise not measured.
- A complete Markdown/HTML/shell parser or infallible classification of arbitrary
  unwrapped strings. Shared preflight masks only documented, certain syntax and
  names; ambiguous prose stays model-visible, and instructions for unmasked text
  are not a byte-integrity proof. Use backticks for exact strings. Language
  decisions run only before translation: a doubtful source costs a translation
  call rather than being skipped. There is no post-translation language/semantic
  gate or AI audit/repair, including for native Claude, long parts and joined
  output. Completed/nonempty responses with valid literal restoration may still
  contain untranslated or inaccurate prose. Literal content cannot trigger
  language rejection, and cached text receives source-literal byte/count checks
  only, not a language or semantic recheck.
- How fast a hosted model translates a part of a long answer, how many requests
  a provider serves at once before limiting them, and whether two parts word a
  term the same way. The parts are tested with a local model whose response time
  grows with its text; the timings that motivated them come from local journals
  of real translations, not from a measured benchmark.
- Production provider credentials, billing, real network outages, organizational
  policies, or every future Pi/Claude release. No paid calls were made here.
- Physical keyboard/mouse/terminal-specific input reporting, all visual layouts,
  every terminal emulator, or hidden UI bands. Pi's fullscreen renderer/layout
  and raw SGR mouse routing are tested programmatically through an in-memory
  terminal, and the Claude Code terminal test sends keys to the real TUI through
  tmux; neither is a hardware or visual compatibility check on every terminal.
- Linux execution on a separate machine, the exact minimum Node version, Windows
  installation (explicitly unsupported), or arbitrary network filesystem behavior.
- Power loss, forced process kill halfway through installation, every possible
  disk/permission failure, or a globally coordinated multi-installer transaction.
  Rollback is tested for caught application/filesystem errors. Locks coordinate
  cooperating processes only: no OS CAS against arbitrary editors, no guarantee
  for unknown symlink aliases or Pi's first-create read-before-lock race. Crashed
  owners can leave locks requiring manual inspection.
- Reliable ordinary Pi SDK/RPC abort during idle input preprocessing, or physical
  Escape-key cancellation in either host. Pi cancellation evidence invokes the
  registered Ctrl+Alt+C handler against the real SDK and routes programmatic keys
  through its native panel. Claude evidence includes native button actions for
  input/output and real-host `turn.abort` during output in both backends, not a
  guarantee that a physical key reaches an abort in every UI/dispatch phase.
  Bare Pi SDK disposal blocks late writes but may leave the translator running
  until completion/timeout.
- Claude's special synthetic no-provider-step transcript flush edge case. The
  normal `turn.step` output path is verified; the fallback sidecar is durable but
  native-notice persistence there remains host-dependent.
- The Claude Code desktop app's own painting and its exact naming of rows. The
  tests send the asks the app sends, with the props and ids seen in its logs and
  transcripts on 2.1.293, and check what the session answers. How the app paints
  that answer, which of the two counts of `n` in `<message id>-t<n>` it uses (both
  are covered), and the Claude mobile app and VS Code extension, which also draw
  remotely, are not tested.

These boundaries matter: broad offline coverage and real host loading are useful
regression evidence, not a promise that every external environment is identical.
