Uh oh!
There was an error while loading. Please reload this page.
fix(inspector): close the follow-ups left on the trace panel - #2041
Conversation
Astro-Han
left a comment
There was a problem hiding this comment.
Nice to see this round land. The three items from the approving review are handled: the per-run catch covers the corrupt-event-row class, the hook now renders in a real suite, and the empty change stops the panel from claiming "nothing to trace" next to a gap report. Two things I found on top:
P2: corrupt run headers still fail the whole trace, one layer above the new catch
readSessionTrace wraps only readRunEvents (inspector-ipc-main.ts:46-63). The Promise.all over readSessionRuntimeEvents and listSessionRuns above it (:38-40) still rejects as a whole. In the real wiring (boot.ts:1210), listSessionRuns runs listSessionRunsForRecovery (agent-run-store.ts:333-348), which JSON.parses and normalizes every header row with no per-row catch: one corrupt header rejects the list, and retry hits the same row forever. That is the same failure class this PR removes for event rows, at a reachable layer. The missing-header ENOENT the new catch covers only occurs in the narrow race where a header disappears between list and read; the comment at inspector-ipc-main.ts:45-46 names that narrower case.
Options: per-row tolerance in the storage layer (it changes listSessionRunsForRecovery's contract for the recovery callers at boot.ts:557,877,947), or an explicit deferral in the PR body. Right now "one unreadable run no longer fails the whole trace" is true for only one of the two read legs. Not a merge blocker, but the claim is wider than the implementation.
P3: re-activation behavior has no test pin
The four hook tests assert subscription and read counts only. None renders a snapshot, and none goes active→hide→active. Reverting load(sessionId, true) to false passes the suite unchanged, so the one behavioral change this PR makes in the hook is unpinned. An active→hide→active sequence asserting the previous trace survives would cover it.
P3: unreadableRecords doc says "could not decode", the counter now also counts unread runs
core/session-trace.ts and the projection input doc describe records that fail to decode, but the run-level catch feeds the same counter. Update both comments to "read or decode". The unit mixing (one run counts as one gap) reads fine as a floor, but the doc should not promise decode-only.
P3: preserveTrace is a dead parameter
All three call sites pass true; the false branch is unreachable. Drop it or say why it stays.
P3: 'zh' | 'en' restates UiLocale
The injected copy types locale as a literal that duplicates UiLocale from @maka/core. A third locale will drift here; use UiLocale.
P3: housekeeping
- PR body says 25 desktop inspector tests; the four suites count 24 (ipc 5, panel model 6, hook 4, refresh 4, workbar layout 5).
as neverremains atinspector-ipc-main.test.ts:135,145.FakeElementis imported but unused inui-render-memo-boundary-contract.test.tsafter the extraction.flushRefreshhardcodes 450ms againstTRACE_REFRESH_DEBOUNCE_MS = 400; export the constant so the two cannot drift.
Second review round on apache#2041. The P2 is the same shape as the defect this PR set out to fix, one layer up — and my PR body claimed more than the code delivered. `readSessionTrace` catches per run, but the `Promise.all` above it does not. `listSessionRunsForRecovery` (`agent-run-store.ts:333`) parses every header row with no per-row tolerance, so one corrupt header still rejects the whole trace, and retry hits the same row forever. Fixing that belongs in storage, where it changes the contract every recovery caller depends on — a decision about recovery, not about this read model. Stated in the code and in the PR body rather than quietly half-fixed. Docs corrected to match: `unreadableRecords` counts records that could not be **read or decode**, and a whole unreadable run counting as one is documented as a floor, since nothing is known about how many records it held. Re-activation now has the test it lacked: reverting the preserve behaviour passed the old suite unchanged, which made it an unpinned behavioural change. The new one asserts that once a trace has arrived no later render goes back to nothing, and it fails when the preservation is removed. Housekeeping from the review: `preserveTrace` was dead at every call site and is gone; the injected copy takes `UiLocale` instead of restating it; `TRACE_REFRESH_DEBOUNCE_MS` is exported so the test's delay derives from it rather than duplicating 400 as 450; the IPC test types its stub against `IpcMain['handle']` instead of casting past it; and the extracted `FakeElement` import is dropped from the suite that no longer uses it. 25 desktop inspector tests, projection 18/18; a11y, dead-css, copy, console and format checks clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ARE404
commented
Aug 4, 2026
All correct. P2 — you're right, and the claim was mine to get wrong. I verified Taking the deferral, not the storage change: per-row tolerance there alters what P3 re-activation had no pin — confirmed by reverting it. The preserve behaviour passed the old suite unchanged, which is exactly the "unpinned behavioural change" you describe. The new test asserts that once a trace has arrived no later render goes back to nothing, and I checked it fails when the preservation is removed. Writing it also caught that my first assertion was wrong for a different reason (the mount and its loading frame legitimately have no trace yet), so it now anchors from the first frame that has content. P3 docs — Housekeeping, all taken: |
The three substantive suggestions from apache#2018's approving review, plus its nits. **One unreadable run no longer fails the whole trace.** `readRunEvents` had no per-run catch, so a corrupt row or a run whose header went missing turned every `inspector:trace` into `INSPECTOR_TRACE_FAILED` — and retry hit the same row forever. A read failure is just another way a record can be unreadable, which is the rule this projection is built on; a failed run now folds into `unreadableRecords` as one counted gap rather than a guess at its size. **The hook has the regression test the original defect deserved.** The P2 in the last round was a doc comment describing a subscription that did not exist, and the fix landed without a test that could catch that class. Four now render the hook for real: subscribe only while active, unsubscribe on hide, one read per closing burst, no read for streaming deltas, and no read at all after the panel hides. Verified they fail with the subscription removed. Two things made that possible. The fake DOM in `ui-render-memo-boundary-contract.test.ts` moved to `fake-dom.ts` so a second suite can render without duplicating it — I had wrongly concluded this repo had no hook-test idiom, having searched only for `renderHook`. And `useSessionTrace` now takes its copy as an argument instead of reading the locale context, so the one hook whose comment outran its code is renderable without the UI package behind it. **A reported gap is never an empty session.** With every record undecodable the panel showed "Nothing to trace in this session yet" beside "N unreadable records" — opposite claims, and the second is exactly what this surface exists to show. Nits: the IPC join test now asserts something only the runtime-event ledger can satisfy (it passed with that ledger empty); the projection suite pins `unreadableRecords`, which only the IPC test referenced; re-activation preserves the timeline rather than blanking it, matching the file's own rationale; the coverage notice renders the turn counts it computes; and the recovery label is localized instead of leaking English into the zh UI. Deferred, unchanged: unbounded per-activation reads and timeline virtualization want a paging contract over the trace, not a patch here. 25 desktop inspector tests, `@maka/core` 755/755, projection 18/18; a11y, dead-css, copy, console and format checks clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second review round on apache#2041. The P2 is the same shape as the defect this PR set out to fix, one layer up — and my PR body claimed more than the code delivered. `readSessionTrace` catches per run, but the `Promise.all` above it does not. `listSessionRunsForRecovery` (`agent-run-store.ts:333`) parses every header row with no per-row tolerance, so one corrupt header still rejects the whole trace, and retry hits the same row forever. Fixing that belongs in storage, where it changes the contract every recovery caller depends on — a decision about recovery, not about this read model. Stated in the code and in the PR body rather than quietly half-fixed. Docs corrected to match: `unreadableRecords` counts records that could not be **read or decode**, and a whole unreadable run counting as one is documented as a floor, since nothing is known about how many records it held. Re-activation now has the test it lacked: reverting the preserve behaviour passed the old suite unchanged, which made it an unpinned behavioural change. The new one asserts that once a trace has arrived no later render goes back to nothing, and it fails when the preservation is removed. Housekeeping from the review: `preserveTrace` was dead at every call site and is gone; the injected copy takes `UiLocale` instead of restating it; `TRACE_REFRESH_DEBOUNCE_MS` is exported so the test's delay derives from it rather than duplicating 400 as 450; the IPC test types its stub against `IpcMain['handle']` instead of casting past it; and the extracted `FakeElement` import is dropped from the suite that no longer uses it. 25 desktop inspector tests, projection 18/18; a11y, dead-css, copy, console and format checks clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
41c4bb5 to
78f7a2bCompareARE404
commented
Aug 4, 2026
Rebased onto The conflict was in I've reverted the extraction. That file is now byte-identical to Re-verified after the rebase: 25 desktop inspector tests, projection 18/18, |
`@maka/core/ui-locale` is not in core's export map, so the desktop main build could not resolve it. Every other renderer file imports the type from the package root; this one now does too. It typechecked locally because this worktree resolves the subpath through the built `dist` regardless of the export map. CI builds from the map, which is the honest surface — a second reminder that a local typecheck here is weaker evidence than it looks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Astro-Han
commented
Aug 4, 2026
An independent look at the current head matches the review thread, with one boundary the deferral comment leaves half-explained.
Two optional notes:
None of these block merge. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
The three substantive suggestions from #2018's approving review, plus its nits. Refs #1625.
One unreadable run no longer fails the whole trace.
readRunEventshad no per-run catch, so a corrupt row — or a run whose header has gone missing — turned everyinspector:traceintoINSPECTOR_TRACE_FAILED, and retry hit the same row forever. You put it exactly right: a read failure is just another way a record can be unreadable, which is the rule this projection is built on. A failed run now folds intounreadableRecordsas one counted gap rather than a guess at its size.The hook has the regression test the original defect deserved. The P2 last round was a doc comment describing a subscription that did not exist, and the fix landed without a test that could catch that class. Four now render the hook for real — subscribe only while active, unsubscribe on hide, one read per closing burst, no read for streaming deltas, no read after the panel hides — and I confirmed they fail with the subscription removed rather than trusting that they would.
Two things made that possible, and one of them was my mistake to begin with: the fake DOM moved from
ui-render-memo-boundary-contract.test.tsintofake-dom.tsso a second suite can render without duplicating it. I had concluded this repo had no hook-test idiom, having searched only forrenderHookand testing-library. Thanks for the correction.useSessionTracealso takes its copy as an argument now instead of reading the locale context, so the hook is renderable without the UI package behind it — which matters here, since@maka/uidoes not build in my worktree and a test I cannot run is how theResulttypo reached CI.A reported gap is never an empty session. With every record undecodable the panel showed "Nothing to trace in this session yet" beside "N unreadable records" — opposite claims, and the second is precisely what this surface exists to show.
Nits, all taken
unreadableRecords, which only the IPC test referenced.Still deferred
Unbounded per-activation reads and timeline virtualization. Still a real limit; the fix is a paging contract over the trace rather than a patch here, and I would rather do it deliberately.
Verification
25 desktop inspector tests,
@maka/core755/755, projection 18/18.check-a11y,check-dead-css,check-copy,check-consoleandformat:checkclean. Renderer and main typechecks clean for every touched file.🤖 Generated with Claude Code