Skip to content

fix(desktop): 副窗口中会话被归档后关闭窗口,禁止继续对话 (#3175) - #3262

Open
junshanxu wants to merge 31 commits into
makecindy:mainfrom
junshanxu:fix/3175-detached-window-lifecycle
Open

fix(desktop): 副窗口中会话被归档后关闭窗口,禁止继续对话 (#3175)#3262
junshanxu wants to merge 31 commits into
makecindy:mainfrom
junshanxu:fix/3175-detached-window-lifecycle

Conversation

@junshanxu

@junshanxu junshanxu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

修复独立副窗口仍持有已归档任务时可以继续派发输入的问题。副窗口会在观察到任务归档后关闭;即使归档与“继续队列”或远程乐观发送发生竞态,Main 也会在真正恢复派发前按持久化任务状态再次拦截。

变更类型

  • fix 缺陷修复

范围

UI 变化

  • 引用的设计规范:不涉及新增视觉、文案或布局。改动复用既有 windowClose() 与分屏树收敛逻辑,属于独立辅助窗口的生命周期与故障隔离修复;对应 docs/design-rules/DESIGN.md 的多窗口一致性原则,以及 docs/dev-rules/electron-security-and-process-boundaries.md §3.1“独立辅助窗口统一生命周期基线”。

怎么验证的

自动验证

pnpm test:unit:related
结果:通过。

pnpm --filter desktop run --if-present typecheck
结果:通过。

Desktop 相关定向 Vitest(队列 coordinator、副窗口归档门禁、makerChatStore 远程恢复等 5 个文件)
结果:502 tests passed。

pnpm --filter @cindy/device-link exec vitest run src/__tests__/client.test.ts -t '多 peer 拓扑:一个 peer 停止 ACK 被限流,另一个 peer 的投递零感知'
结果:通过。

bash /Users/dash/Code/XD/dash/Skills/git/scripts/run-unit-gate.sh <worktree>
结果:Desktop 28,262 passed / 5 skipped;仅 ghostInstallReceipt.test.ts 两项失败。相同两项已在 clean origin/main 单独复现,判定为与本 PR 无关的主干基线故障。

手工验证

未执行;本轮以生命周期、IPC 边界与远程恢复回归测试覆盖。

未执行的验证

  • macOS / Windows 多窗口手工回归。
  • 全仓 unit gate 未达到全绿:被上述已在 clean main 复现的两项基线失败阻断。

风险

风险分类

  • 权限 / 安全 / 用户数据
  • 跨平台差异
  • 其他:独立窗口与远程派发生命周期竞态

影响与回滚

  • 影响范围:仅副窗口对已归档任务的输入派发、队列恢复,以及远程乐观发送恢复路径;主窗口既有归档恢复行为保持不变。
  • 回滚 / 降级方式:回滚本 PR 即恢复旧行为;未新增 migration、持久化 schema 或 wire 协议。
  • 故障半径三问:
    1. 触发层级是单条乐观发送请求或单个任务生命周期在归档边界发生竞态。
    2. 恢复动作保持同半径:只拒绝/回滚对应 outbox 请求,或让对应任务队列继续暂停;不会拆除 peer link、关闭 relay、重连或全量重放。
    3. 多 peer / 共享被控端:新增 Desktop 用例覆盖同一被控端上一个生命周期门禁拒绝不影响另一个在途请求;同时复跑 packages/device-link 既有“双 peer 中一个停止 ACK、另一个投递零感知”用例。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s
  • UI 改动已在“UI 变化”注明引用的设计规范章节
  • 未提交凭证、令牌或授权文件
  • 已补充必要文档
  • 已确认测试结果或说明未执行原因

@junshanxu
junshanxu requested a review from a team as a code owner August 22, 2026 20:57

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 85356f3886

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
@greptile-apps

greptile-apps Bot commented Aug 22, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 收紧了已归档会话在独立副窗口和远程派发路径中的生命周期边界,并补全 Goal 恢复派发的 route-lock 所有权传递。

  • 已归档任务会触发副窗口关闭,并在队列 Resume、Retry 和远程乐观发送恢复前重新校验持久化 active 状态
  • Goal、Learn、远程命令及 review 派发统一接入会话生命周期门禁
  • Goal 更新和恢复路径通过 sessionRouteLockHeld 避免非重入 route lock 的重复获取,同时保证派发期间持续持锁
  • 本地数据库事务与乐观发送回滚增加请求级隔离和配套回归测试

Confidence Score: 5/5

当前代码已修复先前报告的 route-lock 重入和异步持锁问题,未发现仍需阻止合并的故障。

未发现仍然存在的阻塞性失败。

Important Files Changed

Filename Overview
apps/desktop/src/main/maker-ipc/goal.ts 为副窗口和显式远程请求增加持久化生命周期门禁,并将 route-lock 所有权传入 Goal 控制器。
apps/desktop/src/main/goal-host/controller.ts Goal 设置、更新、恢复及重新打开路径完整传递 sessionRouteLockHeld,持锁恢复会等待派发结束。
apps/desktop/src/main/maker-ipc/register.ts pending-agent-switch holder 新增已持锁分支,应用待处理路由后返回空 release,避免非重入锁自死锁。
apps/desktop/src/renderer/lib/makerChatStore.ts 远程乐观发送失败处理改为请求级回滚,避免一个失败请求影响其他在途请求。
apps/desktop/src/main/maker-ipc/agent-input-coordinator.ts 队列恢复与重试在真正派发前重新核验持久化 active 状态,阻止归档竞态重新激活任务。
apps/desktop/src/main/bootstrap-electron.ts Goal、Learn 和远程命令 IPC 注入统一的设备来源判断、会话锁及 active 状态断言。

Sequence Diagram

sequenceDiagram
  participant W as 独立副窗口
  participant M as Electron Main
  participant DB as 持久化会话状态
  participant G as Goal Controller
  participant S as Agent Session
  W->>M: Goal/继续对话请求
  M->>M: 获取 session route lock
  M->>DB: 校验会话仍为 active
  alt 会话已归档
    DB-->>M: archived
    M-->>W: 拒绝派发并关闭窗口
  else 会话仍 active
    DB-->>M: active
    M->>G: 调用并传递 sessionRouteLockHeld
    G->>G: 应用 pending route(不重复加锁)
    G->>S: ensureSession + send
    S-->>G: 派发结果
    G-->>M: 完成
    M->>M: 释放 route lock
  end
Loading

Reviews (35): Last reviewed commit: "fix(desktop): wait for fenced clear life..." | Re-trigger Greptile

@MagicLizi

Copy link
Copy Markdown
Contributor

这条改动会改变用户看得见的交互:副窗口里的会话被主窗口归档后,副窗会自动关闭,而不只是停在已归档会话上。这属于产品行为,需要维护者确认后再合。

请维护者在本 PR 上 Approve;如果希望改成「留窗但禁止发送/恢复」或其它收口,请 Request Changes。

讨论 issue:#3263

@MagicLizi MagicLizi added awaiting-discussion 等待维护者讨论(review-pr) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) labels Aug 22, 2026
@dashhuang
dashhuang force-pushed the fix/3175-detached-window-lifecycle branch from 85356f3 to d543d64 Compare August 22, 2026 22:21

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d543d64b04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated
Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@yuaiccc 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@MagicLizi

Copy link
Copy Markdown
Contributor

命中 UI 路径(apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d497cca98e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/OrcaSplitView.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 124fde79a8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 45be85fdd1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated
Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
@MagicLizi

Copy link
Copy Markdown
Contributor

@yuaiccc 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 289f03d4df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated
@dashhuang

Copy link
Copy Markdown
Member

收敛检查点(HEAD 2defbf9c5

  • 不变量:副窗口一旦获知其路由任务已归档,普通发送、排队操作与恢复路径都不得再派发;脏文件预检取消时保留编辑器,但所有派发入口保持失效。
  • 对称路径:普通 / Workdir / Orca 关窗归属;普通 send / steer;附件物化后的发送;device-link 断线重连后的再次派发;错误、中断、silent-stop 与切换供应商后的 retry;队列 Resume / Steer。
  • 判据收拢:Renderer 用同步归档 ref 约束副窗口入口与每次远端实际派发;Main 仅在副窗口显式请求时,于 retry 入队边界复查持久化 active 状态,主窗口历史行为不变。
  • 可鉴别测试:覆盖重连后再次执行生命周期 fence、归档期间 retry 不入队、主窗口 archived retry 兼容、归档副窗移除 queue Resume / Steer dispatcher。
  • 故障半径:触发与动作都限定在单条乐观发送 / 单个任务生命周期;不拆 relay、不重建连接、不改变共享 peer 状态,因此不会把一个副窗的归档状态放大到其它控制端。

@dashhuang

Copy link
Copy Markdown
Member

收敛检查点:副窗口一旦得知其路由任务已归档,普通发送、排队操作与恢复入口都不得再派发工作;脏文件取消关窗时保留编辑器,但所有派发路径继续保持 inert。

已审计路径:普通 / Workdir / Orca 关窗所有权,send / steer,附件物化后的入队,device-link 断线重连,错误 / 中断 / silent-stop / provider-switch retry,以及队列 Resume / Steer。可鉴别回归覆盖重连后再次执行生命周期 fence、历史读取期间归档时拒绝副窗 retry、主窗归档任务 retry 保持既有恢复语义,以及归档副窗移除队列派发回调。

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2defbf9c52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated
Comment thread apps/desktop/src/renderer/lib/makerChatStore.ts
@MagicLizi MagicLizi added the touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) label Aug 23, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f950f29142

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx Outdated
Comment thread apps/desktop/src/renderer/lib/makerChatStore.ts
@MagicLizi

Copy link
Copy Markdown
Contributor

@yuaiccc 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx / apps/desktop/src/renderer/lib/makerChatStore.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9cd208ff8b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/maker-ipc/register.ts
@MagicLizi

Copy link
Copy Markdown
Contributor

@yuaiccc 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/maker-ipc/register.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ed339149d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@yuaiccc 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/maker-ipc/register.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bc01deb77

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6dd8088b62

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e282539c05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/maker-ipc/reviewStartHandler.ts Outdated
Comment thread apps/desktop/src/renderer/features/cc-agent/CCAgentSessionView.tsx
@MagicLizi MagicLizi added the touches:large-diff 改动量较大(review-pr 自动维护,仅展示) label Aug 24, 2026
dashhuang and others added 26 commits September 3, 2026 01:09
Signed-off-by: Dash <dashhuang@gmail.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Signed-off-by: Dash <dashhuang@gmail.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Address Codex P2 finding on goal.ts: the lifecycle guard only fired for
device-link invokes with requireActiveSession, while a local secondary
window (which hosts a GoalIndicator on a full session) could call
resumeGoal/updateGoal/clearGoal/setGoal and bypass the active-session
fence — re-activating an archived task.

Derive secondary-window status from the real event.sender via
isSecondaryAppWindow(BrowserWindow.fromWebContents(event.sender)),
complementary to the device-link requireActiveSession marker (device-link
synthetic events have no sender). Either path now takes the route lock +
persistent active assertion. runWithLifecycleGuard reports whether it
fenced so GOAL_SET sets sessionRouteLockHeld consistently for both paths.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Windows (1/2) failed one unrelated test in packages/maker-core
(cindySubagentRunner 'honours a stop that shares a batch with an earlier
approval') with a 60s waitFor timeout, while Linux (1/2)(2/2) and Windows
(2/2) all passed. This PR only touches desktop main/renderer goal
lifecycle files (goal.ts, bootstrap-electron.ts, goalHandlers.test.ts)
and does not modify maker-core, so this is a Windows-only flake.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Address Codex P2 (goal.ts:128): GOAL_GET_STATUS looked like a read but its
resumeOnOpen() path has side effects — it rebuilds the Agent session and
may continue a dormant active goal. After a session was archived and its
auto-close cancelled over unsaved files, a secondary-window GoalIndicator
re-binding (renderer reload / session origin re-bind) could call
getGoalStatus and re-activate the archived task, because set/resume/update
/clear were fenced but this auto-recovery read was not.

- Wrap resumeOnOpen in runWithLifecycleGuard so local secondary windows
  (detected via the real event.sender) and device-link secondary windows
  (requireActiveSession marker, since their synthetic events have no
  sender) run it under the route lock + persistent active assertion.
- Primary windows / primary remote keep the historical resume-on-open
  semantics (opening a main-window session is allowed to recover).
- When the fence reports the session is no longer active, GET_STATUS
  degrades to returning the pre-recovery snapshot instead of resuming or
  throwing at the renderer.
- Thread requireActiveSession through makerTransport for the remote
  secondary-window getGoalStatus path (local main process auto-fences via
  sender, so no preload change is needed).
- Add regression tests for both remote and local secondary-window paths.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
…eadlock

Review P2: runWithLifecycleGuard holds the session route lock, then calls
controller.setGoal/resumeGoal/resumeOnOpen which re-enter the same
non-reentrant lock via acquirePendingAgentSwitchForDirectSend →
acquireSendToSessionLock, deadlocking the IPC.

The holder already supports a sessionRouteLockHeld option to skip the
second acquisition. Propagate the fenced flag through every side-effecting
Goal path:
- setGoal: input.sessionRouteLockHeld (already consumed by fireTurn)
- resumeGoal: new opt, forwarded to fireTurn
- resumeOnOpen: new opt, forwarded to acquirePendingAgentSwitch
- goal.ts fence: pass the flag when fenced, omit it otherwise

Also propagate requireActiveSession through the remote secondary-window
goal transport (setGoal/clearGoal/resumeGoal/updateGoal), not just
getGoalStatus (review P1): synthetic device-link events have no sender,
so without the marker the guard treats them as primary-window requests
and a secondary window can restart an archived task.

Tests: update goalHandlers assertions for the new flag, add a
send-to-session ordering contract for the holder fast-path, and fix the
SET_MODEL needle that drifted to `options` in this branch.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
…l IPC

Address remaining review threads on makecindy#3262:
- GOAL_UPDATE fenced path also re-enters the route lock: updateGoal
  resumes paused/blocked goals via resumeGoal→fireTurn when the objective
  changes, so pass sessionRouteLockHeld through updateGoal and its
  resumeGoal call. Previously only setGoal/resumeGoal/resumeOnOpen had
  the marker, leaving updateGoal to self-deadlock.
- isSecondaryWindowEvent must tolerate a missing sender. Device-link
  synthetic events set sender to undefined (invoke-registry); calling
  BrowserWindow.fromWebContents(undefined) threw before the request
  reached the controller. Return false for those calls — they are
  gated by the explicit requireActiveSession marker instead.
- Spread sessionRouteLockHeld only when fenced so non-fence callers
  keep the bare single/two-arg shape (goalHandlers tests updated).

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
The remote secondary-window fence used [sid, remoteFenceOpts()] for
clearGoal/resumeGoal. When not in a secondary window remoteFenceOpts()
returned undefined, but the argument was still passed as a second
element, so spies/IPC saw (sid, undefined) instead of the bare (sid)
shape the transport-routing contract and its tests expect. Use a
conditional spread so non-secondary remote calls keep the single-arg
form (matching getGoalStatus), and only append {requireActiveSession}
for secondary windows.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
…n active session

The secondary-window archive fence only blocked composer/queue input.
Three other entry points could still start an Agent turn on an archived
task when the auto-close was cancelled over dirty files (makecindy#3262 P2):

- Compact: both Pi (COMPACT_SESSION) and Claude (INPUT_COMPACT via the
  input coordinator) now run assertSessionActiveForManualDispatch when
  the caller is a secondary window (local by sender, or device-link with
  requireActiveSession). Renderer passes the marker through
  makerTransport.compactSession and makerChatStore.compactSession.
- Worker dispatch: WORKER_DISPATCH_UI_ASSIGNMENT re-checks the Lead's
  persisted active status inside the serialized claim, immediately before
  sendToWorker, instead of trusting the renderer's cached state.
- Interaction resolve: RESOLVE_INTERACTION looks up the pending
  interaction's owning session and asserts it is still active before
  resolving; approving a permission / answering ask_user / confirming a
  plan on an archived session is now rejected.

The existing assertSessionActiveForManualDispatch is reused (DB status
check + route lock semantics), so main is the single enforcement
boundary for all three paths.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
The prior active-session checks for worker dispatch, compact, and
interaction resolve were bare awaits, leaving a TOCTOU window: the check
could observe 'active', then an archive committed under the route lock,
and the guarded operation still ran (makecindy#3262 P2 follow-up).

- WORKER_DISPATCH_UI_ASSIGNMENT: wrap assertSessionActive + sendToWorker in
  withSendToSessionLock(leadSessionId) so the check and worker dispatch
  are atomic with respect to Lead archive.
- RESOLVE_INTERACTION: wrap assertSessionActive + resolvePendingInteraction
  in the owning session's route lock; approving a permission / answering
  ask_user / confirming a plan can no longer land on an archived turn.
- Compact: carry requireActiveSession through PendingCompactRequest and
  re-check isSessionActiveForManualDispatch right before sendToAgent in
  dispatchCompact, covering the case where the session is archived while
  the compact sits in pendingCompacts. INPUT_COMPACT forwards the flag
  into the coordinator in addition to its enqueue-time check.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
…on fences

Three P1 findings after the prior commit:

- makerTransport.compactSession dropped the optional instructions slot
  when appending the fence, so a secondary window without instructions
  sent [sessionId, {requireActiveSession}] and the controlled endpoint
  rejected the fence object as INVALID_PARAMS. Keep the undefined
  placeholder: [sessionId, instructions, fenceOpts].
- Claude compact (dispatchCompact) pre-checked active state but did not
  carry requireActiveSession into sendToAgent options, so the final in-lock
  fence never ran. Propagate the flag into sendOpts so sendToAgent
  re-asserts under the route lock.
- Pi compact (COMPACT_SESSION) checked active and called
  sess.compactSession() as two separate steps. Move both inside
  withSendToSessionLock so an archive cannot land between the check and
  the turn start. Non-fence callers retain the prior unlocked path.

Signed-off-by: yuaiccc <yuaiccc@aliaun.com>
Conflict resolution on the orcaTeamStore.test.ts afterEach block
inadvertently added a second 'import { setSessionRouteLockImplementation }
from ../sessionRouteLock.js' on the line right after the first one,
plus the new setSessionRuntimeCleanup import from main. TypeScript
rejects the duplicate identifier at compile time, which is what made
'Typecheck desktop' fail on CI for the previous run.

Signed-off-by: yuaiccc <yuaiccc@aliyun.com>
Signed-off-by: yuaiccc <yuaiccc@aliyun.com>
Signed-off-by: yuaiccc <yuaiccc@aliyun.com>
Signed-off-by: yuaiccc <yuaiccc@users.noreply.github.com>
Signed-off-by: yuaiccc <yuaiccc@aliyun.com>
Signed-off-by: yuaiccc <yuaiccc@aliyun.com>
@junshanxu
junshanxu force-pushed the fix/3175-detached-window-lifecycle branch from 912ee35 to 417b889 Compare September 2, 2026 17:15
@junshanxu

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 417b889ba1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4574 to +4577
if (head.requireActiveSession && isSessionNotActiveError(err)) {
latest.activeTurn = null;
this.clearCredentialSwitchWait(latest);
this.deps.onDiscardedQueuedMessage?.(sessionId, head);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore retry recovery when the lifecycle fence wins

When a secondary window starts a manual Retry and another window archives the task after performRetryLastError's active precheck but before the locked send, this branch discards the fenced retry without restoring its recovery state. The retry path has already cleared error, stickyError, and recovery, while the renderer also calls disposeLiveErrorPersist() before the IPC result, so the archived task loses its actionable error and marks the persisted error dismissed even though no retry ran. Restore the manual retry checkpoint on SESSION_NOT_ACTIVE, or serialize the active check and retry transition with the session route lock.

AGENTS.md reference: AGENTS.md:L129-L132

Useful? React with 👍 / 👎.

@MagicLizi

Copy link
Copy Markdown
Contributor

@junshanxu 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/maker-ipc/agent-input-coordinator.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-discussion 等待维护者讨论(review-pr) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:large-diff 改动量较大(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

在新窗口打开会话后,原会话删除或归档不会关闭新窗口,且仍可继续对话

3 participants