Closes #171#182
Conversation
The webview's session-scoped singletons (feed, block/card DOM, summary/board, archive path, metrics) are created once and never cleared, so a second session in the same app run inherited the first's state: session 1's transcript blocks reappeared under session 2's live captions, and — worse — openReview() builds its coaching list from feed.micUtterances(), which still held session 1's own utterances, so session 2's post-meeting review could rewrite lines spoken in the previous meeting. latestArchivePath could likewise show session 1's saved path. Add FeedState.reset() (clears blocks/ids/partials/keys/eviction in place) and a resetSessionState() in main.ts that clears every session-scoped singleton — feed + its blockEls DOM, feedCoalescer, shimmerEl, atBottom, pendingCards/ analysisCards + their DOM, and summaryLine/latestSummary/latestBoard/ latestArchivePath/pendingMetrics. It runs at the transition INTO a new session (idle→starting|live, guarded so pause/resume and starting→live don't re-clear), NOT on Stop — so the just-ended session's review keeps the data it captured. requestCounter stays monotonic (unique card ids); coachingCards live on the review surface (dismissed at the same boundary); channels is re-seeded per start. Regression test drives start → feed content (mic+them, pin, translation, live partial) → reset → asserts a clean feed: no blocks, no leftover mic utterances, no pins, no stale ids, counter reset. Full app suite green (150 tests), typecheck + lint + build clean. No new deps; no caption content logged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: NOT REVIEWED
Structural gate failed before code review.
Checked (evidence)
- Live PR body contains filled
## EPIC Alignmentand## Self-Verificationsections. - UI structural requirement:
## Design Fidelityis prose, not the required table.
Findings
- [P1] Required Design Fidelity table is missing
- File: PR body,
## Design Fidelity - Why it fails: this webview-facing change must provide the required table so the reviewer can verify design/state coverage. Narrative text cannot be spot-checked row-by-row and does not satisfy the template.
- Do instead: replace the prose with a table covering the affected empty/idle feed, pinned dock, cards, and summary states, each with a source pointer and a statement that no layout/token/animation behavior changes.
- File: PR body,
Decision
Add the required table and re-request review; no code review has been performed.
RE2 — APPROVE at PR #182 head (pending
|
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: PASS
The one-file webview-state reset plus FeedState model reset advances #171 without touching the reserved #178/#179 files.
Checked (evidence)
- Structural gate: live PR body now has filled alignment/self-verification sections and a six-row Design Fidelity table.
- Design table spot-check: the cited reset paths match
src/main.ts:1091-1113; no CSS/layout/token/animation changes appear in the live diff. - Reset behavior:
src/main.ts:1091-1129clears the model, DOM/maps, coalescer, and review inputs only on a non-active → starting/live edge. - Feed model:
src/feed-state.ts:54-67clears blocks, ids, partials, render keys, and eviction count in place. - Riskiest part of this diff: stale session data crossing the start boundary; the runtime reset covers it, but the required scalar/review-state regression proof is absent.
- Kill-list: scanned new ranges — clean.
- CI:
gh pr checks 182→ app-macos, color-guard, no-stub-gate, packages-linux all pass.
Findings
- [P1] Regression coverage omits required summary, board, and archive-path reset
- File:
test/session-reset.test.ts:29-91 - Why it fails: all three tests call only
FeedState.reset(). They never executeresetSessionState()or assertsummaryLine,latestSummary,latestBoard, orlatestArchivePath; therefore they do not cover #171 AC’s start → feed content → stop → start with clean summary/board and no stale archive path. The PR body explicitly labels those runtime resets as inspection-only. - Do instead: add a testable reset-state seam (or DOM/Tauri test harness) that drives the status transition and asserts those four review/UI values are cleared alongside the feed.
- File:
Decision
The runtime code and fidelity documentation are aligned, but the stated regression acceptance criterion is not yet tested end-to-end enough to approve.
…sted Address RE1 P1 on PR #182: the regression test proved feed.reset() but not the scalar accumulators (summaryLine/latestSummary/latestBoard/latestArchivePath/ pendingMetrics), so #171's start→stop→start reset was unproven for the review inputs. Group those five session-scoped model values into a new DOM/Tauri-free SessionScope (src/session-scope.ts) with a reset() seam. main.ts holds one `scope` instance and references scope.<field>; resetSessionState() now calls scope.reset() for the model half (feed stays a const cleared via feed.reset(); the block/card DOM clearing is unchanged and remains DOM-coupled). Tests: SessionScope.reset() is unit-tested end to end — populate the summary, board, archive path, and metrics (what openReview reads), reset, assert all cleared; plus a fresh-board (no shared-reference bleed) case and a combined feed+scope start→content→stop→start test mirroring resetSessionState's model half. Full app suite 153 tests green; typecheck, lint, build clean. No new deps; no caption content logged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Epic Alignment: PASS
The #171 fix resets session-bound webview data at the new-session edge and now test-covers both the feed and review-state models without expanding into reserved files.
Checked (evidence)
- Re-review delta:
8de4d3a421d820184b8e69b279103e91e3055d31..2226e1d7f066a897d973800713d51f68ad64e4df. - Reset wiring:
src/main.ts:1080-1104callsscope.reset()with the existing feed/DOM cleanup at the guarded new-session boundary. - Review-state model:
src/session-scope.ts:26-41resets summary line, summary, a fresh board, archive path, and metrics. - Regression coverage:
test/session-reset.test.ts:94-160proves those values and the feed clear together on the modeled start → content → stop → start flow. - Design Fidelity: live PR table spot-checked against
src/main.ts:1091-1113; no CSS, layout, token, or animation changes in the diff. - Riskiest part of this diff: stale review inputs surviving between sessions; the new
SessionScopeseam is exercised directly and wired to the runtime reset. - Kill-list: scanned new ranges — clean.
- CI:
gh pr checks 182→ app-macos, color-guard, no-stub-gate, packages-linux all pass.
Findings
- None.
Decision
The prior test-coverage gap is resolved, and the scoped reset behavior is supported by live green CI.
RE2 — APPROVE at
|
Closes #171
Reset every session-scoped webview singleton when a new session starts, so a second session in the same app run no longer inherits the first's feed, cards, summary/board, or archive path.
EPIC Alignment
Part of EPIC #134 (v1.3 audit follow-up), Batch 39, standing-order sequence position #171. Webview live-view cluster; scoped to
src/main.ts+ two small DOM/Tauri-free reset seams:FeedState.reset()(src/feed-state.ts) and a newSessionScope(src/session-scope.ts) grouping the session-scoped summary/board/archive-path/metrics values. RE1's ticket-review (TICKET-OK, chat #876) confirmed the reset boundary is thesession://statusphase transition and the scope is bounded tosrc/main.ts. Does not touchresample.rs/render.ts/parse.ts/pipeline.rs(reserved for #178/#179) or any dashboard/settings files.Self-Verification
The bug. The webview's session-scoped state is created once at module load and never cleared. The supported flow is Stop → idle Start screen → Start again in the same running webview (no reload). So session 2 started with session 1's state:
feed/DOM and reappeared once phase left idle, with new captions appended after them and no boundary;openReview()(main.ts:856-857) builds its coaching list fromfeed.micUtterances(), which still held session 1's own utterances — so session 2's post-meeting review/coaching could rewrite lines actually spoken in the previous meeting;latestArchivePath/latestSummary/latestBoardcould show session 1's values in session 2's review.The fix — two unit-tested reset seams + a DOM reset, run at the new-session boundary.
FeedState.reset()(feed-state.ts:54-60) clears blocks (in place, so live shimmer/heartbeat references see the empty feed),byId,partials,keyCounter, and the eviction count.SessionScope(session-scope.ts:26-41) groups the five session-scoped model values that live outside the feed —summaryLine,latestSummary,latestBoard,latestArchivePath,pendingMetrics— behind onereset().main.tsholds onescope(main.ts:90) and reads/writesscope.<field>(summary strip,openReview, the host-event handlers).resetSessionState()(main.ts:1087-1105) runs both seams (feed.reset(),scope.reset()at:1104) plus the DOM/rAF reset: removeblockElsnodes (the permanent#feed-notestays),feedCoalescer.drain(),shimmerEl/atBottom/feedNote, thependingCards/analysisCardsresult cards (cardsEl.replaceChildren()+ clear maps), thenrenderPinned().main.ts:1116-1117: a non-activeprevPhase→starting|live), guarded so pause/resume andstarting→livenever re-clear a live session — and crucially not on Stop, so the just-ended session's review screen keeps the data it already captured.render()+syncMiniViews()then repaint the clean panel.Session-scoped state audit (Scope requirement — every module-level singleton in
src/main.ts):feed(FeedState)feed.reset()blockEls(Map + DOM)clear()#feed-notesentinelfeedCoalescerdrain()shimmerElnullblockElsatBottomtruefeedNotevisibilitypendingCards(Map + DOM)cardsEl.replaceChildren()+clear()analysisCards(Map + DOM)summaryLinescope.reset()latestSummaryscope.reset()latestBoardscope.reset()latestArchivePathscope.reset()pendingMetricsscope.reset()coachingCardsreview.hide())channelssession://channelsrequestCounterfeedFlushScheduledphase/statusDetailSecurity invariants. No new dependencies. No caption/audio content logged —
resetSessionState()/FeedState.reset()/SessionScope.reset()emit no logs.feedstaysconst(reset via method, no reference churn); no drive-by refactors. Onlysrc/main.ts,src/feed-state.ts, the newsrc/session-scope.ts, and the test touched.Tests / evidence.
test/session-reset.test.ts(6 tests) drives the exact start → content → stop → start sequence against both reset seams:reset()the feed is clean — no blocks, no leftover mic utterances (the coaching-leak core), no pins, no stale ids, eviction 0, render-key counter reset.summaryLine/latestSummary/latestBoard/latestArchivePath/pendingMetrics(exactly whatopenReviewreads) →reset()→ assert all cleared, incl. a no-stale-archive-path assertion and a fresh-board (no shared-reference bleed) case. This is RE1's P1: the review inputs are now provably cleared.resetSessionState's model half → fully clean session 2.main.test.tsin-repo), routed through the sameresetSessionState.pnpm test:app);pnpm typecheck,pnpm lint, andpnpm buildall clean.Design Fidelity
No new visual surface: the reset produces already-designed empty/idle states, repainted by
render()/syncMiniViews()at the session boundary. Each state is spot-checkable against its existing source; nothing in this PR adds or alters CSS, so there are no layout, token, spacing, color, or animation changes.#feedholds only the permanent#feed-notesentinel; no caption blocksstyles.css:376(#feed),:383(#feed-note); reset removes trackedblockElsnodes only (main.tsresetSessionState)#feed-notehidden (no evicted history yet)styles.css:383,389(.visibletoggle); reset clears.visible#pinnedwithout.has-pins→ collapsed dockstyles.css:570,576; reset →renderPinned()over the empty feed removes.has-pins(main.ts:526-529)#cardsempty containerstyles.css:585,591(#cards/.card); resetcardsEl.replaceChildren()#summarylabel/line reset to the idle/starting content, dot offstyles.css:324,331,337;renderSummaryStrip()reads the clearedscope.summaryLine(main.ts:394-399, called byrender())Listening…/LiveCap(empty feed)syncMiniViews()readsfeed.latest()The only user-visible effect is that session 2 starts clean instead of showing session 1's leftover transcript/cards/summary; every rendered state is one already in the design system.
Deviations
SessionScope(src/session-scope.ts) for the five summary/board/archive/metrics values, andFeedState.reset()for the feed — two DOM/Tauri-free seams so the whole model reset is unit-testable (RE1 P1 on the first revision: the review inputs were previously reset only inside DOM-coupledmain.tsand thus unproven).feedstays aconst(reset via method, zero reference churn);main.tsnow referencesscope.<field>for the grouped values.stopped) still reads its summary/board/utterances/archive path.🤖 Generated with Claude Code