work-ally 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/AGENTS.md +110 -0
  2. package/DASHBOARD.md +160 -0
  3. package/PRODUCT.md +113 -0
  4. package/README.md +403 -0
  5. package/ally.sh +171 -0
  6. package/bridge/src/approval-rules.ts +360 -0
  7. package/bridge/src/channel-delivery.ts +207 -0
  8. package/bridge/src/channel-types.ts +22 -0
  9. package/bridge/src/channels/fake/adapter.ts +31 -0
  10. package/bridge/src/channels/feishu/adapter.ts +411 -0
  11. package/bridge/src/channels/feishu/approvals.ts +6 -0
  12. package/bridge/src/channels/feishu/formatter.ts +276 -0
  13. package/bridge/src/channels/feishu/normalize.ts +368 -0
  14. package/bridge/src/codex-config.ts +52 -0
  15. package/bridge/src/config.ts +240 -0
  16. package/bridge/src/fake-runtime-client.ts +505 -0
  17. package/bridge/src/handoff-service.ts +494 -0
  18. package/bridge/src/logger.ts +194 -0
  19. package/bridge/src/memory-digest.ts +186 -0
  20. package/bridge/src/receiver-approval-autonomy.ts +158 -0
  21. package/bridge/src/receiver-control-core.ts +140 -0
  22. package/bridge/src/receiver-control-work-session.ts +218 -0
  23. package/bridge/src/receiver-control.ts +83 -0
  24. package/bridge/src/receiver-delivery.ts +136 -0
  25. package/bridge/src/receiver-helpers.ts +96 -0
  26. package/bridge/src/receiver-human-gate.ts +333 -0
  27. package/bridge/src/receiver-inbound-preflight.ts +162 -0
  28. package/bridge/src/receiver-recovery.ts +236 -0
  29. package/bridge/src/receiver-runtime-callbacks.ts +367 -0
  30. package/bridge/src/receiver-runtime-policy.ts +132 -0
  31. package/bridge/src/receiver-runtime-state.ts +124 -0
  32. package/bridge/src/receiver-support-actions.ts +189 -0
  33. package/bridge/src/receiver-thread-start.ts +57 -0
  34. package/bridge/src/receiver-turn-coordination.ts +94 -0
  35. package/bridge/src/receiver-turn-execution.ts +257 -0
  36. package/bridge/src/receiver-turn-failure.ts +143 -0
  37. package/bridge/src/receiver-turn-result.ts +185 -0
  38. package/bridge/src/receiver-turn-steer.ts +70 -0
  39. package/bridge/src/receiver-work-session.ts +76 -0
  40. package/bridge/src/receiver.ts +329 -0
  41. package/bridge/src/router.ts +62 -0
  42. package/bridge/src/runtime-client-agent-messages.ts +150 -0
  43. package/bridge/src/runtime-client-message-dispatch.ts +176 -0
  44. package/bridge/src/runtime-client-protocol.ts +411 -0
  45. package/bridge/src/runtime-client-request-ops.ts +56 -0
  46. package/bridge/src/runtime-client-run-turn.ts +158 -0
  47. package/bridge/src/runtime-client-thread-ops.ts +270 -0
  48. package/bridge/src/runtime-client-transport.ts +309 -0
  49. package/bridge/src/runtime-client-turn-poll.ts +224 -0
  50. package/bridge/src/runtime-client-turn-read.ts +185 -0
  51. package/bridge/src/runtime-client-turn-state.ts +105 -0
  52. package/bridge/src/runtime-client.ts +344 -0
  53. package/bridge/src/runtime-user-input.ts +403 -0
  54. package/bridge/src/scheduler.ts +239 -0
  55. package/bridge/src/server-handoff-command.ts +364 -0
  56. package/bridge/src/server-main.ts +80 -0
  57. package/bridge/src/server-routine-command.ts +60 -0
  58. package/bridge/src/server-routine-execution.ts +222 -0
  59. package/bridge/src/server-runtime-app-support.ts +107 -0
  60. package/bridge/src/server-runtime-app.ts +238 -0
  61. package/bridge/src/server-thread-sync-command.ts +63 -0
  62. package/bridge/src/server.ts +17 -0
  63. package/bridge/src/session-store-delivery.ts +220 -0
  64. package/bridge/src/session-store-human-gate.ts +380 -0
  65. package/bridge/src/session-store-inbound-acceptance.ts +66 -0
  66. package/bridge/src/session-store-meta.ts +134 -0
  67. package/bridge/src/session-store-turn-ledger.ts +272 -0
  68. package/bridge/src/session-store.ts +380 -0
  69. package/bridge/src/system-notify.ts +220 -0
  70. package/bridge/src/thread-sync.ts +200 -0
  71. package/bridge/src/translator.ts +494 -0
  72. package/bridge/src/types.ts +289 -0
  73. package/bridge/src/utils.ts +104 -0
  74. package/bridge/src/work-session-store.ts +471 -0
  75. package/docs/.gitkeep +0 -0
  76. package/docs/architecture/codex-feishu-bridge-proposal.md +2742 -0
  77. package/docs/completed/FEATURE-feishu-markdown-and-reply-support.md +327 -0
  78. package/docs/completed/README.md +21 -0
  79. package/docs/completed/SPEC-approval-autonomy-and-safe-defaults.md +205 -0
  80. package/docs/completed/SPEC-approval-batch-and-strict-reply-shortcuts.md +153 -0
  81. package/docs/completed/SPEC-conversation-noise-reduction-and-busy-input-gate.md +538 -0
  82. package/docs/completed/SPEC-engineering-sop-skillization.md +190 -0
  83. package/docs/completed/SPEC-faithful-bridge-core-thinning-v2.md +376 -0
  84. package/docs/completed/SPEC-faithful-bridge-core-thinning.md +1071 -0
  85. package/docs/completed/SPEC-group-chat-sender-identity.md +301 -0
  86. package/docs/completed/SPEC-middleware-exception-visibility.md +227 -0
  87. package/docs/completed/SPEC-nightly-memory-digest-visibility.md +121 -0
  88. package/docs/completed/SPEC-project-group-chat-human-centered-conversation-mapping.md +326 -0
  89. package/docs/completed/SPEC-remove-cli-persona-bootstrap.md +201 -0
  90. package/docs/developer-workflow.md +49 -0
  91. package/docs/implementation/SPEC-codex-same-machine-session-handoff-implementation.md +239 -0
  92. package/docs/implementation/test-coverage-map.md +363 -0
  93. package/docs/implementation/work-ally-implementation-guide.md +790 -0
  94. package/docs/issues/README.md +10 -0
  95. package/docs/issues/pending/ANALYSIS-ally-premature-recovery-notice-and-task-state-semantics-2026-03-18.md +295 -0
  96. package/docs/issues/resolved/ANALYSIS-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +466 -0
  97. package/docs/issues/resolved/ANALYSIS-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +261 -0
  98. package/docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md +606 -0
  99. package/docs/issues/resolved/ANALYSIS-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +348 -0
  100. package/docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md +603 -0
  101. package/docs/issues/resolved/ANALYSIS-self-test-gap-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +166 -0
  102. package/docs/issues/resolved/ANALYSIS-self-test-gap-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +186 -0
  103. package/docs/issues/resolved/ANALYSIS-self-test-gap-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +166 -0
  104. package/docs/issues/resolved/REPORT-ally-runtime-turn-delivery-3b42fb8-2026-03-15.md +373 -0
  105. package/docs/manual-acceptance.md +127 -0
  106. package/docs/ops-runbook.md +44 -0
  107. package/docs/planning/FEATURE-memory-system.md +748 -0
  108. package/docs/planning/SPEC-active-turn-steer-and-context-compaction-visibility.md +269 -0
  109. package/docs/planning/SPEC-approval-rules-inheritance-and-local-validation-lane.md +450 -0
  110. package/docs/planning/SPEC-assistant-persona-bootstrap.md +199 -0
  111. package/docs/planning/SPEC-assistant-rename.md +610 -0
  112. package/docs/planning/SPEC-bridge-app-server-protocol-alignment.md +667 -0
  113. package/docs/planning/SPEC-claude-runtime-host-for-work-ally.md +434 -0
  114. package/docs/planning/SPEC-cli-feishu-codex-session-unification.md +236 -0
  115. package/docs/planning/SPEC-codex-same-machine-session-handoff.md +873 -0
  116. package/docs/planning/SPEC-feishu-reaction-shortcuts.md +282 -0
  117. package/docs/planning/SPEC-local-stable-release-boundary.md +166 -0
  118. package/docs/planning/SPEC-managed-thread-entry-and-surface-mobility.md +862 -0
  119. package/docs/planning/SPEC-minimal-bridge-semantics-and-user-visible-surface.md +362 -0
  120. package/docs/planning/SPEC-npm-alpha-distribution-and-install-first-release.md +222 -0
  121. package/docs/planning/SPEC-remove-websocket-runtime-transport.md +364 -0
  122. package/docs/planning/SPEC-runtime-abstraction-phase-1.md +424 -0
  123. package/docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md +274 -0
  124. package/docs/planning/SPEC-session-presence-and-state-visibility.md +397 -0
  125. package/docs/planning/SPEC-skill-first-capability-packaging.md +338 -0
  126. package/docs/planning/SPEC-stable-archive-contract.md +456 -0
  127. package/docs/planning/SPEC-supervised-start-boundary.md +127 -0
  128. package/docs/planning/SPEC-user-barrier-reduction-and-activation.md +832 -0
  129. package/docs/planning/ally-next.md +1278 -0
  130. package/docs/planning/assistant-workbench-spec.md +725 -0
  131. package/docs/planning/product-workbench.md +283 -0
  132. package/docs/product-onboarding.md +227 -0
  133. package/docs/product-spec-standard.md +528 -0
  134. package/docs/troubleshooting.md +45 -0
  135. package/docs/user-quickstart.md +46 -0
  136. package/internal/dispatch.sh +95 -0
  137. package/internal/lib/common.sh +1450 -0
  138. package/internal/modules/assistant/manage.sh +1312 -0
  139. package/internal/modules/bootstrap/setup.sh +144 -0
  140. package/internal/modules/config/init-env.sh +10 -0
  141. package/internal/modules/global/manage.sh +154 -0
  142. package/internal/modules/handoff/manage.sh +54 -0
  143. package/internal/modules/mcp/manage.sh +83 -0
  144. package/internal/modules/ops/logs.sh +76 -0
  145. package/internal/modules/routines/manage.sh +55 -0
  146. package/internal/modules/runtime/assistant-autosave.sh +26 -0
  147. package/internal/modules/runtime/restart.sh +6 -0
  148. package/internal/modules/runtime/start.sh +283 -0
  149. package/internal/modules/runtime/status.sh +194 -0
  150. package/internal/modules/runtime/stop.sh +55 -0
  151. package/internal/modules/runtime/supervisor.sh +216 -0
  152. package/internal/modules/runtime/update.sh +26 -0
  153. package/package.json +41 -0
  154. package/runtime/config/.gitkeep +0 -0
  155. package/runtime/host/.gitkeep +0 -0
  156. package/runtime/host/healthcheck-codex-app-server.ts +22 -0
  157. package/runtime/host/ping-pong-codex-app-server.ts +66 -0
  158. package/runtime/host/probe-codex-app-server.ts +115 -0
  159. package/skills/archive-reader/SKILL.md +9 -0
  160. package/skills/feishu-production-debug/SKILL.md +37 -0
  161. package/skills/feishu-production-debug/references/feishu-debug-order.md +49 -0
  162. package/skills/feishu-production-debug/references/platform-permission-baseline.md +23 -0
  163. package/skills/issue-to-spec-triage/SKILL.md +44 -0
  164. package/skills/issue-to-spec-triage/references/triage-rules.md +66 -0
  165. package/skills/memory-digest/SKILL.md +9 -0
  166. package/skills/post-implementation-closure/SKILL.md +39 -0
  167. package/skills/post-implementation-closure/references/closure-checklist.md +45 -0
  168. package/skills/post-implementation-closure/references/doc-drift-map.md +49 -0
  169. package/skills/product-spec/SKILL.md +244 -0
  170. package/templates/env.example +5 -0
  171. package/templates/routines/nightly-memory-digest.yaml +10 -0
  172. package/templates/workspace/AGENTS.md +26 -0
