Files
ironclaw/tests
jinxin 9fd1e638a6 feat(inspector): complete statistics, navigation, and localization (#7291)
* feat(inspector): add operator inspection API

* docs(inspector): assign product service ownership

* test(inspector): ratchet diagnostic contracts

* feat(inspector): add debug panel shell

* test(inspector): cover debug panel shell e2e

* fix(inspector): stop diagnostics when panel closes

* feat(inspector): add prompt inspection

* fix(inspector): follow current webui ownership

* feat(inspector): add model call statistics

* test(inspector): cover model statistics e2e

* fix(inspector): avoid uncollected tool metrics

* test(inspector): cover prompt diagnostics e2e

* test(inspector): align statistics e2e scope

* fix(inspector): redact prompt metadata

* fix(inspector): preserve per-call model identity

* fix(inspector): classify prompt instruction sources

* test(inspector): assert reported token usage

* feat(inspector): add activity timeline and turn navigation

* test(inspector): cover activity timeline in browser

* fix(inspector): read current run before publishing activity

* feat(inspector): add bounded tool execution details

* test(inspector): cover bounded tool details in browser

* fix(inspector): validate retained tool result sizes

* test(inspector): add security and operator coverage

* test(inspector): cover browser workflows end to end

* fix(inspector): address review feedback

* fix(inspector): retry transient snapshot failures

* fix(inspector): address prompt diagnostic review findings

* fix(inspector): follow debug query navigation

* feat(inspector): complete frontend diagnostics

* test(inspector): cover frontend parity in browser

* fix(inspector): preserve stream terminal state

* fix(inspector): capture full capability surface

* fix(inspector): scope projection activity to its run

* fix(inspector): harden activity diagnostics

* fix(inspector): bound tool result diagnostic capture

* fix(inspector): harden tool diagnostic pipeline

* fix(llm): request usage for NEAR AI streams

* fix(inspector): address prompt diagnostic review feedback

* fix(webui): harden inspector stream coverage

* fix(inspector): preserve debug session statistics

* fix(inspector): keep diagnostics active while hidden

* test(e2e): cover hidden inspector observation

* fix inspector model call stats review findings

* fix inspector refresh and truncation regressions

* fix(inspector): address activity timeline review feedback

* fix(inspector): harden activity lifecycle handling

* fix(composition): move tool diagnostics to loop host

* fix(inspector): keep a settled stream live and complete locale parity

A live diagnostic update's debounced snapshot refresh was announcing LOADING,
so an open, healthy stream read as "Connecting" indefinitely once a run
settled — the settling stats update is the last one. That refresh is now a
background read. Incomplete snapshot statistics no longer accumulate as real
zeros, browser-session inspector state is namespaced by the authenticated
caller, an evicted pinned run rejoins the latest turn instead of the oldest,
tool status is localized, and the inspector strings now cover all ten locales.

* test(inspector): put the inspector locale sidecar under the parity gate

The inspector's English copy is registered from its lazy chunk instead of
src/i18n/en.ts, so the all-locale parity test — which derives the required key
set from en.ts — never covered those keys; a locale could drop one and fall
back to English silently. The test now treats the English key set as the union
of en.ts and a declared sidecar list. Keeping the copy in en.ts is not an
option: measured, it puts /chat at 217.4 KB gzip against a 217.0 KB budget.

* fix(inspector): reject malformed model breakdowns and correct locale copy

A `calls_per_model` entry with a negative or non-integer `calls` passed the
statistics decoder and was then coerced to zero during accumulation without
marking the breakdown truncated, presenting a fabricated "0 calls" for a model.
Every entry is now validated before a record is accepted. German turn
navigation used "Zug" (a train, or a game move); it now reads "Runde", with the
determiner agreement that noun requires. Spanish and Portuguese tool-status
values were written feminine against a masculine "Estado"/"Status" label.

* fix(inspector): bound the model breakdown before scanning and retaining it

The statistics decoder validated every calls_per_model entry but never the
array length, so an out-of-contract response was scanned in full and then
retained by the accumulator for up to 128 runs. The host truncates this
breakdown at MAX_MODELS_IN_STATS and reports it as truncated, so a longer
array cannot conform; the client now mirrors that ceiling and rejects the
record before the scan.

* fix(inspector): align turn navigation with host diagnostic retention

The browser offered 32 turns of navigation per thread while the host retained
diagnostics for 2 runs per session, so every turn past the second rendered
blank. Each layer was individually correct and the e2e scenario stopped at two
turns, so nothing saw the dead zone. Retention moves to 4 and the navigation
window mirrors it, pinned by a new architecture gate that reads both constants;
the scenario now walks back two turns and asserts real activity. Retention is a
ceiling as well as a default, and capture is unconditional, so 4 is a resident
memory choice — roughly 80 MB worst case across the eight tracked sessions.

* fix(composition): delimit the i18n bundle guard with an i18n-owned marker

The guard sliced the concatenated chunk bundle from the i18n provider up to
`QueryClient`, a symbol another module owns, so the segment's extent tracked
Rollup's chunk boundaries. A split that merely folded react-query into the
entry chunk removed that marker from everything appended after the provider and
failed an i18n guard with no i18n change. It now ends on the AVAILABLE_LANGUAGES
literal that follows the provider in the same module; string literals survive
minification, and every existing assertion holds against the tighter segment.

* fix(architecture): resolve the inspector gate's SPA path through crate_path

The gate joined a family-nested literal onto the workspace root, the idiom
crate_path exists to replace: a crate family move would have turned this into a
read failure rather than a resolved path. It now names the SPA file in the
logical flat spelling and resolves it, and the assertion reports the resolved
path so the message still points at a file that exists.

* test(inspector): follow a pinned turn explicitly when a new turn arrives

The multi-turn scenario assumed the panel would jump to an arriving turn, but a
selection the operator navigated to is deliberately sticky: the new turn widens
the window without yanking them off the turn they are reading. The scenario now
asserts that guarantee, then clicks Latest to follow, then walks back two turns
as before. Verified by running the inspector scenarios locally rather than by
reading, which is how this slipped through the first time.
2026-08-10 06:12:10 +00:00
..