Skip to content

[Fix] fix dashboard restored session rows#277

Merged
deepcoldy merged 3 commits into
deepcoldy:masterfrom
nil-err:wt/botmux-starting-dashboard
Jun 23, 2026
Merged

[Fix] fix dashboard restored session rows#277
deepcoldy merged 3 commits into
deepcoldy:masterfrom
nil-err:wt/botmux-starting-dashboard

Conversation

@nil-err

@nil-err nil-err commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

背景 / Problem Found

这次修改是排查线上问题时发现的:botmux 重启前有 3 个会话在 dashboard 上表现为 starting,重启后这些会话在 dashboard 里看不到了。

排查后确认,starting 不是持久化的 Session.status,而是 dashboard 根据 active session 缺少 screen/status 派生出来的展示状态。daemon 重启时 restoreActiveSessions() 会把 active session 注册回内存,但此前不会向 dashboard SSE 广播完整 session row。如果 dashboard 在 hydrate/SSE 时序上先收到后续 session.update / close 事件,却本地还没有对应 row,这些 patch 就会被当成 unknown row 忽略,最终表现为恢复/关闭状态在 dashboard 消失。

What Changed

  • Added announceSessionRow(ds) to publish a full session.spawned dashboard row from composeRowFromActive(ds).
  • Reused that helper from announcePendingRepoSession() so session row announcements share one path.
  • Updated restoreActiveSessions() to announce restored normal sessions and restored adopt sessions immediately after they are registered into activeSessions.
  • Added optional wake=1 support to POST /api/sessions/:sessionId/resume.
    • Default behavior is unchanged: resume marks a closed session active and waits for the next inbound message to cold-resume the CLI.
    • With wake=1, the route immediately calls forkWorker(ds, '', true) after a successful resume, which is useful for operational recovery when a session must be usable right away.

Impact

  • Restored sessions become visible to dashboard subscribers even when dashboard hydrate and daemon restore race with each other.
  • Subsequent status/close updates are applied to a known row instead of being dropped as unknown.
  • Existing resume callers keep the same behavior unless they explicitly opt into wake=1.

Validation

  • corepack pnpm vitest run --project unit test/dashboard-ipc.test.ts test/dashboard-attention-signals.test.ts test/restore-zombie-close.test.ts
  • corepack pnpm exec tsc --noEmit
  • git diff --check

@nil-err nil-err force-pushed the wt/botmux-starting-dashboard branch from 8790dc7 to 42c75fd Compare June 22, 2026 12:55
@nil-err nil-err marked this pull request as ready for review June 22, 2026 13:05
@nil-err nil-err requested a review from deepcoldy as a code owner June 22, 2026 13:05
@nil-err nil-err changed the title [codex] fix dashboard restored session rows [Fix] fix dashboard restored session rows Jun 22, 2026
…响应报有效动作 + no-wake 负向测试

Review 修复(PR deepcoldy#277):
- 阻塞: session-resume.test.ts 也 mock 了 session-activity.js 但漏导出新增的
  announceSessionRow,restoreActiveSessions 跑到 announceSessionRow(ds) 即抛
  "No announceSessionRow export" → 补 vi.fn()(与 restore-zombie-close.test.ts 一致)
- /resume 响应的 wake 改为报「实际是否 fork」(woke) 而非原始 query 参数;加注释
  说明 wake=1 是 opt-in 运维 curl 钩子,默认关、不改任何现有调用方行为
- 补默认 resume(无 wake) 不 fork 的负向测试,守住 wake && 短路守卫
Codex 二审发现的残留竞态:daemon 在 restoreActiveSessions() 之前就发布发现
descriptor(daemon.ts:3643 vs :3765),dashboard 的 attachDaemon 是先 hydrate
(GET /api/sessions)再订阅 SSE。若 hydrate 落在 restore 前 → 拿到空快照;而
DashboardEventBus 无 buffer/replay,restore 期的 announceSessionRow() 若发生在
本条 SSE 订阅建立之前就被丢弃 → 聚合器既无快照行也无 spawned 行,后续
session.update/close 仍按 unknown row 丢弃。原 PR 只修了「已订阅时 restore 才
announce」的路径,没修掉竞态本身。

修法:/api/events 处理器先 subscribe 再回放当前 listActiveSessions() 为
session.spawned。这样订阅前已注册的行经快照送达、订阅后注册的行经实时事件送达,
两路覆盖确定性消除竞态;不改启动顺序/descriptor 时机。幂等(聚合器/前端 store
均按 sessionId upsert)。补 SSE 快照回放回归测试。
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