@@ -0,0 +1,10 @@
1
+ # Issues
2
+
3
+ `docs/issues/` 用来放问题调查、事故分析和问题演进材料。
4
+
5
+ 从现在开始,这里分成两层:
6
+
7
+ - `pending/`:还没真正修完、后续仍要继续推进落地的问题
8
+ - `resolved/`:已经完成收口,保留作问题演进痕迹和历史证据
9
+
10
+ 当前应优先关注 `pending/`。只有当实现、验证和文档都收口后,才应把对应材料移入 `resolved/`。
@@ -0,0 +1,295 @@
1
+ # 分析报告:Ally 首轮误发 recovery notice 与“任务状态”语义偏厚问题
2
+
3
+ 更新时间:2026-03-18
4
+ 状态:待修复 / 待收口
5
+ 作者:Codex
6
+
7
+ ## 1. 这份报告回答什么
8
+
9
+ 这份文档回答两个直接相关的问题:
10
+
11
+ 1. 为什么 `Ally` 在 2026-03-18 14:40 左右,刚启动后收到第一条消息,就立刻向用户发出:
12
+ `【系统消息】 当前任务状态暂未确认,正在继续核对这一轮结果。`
13
+ 2. `work-ally` 当前是否引入了一层不必要的“任务状态”用户语义;如果是,它和官方 Codex App Server 推荐的原语之间到底是什么关系。
14
+
15
+ 这不是单纯排查一句文案,也不是单纯排查一个竞态 bug。
16
+
17
+ 这次问题同时暴露了两层缺口:
18
+
19
+ - 一层是实现缺口:bridge 在 turn 刚启动后的极短窗口内,过早把一次暂态对账失败升级成了 recovery notice。
20
+ - 一层是产品语义缺口:bridge 仍在用“任务状态”这类本地二次解释去面向用户表达协议事实,这与“克制中间层、尽量贴近官方 App Server 原语”的方向存在张力。
21
+
22
+ ## 2. 背景问题
23
+
24
+ 用户当前对 `work-ally` 的核心诉求很明确:
25
+
26
+ - 只做非常克制的中间层。
27
+ - 重点负责“人 <-> Codex”之间消息往返的稳定转交。
28
+ - 允许保留少量必要中间能力,例如自动审批、补拉最终结果、必要重发提示。
29
+ - 不希望 bridge 变成一套自作主张的任务引擎,也不希望引入一层难以和官方文档对齐的厚语义。
30
+
31
+ 在这个背景下,`Ally` 启动后第一句就收到“当前任务状态暂未确认”,会让人自然质疑两件事:
32
+
33
+ 1. 这是不是一个真实故障。
34
+ 2. bridge 是否已经越过“协议事实转发器 + 最小编排器”的边界,开始替用户解释一套自己的“任务状态”。
35
+
36
+ ## 3. 官方原语与我们当前说法的关系
37
+
38
+ 先把官方模型说清楚。
39
+
40
+ 根据 OpenAI 官方 `Codex App Server` 文档与《Unlocking the Codex harness》一文,客户端真正需要围绕的是这些原语:
41
+
42
+ - `thread`
43
+ - `turn`
44
+ - `item`
45
+ - `thread.status`
46
+ - `turn.status`
47
+ - server-initiated request(例如 approval)
48
+
49
+ 官方对 conversation primitives 的定义是:
50
+
51
+ - `item` 是原子输入输出单元,具有 `item/started`、可选 `item/*/delta`、`item/completed` 生命周期。
52
+ - `turn` 是由用户输入触发的一次 agent 工作单元。
53
+ - `thread` 是可持久化的会话容器,持有多个 turn。
54
+
55
+ 官方还明确说明:
56
+
57
+ - `thread/read(includeTurns=true)` 可以读取线程与 turn 历史。
58
+ - `thread.status` 是 runtime status,类型是 `notLoaded`、`idle`、`systemError`、`active`;如果是 `active`,可能带 `activeFlags`,例如 `waitingOnApproval`。
59
+ - `turn/completed` 才携带 turn 的最终状态,终态是 `completed`、`interrupted`、`failed`。
60
+ - 审批这类 server request 会暂停 turn,直到客户端回复。
61
+
62
+ 重要的是:
63
+
64
+ > 官方协议里没有一个独立命名、独立建模的“任务状态(task state)”原语。
65
+
66
+ 因此,bridge 当前面向用户说的“当前任务状态暂未确认”,并不是官方 App Server 原生状态;它只是我们拿 `thread.status`、`turn` 终态对账结果、以及本地 recovery 判断,二次翻译出来的一句中文。
67
+
68
+ 这件事本身不一定绝对错误,但它说明我们当前前台语义已经不再是“直接贴协议事实”,而是“在协议事实之上加了一层本地产品解释”。
69
+
70
+ ## 4. 现场证据
71
+
72
+ ### 4.1 事件时间与对象
73
+
74
+ - 助理:`Ally`
75
+ - 办公桌:`/Users/allenfeng/.work-ally/assistants/Ally`
76
+ - 会话:`feishu--oc_1890ff7f9132a7d90b09765f27ff5bc8`
77
+ - 本地时间:2026-03-18 14:40 左右(Asia/Shanghai)
78
+ - 对应日志时间:`2026-03-18T06:40Z`
79
+
80
+ ### 4.2 bridge 日志事实链
81
+
82
+ `/Users/allenfeng/.work-ally/assistants/Ally/.system/logs/bridge-2026-03-18.log`
83
+
84
+ 关键事实如下:
85
+
86
+ 1. `06:40:33Z`,bridge 收到用户消息:`你还在吗?好久不见,最近这个项目有什么新的进展?`
87
+ 2. `06:40:37.186Z`,turn 正常启动。
88
+ 3. `06:40:37.712Z`,仅约 0.5 秒后,bridge 记录:
89
+ `runtime turn reconciliation failed: idle thread without completed turn event (...)`
90
+ 4. 同一时刻,receiver 进入 `turn_recovery_attempt`。
91
+ 5. 紧接着,bridge 向前台发送了一条系统消息;这条消息对应的文案就是:
92
+ `当前任务状态暂未确认,正在继续核对这一轮结果。`
93
+ 6. 但 `06:41:07.638Z`,真正的 `runtime.turn_completed_event` 到达,状态是 `completed`。
94
+ 7. `06:41:08.134Z`,bridge 记录 `receiver.turn_recovered`。
95
+ 8. `06:41:09.478Z`,最终回复成功送达前台。
96
+
97
+ 这条事实链说明:
98
+
99
+ - 这轮 turn 并没有真正失败。
100
+ - 前台收到 recovery notice 时,bridge 只是“本地暂未对账成功”,不是 Codex App Server 已经宣告 turn 失败。
101
+ - 这句系统消息不是来自官方 turn 终态,而是来自 bridge 本地 recovery 分支。
102
+
103
+ ### 4.3 持久化 turn 记录事实
104
+
105
+ `/Users/allenfeng/.work-ally/assistants/Ally/.system/runtime/sessions/feishu--oc_1890ff7f9132a7d90b09765f27ff5bc8/turns/2026-03-18T06-40-37-186Z-019cffac-bf45-7c13-93d3-c574ac4bdc88.json`
106
+
107
+ 该文件最终记录的是:
108
+
109
+ - `status: completed`
110
+ - `completedAt: 2026-03-18T06:41:08.136Z`
111
+
112
+ 也就是说,持久化真相明确表明:
113
+
114
+ > turn 最终完成了。
115
+
116
+ 因此,14:40 用户看到的那句系统消息,描述的不是 turn 的真实最终状态,而是 bridge 在 recovery 过程中的一个过早、过度外显的中间判断。
117
+
118
+ ### 4.4 代码层证据
119
+
120
+ 相关代码位置:
121
+
122
+ - `bridge/src/runtime-client.ts`
123
+ - `bridge/src/receiver.ts`
124
+ - `bridge/src/translator.ts`
125
+
126
+ 当前实现链路如下:
127
+
128
+ 1. `runtime-client.ts` 在 `pollTurnFinalState()` 中,如果 thread 已经进入 `idle`,但本地还没有拿到 `completedEventResult`,就会抛出:
129
+ `runtime turn reconciliation failed: idle thread without completed turn event (...)`
130
+ 2. `receiver.ts` 捕获到这类错误后,会进入 `turn_recovery_attempt`。
131
+ 3. 在 recovery attempt 开始时,receiver 会主动往前台发一条 `progress_update`。
132
+ 4. 这条 `progress_update` 的文本定义在 `translator.ts`,固定就是:
133
+ `当前任务状态暂未确认,正在继续核对这一轮结果。`
134
+
135
+ 所以这条系统消息的触发条件,不是官方协议里出现了某个“task state = unknown”,而是:
136
+
137
+ > 我们自己的 runtime-client 在某个时间窗内,没有拿到足够的终态证据,于是本地转入 recovery path,并主动向用户暴露了一条自己翻译出来的状态文案。
138
+
139
+ ## 5. 我的思考
140
+
141
+ ### 5.1 这次 bug 真正是什么
142
+
143
+ 这次 bug 不是 transport 真断了,也不是 Codex 真告诉用户“任务状态不明”。
144
+
145
+ 它本质上是:
146
+
147
+ - turn 刚启动。
148
+ - bridge 很快看到 thread 落到 `idle`。
149
+ - 但 `turn/completed` 事件还没来,或还没被本地拿到。
150
+ - bridge 过早把这一瞬间解释成“终态待恢复”。
151
+ - 于是前台先收到一条恢复型系统消息。
152
+ - 几十秒后,turn 其实又正常完成并送达了。
153
+
154
+ 所以从第一性原理看,这是一种**过早 recovery 可见化**问题。
155
+
156
+ 更准确地说:
157
+
158
+ > 本地对账机制本来是为了提升可靠性,但它在一个很短的正常时序抖动窗口里,被过早上升成了用户可见语义。
159
+
160
+ ### 5.2 “任务状态”是不是必要概念
161
+
162
+ 我的判断是分两层。
163
+
164
+ 第一层,内部实现层:
165
+
166
+ - 需要有最小 execution / delivery / recovery 状态。
167
+ - 需要有 ledger。
168
+ - 需要区分 `pending_recovery`、`delivery_unavailable`、`recovery_required` 等内部事实。
169
+
170
+ 这层是必要的,因为它支撑稳定补偿、补读、补发,不应轻易删除。
171
+
172
+ 第二层,用户语义层:
173
+
174
+ - “任务状态”这个说法不属于官方协议原语。
175
+ - 它会把 bridge 自己的对账不确定性,包装成“Codex 的任务状态”。
176
+ - 这容易让用户误以为自己看到的是一条权威协议事实。
177
+
178
+ 这层我认为不必要,至少不应该成为默认用户词汇。
179
+
180
+ 更克制的做法应该是:
181
+
182
+ - 内部继续保留 recovery / ledger。
183
+ - 前台尽量只暴露协议事实本身,或者只暴露最小动作提示。
184
+
185
+ ### 5.3 前台到底应该暴露什么
186
+
187
+ 我认为前台可以分成三类信息。
188
+
189
+ 第一类:用户必须立刻行动的。
190
+
191
+ - 等审批
192
+ - 等补充输入
193
+ - 明确需要重发上一条消息
194
+
195
+ 这类应该保留,而且可以直接对齐官方 `waitingOnApproval` 等事实。
196
+
197
+ 第二类:最终失败且无法自动补偿的。
198
+
199
+ - 例如补拉失败,bridge 无法证明这轮是否已完成,只能要求用户重发
200
+
201
+ 这类也应保留。
202
+
203
+ 第三类:bridge 自己正在内部补对账的短暂过程。
204
+
205
+ - 例如这次 14:40 这种,最终几十秒后自己恢复并补齐了结果
206
+
207
+ 这类默认不应前台外显,至少不应立刻外显。
208
+
209
+ 如果真的必须外显,也应尽量贴近协议与实现事实,比如:
210
+
211
+ - `reconciling latest turn result`
212
+ - `recovering final turn result`
213
+
214
+ 而不是说成“当前任务状态暂未确认”。
215
+
216
+ 因为后者已经是一层偏厚的解释。
217
+
218
+ ## 6. 最终合理的修改建议
219
+
220
+ 下面的建议分成“必须改”和“应该收口”两层。
221
+
222
+ ### 6.1 必须改:修掉这次首轮误发 recovery notice 的 bug
223
+
224
+ 目标不是删 recovery,而是避免它在正常短时序抖动窗口里过早前台可见。
225
+
226
+ 建议:
227
+
228
+ 1. 保留内部 `pending_recovery` / `recoverTurnResult` / ledger。
229
+ 2. 收紧 fresh turn 启动后的 recovery 触发条件,不要在 turn 刚启动后的极短窗口里,仅凭一次 `idle + 无 completedEventResult` 就立刻发前台 notice。
230
+ 3. 优先等待更可靠的 turn 终态证据,再决定是否对用户可见。
231
+ 4. 将“开始 recovery”与“需要前台提示”拆成两个阶段:
232
+ - 内部先 recovery
233
+ - 只有超出短暂窗口仍未收敛,才考虑用户可见化
234
+
235
+ 这样改动不会损害稳定性骨架,反而会减少误报。
236
+
237
+ ### 6.2 应该收口:去掉默认用户语汇里的“任务状态”
238
+
239
+ 建议默认不再用:
240
+
241
+ - `当前任务状态暂未确认`
242
+ - `当前任务状态待确认`
243
+
244
+ 原因很简单:
245
+
246
+ - 它们不是官方协议原语。
247
+ - 它们混淆了 bridge 内部对账状态与 Codex 的 thread / turn 事实。
248
+ - 它们让中间层看起来像“任务裁判”,而不是“协议事实转发器 + 最小编排器”。
249
+
250
+ ### 6.3 应该保留:内部稳定性机制不要因为收薄语义而被误删
251
+
252
+ 本次收口不应动这些底层能力:
253
+
254
+ - `thread/read(includeTurns=true)` 的 pull-primary 对账
255
+ - inbound / turn / delivery ledger
256
+ - `delivery_unavailable` 后续补发
257
+ - waiting approval / waiting user input 承接
258
+ - `recovery_required` 时的明确用户兜底
259
+
260
+ 原因是:
261
+
262
+ > 我们要收薄的是“用户语义层”,不是“可靠性交付层”。
263
+
264
+ ### 6.4 推荐的前台暴露原则
265
+
266
+ 后续用户可见语义建议统一按下面原则约束:
267
+
268
+ 1. 能直接对应官方协议事实的,优先直接对应,不额外翻译厚化。
269
+ 2. 不需要用户行动的短暂内部恢复过程,默认静默。
270
+ 3. 只有以下两类事情值得主动打断用户:
271
+ - 需要用户立刻动作
272
+ - 已确认无法自动恢复,需要用户补救
273
+ 4. 若确实要暴露中间恢复过程,使用贴协议、贴实现事实的表述,不使用“任务状态”这种二次抽象。
274
+
275
+ ## 7. 一句话结论
276
+
277
+ 这次 14:40 的问题,表层是一个 recovery notice 误触发 bug;深层是 bridge 仍保留了一层偏厚的“任务状态”前台语义。
278
+
279
+ 合理的修正方向不是削掉内部稳定性机制,而是:
280
+
281
+ > 保留最小 recovery / ledger 骨架,修掉误触发,把默认前台语言从“任务状态”收回到更克制、更贴官方 App Server 原语的表达。
282
+
283
+ ## 8. 相关材料
284
+
285
+ 仓库内相关材料:
286
+
287
+ - `docs/planning/SPEC-bridge-app-server-protocol-alignment.md`
288
+ - `docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md`
289
+ - `docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md`
290
+ - `docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md`
291
+
292
+ 外部参考:
293
+
294
+ - OpenAI Developers: `Codex App Server`
295
+ - OpenAI Engineering: `Unlocking the Codex harness: how we built the App Server`