Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions config/architecture-policies.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
"type": "change-scope",
"comparison": "worktree",
"whenChanged": [
"src/main/mobile-terminal-surface-recovery/**",
"src/main/ipc/pty/spawn-operation.ts",
"src/main/ipc/pty/pty-dead-owner-respawn.test.ts",
"src/renderer/src/components/terminal-pane/pty-connection-cold-restore-resume-command.spec.ts",
"src/renderer/src/mobile-terminal-surface-recovery/**",
"docs/issue/手机打开工作区终端身份恢复/**"
],
Expand Down Expand Up @@ -76,6 +80,10 @@
"src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-live-bookmark.test.ts",

"tests/e2e/mobile-terminal-surface-recovery.spec.ts",
"src/main/mobile-terminal-surface-recovery/**",
"src/main/ipc/pty/spawn-operation.ts",
"src/main/ipc/pty/pty-dead-owner-respawn.test.ts",
"src/renderer/src/components/terminal-pane/pty-connection-cold-restore-resume-command.spec.ts",
"src/renderer/src/mobile-terminal-surface-recovery/**",
"src/renderer/src/lib/worktree-agent-live-surface-adoption.ts",
"src/renderer/src/lib/worktree-agent-activation-gate.ts",
Expand Down Expand Up @@ -273,6 +281,10 @@
"src/renderer/src/store/terminals/workspace-terminal-hydration.ts",
"src/renderer/src/store/repos/all-host-repo-catalog-actions.ts",
"src/renderer/src/store/repos/runtime-repo-catalog-actions.ts",
"src/main/mobile-terminal-surface-recovery/**",
"src/main/ipc/pty/spawn-operation.ts",
"src/main/ipc/pty/pty-dead-owner-respawn.test.ts",
"src/renderer/src/components/terminal-pane/pty-connection-cold-restore-resume-command.spec.ts",
"src/renderer/src/mobile-terminal-surface-recovery/**",
"tests/e2e/mobile-terminal-surface-recovery.spec.ts",
"src/renderer/src/lib/worktree-agent-live-surface-adoption.ts",
Expand Down
20 changes: 19 additions & 1 deletion config/fork-features.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
],
"policyId": "mobile-terminal-surface-recovery",
"ownedPaths": [
"src/main/mobile-terminal-surface-recovery/**",
"src/renderer/src/mobile-terminal-surface-recovery/**",
"tests/e2e/mobile-terminal-surface-recovery.spec.ts",
"docs/issue/手机打开工作区终端身份恢复/**"
Expand All @@ -111,6 +112,21 @@
"src/renderer/src/mobile-terminal-surface-recovery/live-terminal-placement-verdict.ts"
],
"seams": [
{
"file": "src/main/ipc/pty/spawn-operation.ts",
"mustContain": "assertNumericReattachMaySpawn",
"why": "A numeric restore without a stable owner cannot become a fresh local or SSH shell without host-proven absence."
},
{
"file": "src/main/ipc/pty/pty-dead-owner-respawn.test.ts",
"mustContain": "hasOwner",
"why": "Exercise numeric live, positive absence and missing-owner requests through the actual IPC handler."
},
{
"file": "src/renderer/src/components/terminal-pane/pty-connection-cold-restore-resume-command.spec.ts",
"mustContain": "keeps a live local reattach",
"why": "A hibernation note and empty replay cannot retire a live process."
},
{
"file": "src/main/runtime/workspaces/workspace-activation.ts",
"mustContain": "resolveWorkspaceSelector(worktreeSelector)",
Expand Down Expand Up @@ -226,6 +242,8 @@
}
],
"tests": [
"src/main/ipc/pty/pty-dead-owner-respawn.test.ts",
"src/renderer/src/components/terminal-pane/pty-connection-restore-and-resume.test.ts",
"src/renderer/src/hooks/ipc-events/worktree-event-runtime-activation.test.ts",
"src/renderer/src/hooks/ipc-events/worktree-event-lineage-refresh.test.ts",

Expand All @@ -241,7 +259,7 @@
"src/renderer/src/lib/worktree-agent-activation-gate.test.ts"
],
"checks": [
"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/project-group-folder-workspace-selectors.test.ts src/renderer/src/hooks/ipc-events/worktree-event-runtime-activation.test.ts src/renderer/src/hooks/ipc-events/worktree-event-lineage-refresh.test.ts src/renderer/src/mobile-terminal-surface-recovery src/renderer/src/lib/worktree-agent-activation-gate.test.ts src/renderer/src/lib/worktree-agent-activation-seam.test.ts src/renderer/src/components/terminal-pane/pty-connection/reattach-success-settle.test.ts src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-newer-daemon-hold.test.ts src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-live-bookmark.test.ts"
"pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/pty/pty-dead-owner-respawn.test.ts src/renderer/src/components/terminal-pane/pty-connection-restore-and-resume.test.ts src/main/runtime/project-group-folder-workspace-selectors.test.ts src/renderer/src/hooks/ipc-events/worktree-event-runtime-activation.test.ts src/renderer/src/hooks/ipc-events/worktree-event-lineage-refresh.test.ts src/renderer/src/mobile-terminal-surface-recovery src/renderer/src/lib/worktree-agent-activation-gate.test.ts src/renderer/src/lib/worktree-agent-activation-seam.test.ts src/renderer/src/components/terminal-pane/pty-connection/reattach-success-settle.test.ts src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-newer-daemon-hold.test.ts src/renderer/src/components/terminal-pane/pty-connection/deferred-session-reattach-live-bookmark.test.ts"
]
},
{
Expand Down
11 changes: 10 additions & 1 deletion docs/issue/手机打开工作区终端身份恢复/journal.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ slug: '手机打开工作区终端身份恢复'
status: testing
created: 2026-10-24
updated: 2026-11-09
external_ids: ['STA-3859', 'Fartown/orca#92']
external_ids: ['STA-3859', 'Fartown/orca#92', 'Fartown/orca#95']
---

# 手机打开工作区终端身份恢复 开发 Journal
Expand Down Expand Up @@ -259,3 +259,12 @@ external_ids: ['STA-3859', 'Fartown/orca#92']
- 完成内容补充:生产 Mac 先保存 `renderer-before.json` 备份,再仅移除其他两个工作区 mounted 列表中已由新鲜主机证明属于当前工作区的裸 `4/5` 缓存,使用现有 createTab 恢复原 tab/leaf。桌面4→6,主机发布6;`mac-host-after-repair.json` / `mac-renderer-after-repair.json` 对比确认六个 handle/incarnation 不变、两个根 PID/启动时间不变、导航不变、主进程仍为19549;没有退出应用、关闭 tab 或向生产终端输入。
- 未解决问题:永久代码尚未正式发布/安装,真实手机13标签的当前画面未获得;当前状态 testing,不是 done。完整 e2e 类型检查有 cloud/mobile 未装独立依赖的诊断,目标 spec 无诊断。初次旧场景 E2E 被上游 setup script 提示卡挡住,复用现有 dismiss helper 后重跑,不改产品提示卡。
- 下一步:收齐重跑与 PR 检查,发布防复发版本;正式安装重启须取得该 Mac 的明确许可,不能把现场状态修复当作永久代码已经安装。

### 2026-11-09 既有 pane 连接与恢复判定源码复核

- 本轮目标:复核此前三轮之后仍可增生空 shell 的完整调用链;先给出源代码反例,再修改准入。
- 完成内容:确认 numeric sessionId + owner 缺失可从共享 fresh 进入 provider;ambiguous 被当 owned;partial placement 提前 adopted;window 因 live reattach 无回放加睡眠 note 清绑定重开;pending null/旧 generation 直接 fresh。分别拦住这些分支,正向退出和正常新建保留。
- 代码或文档变更:新增 main feature-owned numeric admission,共享 spawn-operation 接线;调整原 adoption/gate/reattach 接缝及对应现有反例测试;登记 REQ-008、TC-023 和源码审查记录。无 wire 变更,无用户现场 tab 删除。
- 验证证据:状态 testing。主类型检查、feature checks、架构/Fork/三项本地化通过。实际应用 7 项通过:真实 numeric fallback + 无 owner 请求拒绝、4 项 Git/folder 旧 census 路径、无答复 attach 后 reload、SSH Git/folder 手机激活及隔离客户端重启。最后补查 sleeping claim 后 partial placement 的拒绝,最终完整 feature checks 为 13 文件、224 项通过;最终主类型、按 PR base 的 changed-code quality、架构与 Fork 门禁均通过。原始记录在 `.docs/mobile-terminal-recovery-ui-validation/2026-11-09-source-audit/`。
- 未解决问题:用户 Mac 正在运行的 .76 未包含这轮代码。先前 #91 的 Mac build 已 cancelled、publish skipped,不能宣称永久包已安装。现场 21:25 新建 PTY 16 的发起者尚无完整 breadcrumb,不能把源码反例直接当作该次运行的唯一根因。pending null 的拒绝覆盖当前连接尝试,不把任何未来 remount 或旧 host 的行为假定为已验证。额外 E2E 全树类型检查有 42 个 cloud/mobile 依赖或 stub 错误,与基线逐条相同,无新增;不把它记为通过。
- 下一步:完成本轮源码复核后的针对性验证并提交独立 PR;正式产物和 Mac 安装/重启须分开记录,未获该主机重启授权不退出应用。
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,10 @@ updated: 2026-11-05
| 2026-10-24 | 临时修复实施授权 | REQ-006 收窄到本次 adoption 兜底;普通重连异常列后续,保留桌面 seed 与后台 wake 的实际边界 | REQ-006 | D-005 |
| 2026-10-25 | Claude 代码 review 的 daemon 反例 | 撤回“非目标全部 decline”,仅新增 recorded 原身份分支;daemon fallback 保留,numeric 残留如实记录 | REQ-006 | D-006 |
| 2026-10-25 | 最终窄版代码复核与运行证据 | 按有效 recorded 单 leaf slice 记录本机/SSH 局部结果;独立 folder selector 跳过、多 leaf 与微竞态不升级为通过 | REQ-001 至 REQ-006 | D-007 |

### REQ-008 恢复入口不能把未知结果升级为新建许可

- 当前状态:待实现。
- 描述:已有数字 PTY 的 pane owner 缺失、重复归属、部分认领失败、pending 启动空结果以及 live attach 无回放均不得单独授权 fresh。
- 本地验收:每个源码反例保留原 tab/leaf/进程,拒绝新增进程;host 正向确认原进程退出后正常恢复;正常用户新建 shell 仍可用。
- SSH 验收:共享 host 入口按远端 PTY 标识和退出证明裁决;断联不发请求、不在客户端降级新建;Git/folder 工作区使用已有远端验证入口。
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 2026-11-09 恢复准入源码审查

对应 Fartown/orca#95、REQ-001/002/003/004/006/008、TC-023。基线 a6445b0766,已有 #91 不覆盖既有 pane connect。

| 入口 | 基线代码能推出的反例 | 修订后的判断 |
| --- | --- | --- |
| deferred-session-reattach-connect → runPtySpawn → reconcilePaneOwner → spawnLocalPty | 普通数字 sessionId,owner 为 null,fresh 最后忽略数字 ID 并新建进程 | fresh 前必须有同一主机该 ID 的 absentOwner 或 stop 证明;无 owner 返回 unverified,provider 不被调用 |
| adoptLiveWorkspacePtySurfaces | 两个 surface 声明同 PTY,ambiguous 被计为 surfaced,跳过 host census | 仅 owned 可计为 surfaced,ambiguous declined,不自动覆盖或删除任何一方 |
| runWorktreeAgentActivationGate | 一项恢复成功,另一项 declined,却先返回 adopted;structured 也能提前返回 | 未安置 live 工作先 blocked,再判 adopted/structured |
| bindHandleReattachResult | isReattach true、空回放、客户端睡眠 done note,使 renderer 断开、清绑定并 cold resume | window 保留 live reattach;main-owned startPane 继续由主机仲裁 |
| runDeferredSessionReattachChoice | 前一请求 null 或 generation 不同,直接 fresh | 本次尝试失败,不新建也不把旧 generation 的 PTY 附着给新 generation |

这是一组可达的源码反例,不依赖测试数量来成立。反例不等于生产事件的完整调用来源;21:25 PTY 16 只有 provider-returned 的新进程证据,缺 launch origin,不作唯一归因。

执行主机拥有 PTY 和持久化绑定。本机 main 持有本机 proof;SSH 场景通过 getAppPtyId 对齐对应 connectionId 的 PTY 标识。配对 runtime 和旧 host 独立更新,本轮不更改 wire;失联仍为 unverifiable,不请求本机替代,不新增重连或轮询。测试隔离目录、2222 端口及 SSH fixture HOME 均位于验证机,不接触用户 Mac 的服务或 session。

主机缺 owner 后能等待并在归属恢复后重连,正常新建与 host-positive exit 都必须保留。空 viewport 仍可能涉及输出恢复;不能仅凭本轮 no-fresh 断言所有可见内容问题已解决。所有 REQ 的整体验收状态继续以 journal 为准。
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 2026-11-09 源码复核后的恢复准入

本轮沿 renderer pane → IPC spawn → stable owner → provider 审查,确认 #91 只修复认领 fallback。补充以下约束:

- 数字 sessionId 的既有 pane 连接,owner 缺失时拒绝进入 fresh;只允许同一执行主机给出的 `absentOwner` 或明确停止后的 replacement 放行。检查位于所有 IPC/runtime fresh 的共同入口,不新增 wire 字段。
- 多个 surface 同时声明一个 PTY 是 `unverifiable`,不能当作已恢复。任一 live PTY declined,整体不得先返回 adopted/structured。
- 客户端睡眠记录和没有回放的 attach 结果不能证明进程退出。window-owned 路径保留 live reattach,不先清绑定再启动新 shell。main-owned 显式 startPane 仍由 host 仲裁。
- pending start 返回 null 时不立即再启动;结束本次附着为失败,等待既有连接/归属恢复入口或明确用户动作。旧 generation 的 pending start 也先等待结果,不因 generation 不同并行启动。

原 tab/leaf 的新建与关闭仍走既有 Store;本轮不根据名字或空画面删除终端。numeric ID 复用不能绕过 provider 已有的拒绝策略。

本机文件、进程、provider 和绑定由本机 main 拥有;SSH 文件、进程和服务由 SSH 执行主机拥有。共享 spawn guard 按 `getAppPtyId(connectionId, sessionId)` 比对主机自己的退出证明。SSH 失联继续交给连接层;本功能不重连、不定时探测,不把失联作为 `exited`。配对 runtime wire 不变,旧 peer 行为仍须单独标注验证边界。

以下历史设计保留当时决策,不能据其窄版 approved 状态声称本轮完整发布或安装成功。

---
title: 手机工作区原终端身份恢复方案
type: solution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,12 @@ flowchart LR
- 自动入口:`numeric-terminal-surface-recovery.test.ts`;真实应用 `mobile-terminal-surface-recovery.spec.ts` 的 numeric fallback provider 用例及 SSH 用例。
- 证据:本次数字回归修改前4项失败、修改后通过;真实 local fallback provider 产生数字 PTY 后,经手机激活恢复原 tab/leaf、相同 incarnation/root PID 和 shell 中的随机变量,再次执行可读到原变量。图像与身份快照位于 `.docs/mobile-terminal-recovery-ui-validation/2026-11-09/evidence/numeric-app/`;SSH 验证位于同目录 `ssh-app/`。
- 边界:SSH 真机回归覆盖现行 managed server 路由与旧 host 混合版本,不宣称远端 relay 数字编号可被本地 provider 同样处理;裸编号的跨工作区冲突策略由权威清单回归覆盖。

## TC-023 源码反例:既有 pane 准入与不确定结果

- 关联:REQ-001、REQ-002、REQ-003、REQ-004、REQ-006、REQ-008。
- 前置:数字 provider,仍 live 原 PTY;旧 pane/窗口和主机状态可能暂不同步。
- 步骤与预期:缺 stable owner 的数字 restore 在 provider 调用前拒绝;补回 owner 后接回原进程;typed SessionNotFound 后可 fresh;普通不带 sessionId 的新建仍成功。两 surface 同时声明该 PTY 与一成功一 declined 时均 blocked,不 mint、不自动删除。live isReattach 为空回放且有 hibernation note 时不 disconnect/clear/fresh。pending null 或旧 generation 不直接启动。
- 本机证据:实际 numeric fallback E2E 不再用虚拟 900001 作为首次启动 ID,直接创建真实数字 PTY;额外无 owner 数字请求被拒绝,三次手机激活仍保留 tab/leaf/PTY/incarnation/root PID、shell nonce 与后续输出。
- SSH:隔离 root sshd 和执行主机 Git/folder 现有路径复跑,检查远端身份、root PID、画面和后续命令;旧服务端只作为混合版本兼容证据,不冒称旧 server 已获得新的主机 guard。
- 执行状态:testing;结果与未验证边界见本轮 journal 和 `.docs/mobile-terminal-recovery-ui-validation/2026-11-09-source-audit/`。
Loading
Loading