Skip to content

fix(live-voice): give the docked widget its own state, not a store it lacks - #1274

Merged
vastsa merged 2 commits into
mainfrom
fix/live-voice-widget-gaps
Oct 1, 2026
Merged

vastsa merged 2 commits into
mainfrom
fix/live-voice-widget-gaps

Conversation

@vastsa

@vastsa vastsa commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Why

The docked widget window boots no app store and renders no toast surface, but after the #1271 merge the call bar still

  • derived the "work session is waiting for your answer" hint from that store → the hint could never appear in the widget, and
  • sent one-shot failures to that toast → those failures were silently swallowed.

main is also red: 27fda481d fails Docs checks and JS build/typecheck/lint/architecture/test because docs/adr carries two ADR 0314 files (live-voice-docked-widget + live-voice-spoken-asktool-answers), and the ADR catalog requires unique decision ids.

What

  • Owner reports, widget draws. The main window computes the waiting decision from its own queues and reports it together with the failure code it already owned: voice/live/widget/ownerState replaces voice/live/widget/issue ({ callId, errorCode, decisionWaiting }). Main caches both per call and pushes them with the authoritative view.
  • The bar is presentational again: decisionWaiting arrives as a prop and every issue is drawn in place next to its verbatim LIVE_* code, so nothing the user must see depends on a surface the widget window does not have. The owner-frame playback gesture from feat(live-voice): dock the call bar as a global desktop widget #1271 is untouched.
  • ADR fixed: the widget record is renamed to 0315 and registered next to 0314, so the ADR catalog check passes.
  • Fixture: seeds the owner store and asserts the hint reaches the widget bar and clears with the decision; sender-authorization and payload-validation coverage extended to the renamed channel.

Verification (on this branch)

  • apps/desktop typecheck; biome; style-token guard; check-architecture; check-agent-policy-sync.
  • docs:check: 543 pages + 83 EN/zh pairs + ADR catalog ✓.
  • apps/desktop suite 3346/3346; Live Voice / Live Work sets incl. the spoken-answer and pending-interactive tests 97/97.
  • Mounted interaction fixture 51/51 (adds "a decision the bound session waits on reaches the widget bar" and "the waiting hint clears with the decision").
  • pnpm test:e2e:live-voice 5/5 journeys against the real app.

… lacks

The docked widget window boots no app store and renders no toast surface, yet the
call bar derived the work-decision hint from that store and sent one-shot
failures to that toast. In the widget window both were invisible.

- the owner frame computes the waiting decision and reports it together with its
  own failure code (voice/live/widget/ownerState replaces widget/issue)
- the bar takes the flag as a prop and draws every issue in place, so nothing the
  user must see depends on a surface the widget window does not have
- rename the widget ADR to 0315: it collided with the spoken-answer ADR 0314 and
  failed the ADR catalog check on main
- fixture: assert the waiting hint arrives from the owner store and clears again
Copilot AI balanced review requested due to automatic review settings October 1, 2026 06:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The renamed channel remains stale in ADR documentation, validation records are outdated, and the fixture contains unreachable legacy code.

Review effort: Balanced
Findings: 4 Low severity

Open (4)
What changed in this PR

Moves widget-only state derivation to the main window owner and forwards it through validated IPC, while fixing the duplicate ADR identifier.

Changes:

  • Reports failure codes and pending decisions through widget/ownerState.
  • Makes the docked call bar fully presentational with inline errors.
  • Extends widget tests and renumbers the widget ADR to 0315.
File Description
packages/​shared/​src/​protocol.ts Renames the widget owner-state IPC channel.
docs/​spec/​03-runtime/​01-ipc-protocol.md Documents the expanded IPC payload.
docs/​spec/​04-ux/​08-component-spec.md Documents owner-derived decision state.
docs/​zh-CN/​spec/​03-runtime/​01-ipc-protocol.md Updates Chinese IPC documentation.
docs/​zh-CN/​spec/​04-ux/​08-component-spec.md Updates Chinese component behavior.
docs/​adr/​README.md Registers ADR 0315.
docs/​adr/​0315-live-voice-docked-widget.md Renumbers the widget ADR.
apps/​desktop/​src/​features/​voice/​live/​LiveVoiceStatusHost.tsx Derives and reports owner-only state.
apps/​desktop/​src/​features/​voice/​live/​LiveVoiceCallBar.tsx Accepts decision state as a prop and renders errors inline.
apps/​desktop/​src/​features/​voice/​live/​LiveVoiceWidget.tsx Passes reported decision state to the bar.
apps/​desktop/​src/​features/​voice/​live/​live-voice-api.ts Exposes the renamed owner-state IPC API.
apps/​desktop/​electron/​main/​ipc/​live-voice-ipc.ts Validates and handles owner-state reports.
apps/​desktop/​electron/​main/​live-voice/​widget-window.ts Caches and publishes owner-only widget state.
apps/​desktop/​test/​live-work-decision.test.mjs Supplies derived decision state to component tests.
apps/​desktop/​test/​live-voice-widget.test.mjs Tests authorization and payload validation.
apps/​desktop/​test/​live-voice-controls.test.mjs Updates owner-state source assertions.
apps/​desktop/​test/​fixtures/​live-voice-interaction.jsx Models owner-state forwarding in the fixture.
apps/​desktop/​test/​fixtures/​live-voice-interaction-runner.cjs Tests showing and clearing the waiting hint.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/desktop/src/features/voice/live/LiveVoiceStatusHost.tsx Outdated
Comment on lines +230 to +234
await check("a decision the bound session waits on reaches the widget bar",
`document.querySelector('.live-voice-call-bar')?.textContent.includes('waiting for your answer or approval') === true`);
await evaluate("window.liveVoiceFixture.clearPendingAsks()");
await check("the waiting hint clears with the decision",
`document.querySelector('.live-voice-call-bar')?.textContent.includes('waiting for your answer or approval') === false`);
Comment on lines 162 to 164
widgetReports.errorCode = request.code ?? undefined;
pushWidgetState();
return { ok: true };
liveVoiceCancelQueuedOperation: "pi-desktop/voice/live/work/cancelQueuedOperation",
liveVoiceWidgetAction: "pi-desktop/voice/live/widget/action",
liveVoiceWidgetIssue: "pi-desktop/voice/live/widget/issue",
liveVoiceWidgetOwnerState: "pi-desktop/voice/live/widget/ownerState",
Keep the owner-state boundary while preserving the latest ADR numbering and main-branch Live Voice changes. Remove the duplicate stylesheet import introduced by the conflict resolution.
@vastsa
vastsa merged commit 99a35c6 into main Oct 1, 2026
4 checks passed
jiangchuanso added a commit to jiangchuanso/PI-Desktop that referenced this pull request Oct 1, 2026
@vastsa
vastsa deleted the fix/live-voice-widget-gaps branch October 6, 2026 16:56
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.

2 participants