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.
- package/AGENTS.md +110 -0
- package/DASHBOARD.md +160 -0
- package/PRODUCT.md +113 -0
- package/README.md +403 -0
- package/ally.sh +171 -0
- package/bridge/src/approval-rules.ts +360 -0
- package/bridge/src/channel-delivery.ts +207 -0
- package/bridge/src/channel-types.ts +22 -0
- package/bridge/src/channels/fake/adapter.ts +31 -0
- package/bridge/src/channels/feishu/adapter.ts +411 -0
- package/bridge/src/channels/feishu/approvals.ts +6 -0
- package/bridge/src/channels/feishu/formatter.ts +276 -0
- package/bridge/src/channels/feishu/normalize.ts +368 -0
- package/bridge/src/codex-config.ts +52 -0
- package/bridge/src/config.ts +240 -0
- package/bridge/src/fake-runtime-client.ts +505 -0
- package/bridge/src/handoff-service.ts +494 -0
- package/bridge/src/logger.ts +194 -0
- package/bridge/src/memory-digest.ts +186 -0
- package/bridge/src/receiver-approval-autonomy.ts +158 -0
- package/bridge/src/receiver-control-core.ts +140 -0
- package/bridge/src/receiver-control-work-session.ts +218 -0
- package/bridge/src/receiver-control.ts +83 -0
- package/bridge/src/receiver-delivery.ts +136 -0
- package/bridge/src/receiver-helpers.ts +96 -0
- package/bridge/src/receiver-human-gate.ts +333 -0
- package/bridge/src/receiver-inbound-preflight.ts +162 -0
- package/bridge/src/receiver-recovery.ts +236 -0
- package/bridge/src/receiver-runtime-callbacks.ts +367 -0
- package/bridge/src/receiver-runtime-policy.ts +132 -0
- package/bridge/src/receiver-runtime-state.ts +124 -0
- package/bridge/src/receiver-support-actions.ts +189 -0
- package/bridge/src/receiver-thread-start.ts +57 -0
- package/bridge/src/receiver-turn-coordination.ts +94 -0
- package/bridge/src/receiver-turn-execution.ts +257 -0
- package/bridge/src/receiver-turn-failure.ts +143 -0
- package/bridge/src/receiver-turn-result.ts +185 -0
- package/bridge/src/receiver-turn-steer.ts +70 -0
- package/bridge/src/receiver-work-session.ts +76 -0
- package/bridge/src/receiver.ts +329 -0
- package/bridge/src/router.ts +62 -0
- package/bridge/src/runtime-client-agent-messages.ts +150 -0
- package/bridge/src/runtime-client-message-dispatch.ts +176 -0
- package/bridge/src/runtime-client-protocol.ts +411 -0
- package/bridge/src/runtime-client-request-ops.ts +56 -0
- package/bridge/src/runtime-client-run-turn.ts +158 -0
- package/bridge/src/runtime-client-thread-ops.ts +270 -0
- package/bridge/src/runtime-client-transport.ts +309 -0
- package/bridge/src/runtime-client-turn-poll.ts +224 -0
- package/bridge/src/runtime-client-turn-read.ts +185 -0
- package/bridge/src/runtime-client-turn-state.ts +105 -0
- package/bridge/src/runtime-client.ts +344 -0
- package/bridge/src/runtime-user-input.ts +403 -0
- package/bridge/src/scheduler.ts +239 -0
- package/bridge/src/server-handoff-command.ts +364 -0
- package/bridge/src/server-main.ts +80 -0
- package/bridge/src/server-routine-command.ts +60 -0
- package/bridge/src/server-routine-execution.ts +222 -0
- package/bridge/src/server-runtime-app-support.ts +107 -0
- package/bridge/src/server-runtime-app.ts +238 -0
- package/bridge/src/server-thread-sync-command.ts +63 -0
- package/bridge/src/server.ts +17 -0
- package/bridge/src/session-store-delivery.ts +220 -0
- package/bridge/src/session-store-human-gate.ts +380 -0
- package/bridge/src/session-store-inbound-acceptance.ts +66 -0
- package/bridge/src/session-store-meta.ts +134 -0
- package/bridge/src/session-store-turn-ledger.ts +272 -0
- package/bridge/src/session-store.ts +380 -0
- package/bridge/src/system-notify.ts +220 -0
- package/bridge/src/thread-sync.ts +200 -0
- package/bridge/src/translator.ts +494 -0
- package/bridge/src/types.ts +289 -0
- package/bridge/src/utils.ts +104 -0
- package/bridge/src/work-session-store.ts +471 -0
- package/docs/.gitkeep +0 -0
- package/docs/architecture/codex-feishu-bridge-proposal.md +2742 -0
- package/docs/completed/FEATURE-feishu-markdown-and-reply-support.md +327 -0
- package/docs/completed/README.md +21 -0
- package/docs/completed/SPEC-approval-autonomy-and-safe-defaults.md +205 -0
- package/docs/completed/SPEC-approval-batch-and-strict-reply-shortcuts.md +153 -0
- package/docs/completed/SPEC-conversation-noise-reduction-and-busy-input-gate.md +538 -0
- package/docs/completed/SPEC-engineering-sop-skillization.md +190 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning-v2.md +376 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning.md +1071 -0
- package/docs/completed/SPEC-group-chat-sender-identity.md +301 -0
- package/docs/completed/SPEC-middleware-exception-visibility.md +227 -0
- package/docs/completed/SPEC-nightly-memory-digest-visibility.md +121 -0
- package/docs/completed/SPEC-project-group-chat-human-centered-conversation-mapping.md +326 -0
- package/docs/completed/SPEC-remove-cli-persona-bootstrap.md +201 -0
- package/docs/developer-workflow.md +49 -0
- package/docs/implementation/SPEC-codex-same-machine-session-handoff-implementation.md +239 -0
- package/docs/implementation/test-coverage-map.md +363 -0
- package/docs/implementation/work-ally-implementation-guide.md +790 -0
- package/docs/issues/README.md +10 -0
- package/docs/issues/pending/ANALYSIS-ally-premature-recovery-notice-and-task-state-semantics-2026-03-18.md +295 -0
- package/docs/issues/resolved/ANALYSIS-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +466 -0
- package/docs/issues/resolved/ANALYSIS-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +261 -0
- package/docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md +606 -0
- package/docs/issues/resolved/ANALYSIS-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +348 -0
- package/docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md +603 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +166 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +186 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +166 -0
- package/docs/issues/resolved/REPORT-ally-runtime-turn-delivery-3b42fb8-2026-03-15.md +373 -0
- package/docs/manual-acceptance.md +127 -0
- package/docs/ops-runbook.md +44 -0
- package/docs/planning/FEATURE-memory-system.md +748 -0
- package/docs/planning/SPEC-active-turn-steer-and-context-compaction-visibility.md +269 -0
- package/docs/planning/SPEC-approval-rules-inheritance-and-local-validation-lane.md +450 -0
- package/docs/planning/SPEC-assistant-persona-bootstrap.md +199 -0
- package/docs/planning/SPEC-assistant-rename.md +610 -0
- package/docs/planning/SPEC-bridge-app-server-protocol-alignment.md +667 -0
- package/docs/planning/SPEC-claude-runtime-host-for-work-ally.md +434 -0
- package/docs/planning/SPEC-cli-feishu-codex-session-unification.md +236 -0
- package/docs/planning/SPEC-codex-same-machine-session-handoff.md +873 -0
- package/docs/planning/SPEC-feishu-reaction-shortcuts.md +282 -0
- package/docs/planning/SPEC-local-stable-release-boundary.md +166 -0
- package/docs/planning/SPEC-managed-thread-entry-and-surface-mobility.md +862 -0
- package/docs/planning/SPEC-minimal-bridge-semantics-and-user-visible-surface.md +362 -0
- package/docs/planning/SPEC-npm-alpha-distribution-and-install-first-release.md +222 -0
- package/docs/planning/SPEC-remove-websocket-runtime-transport.md +364 -0
- package/docs/planning/SPEC-runtime-abstraction-phase-1.md +424 -0
- package/docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md +274 -0
- package/docs/planning/SPEC-session-presence-and-state-visibility.md +397 -0
- package/docs/planning/SPEC-skill-first-capability-packaging.md +338 -0
- package/docs/planning/SPEC-stable-archive-contract.md +456 -0
- package/docs/planning/SPEC-supervised-start-boundary.md +127 -0
- package/docs/planning/SPEC-user-barrier-reduction-and-activation.md +832 -0
- package/docs/planning/ally-next.md +1278 -0
- package/docs/planning/assistant-workbench-spec.md +725 -0
- package/docs/planning/product-workbench.md +283 -0
- package/docs/product-onboarding.md +227 -0
- package/docs/product-spec-standard.md +528 -0
- package/docs/troubleshooting.md +45 -0
- package/docs/user-quickstart.md +46 -0
- package/internal/dispatch.sh +95 -0
- package/internal/lib/common.sh +1450 -0
- package/internal/modules/assistant/manage.sh +1312 -0
- package/internal/modules/bootstrap/setup.sh +144 -0
- package/internal/modules/config/init-env.sh +10 -0
- package/internal/modules/global/manage.sh +154 -0
- package/internal/modules/handoff/manage.sh +54 -0
- package/internal/modules/mcp/manage.sh +83 -0
- package/internal/modules/ops/logs.sh +76 -0
- package/internal/modules/routines/manage.sh +55 -0
- package/internal/modules/runtime/assistant-autosave.sh +26 -0
- package/internal/modules/runtime/restart.sh +6 -0
- package/internal/modules/runtime/start.sh +283 -0
- package/internal/modules/runtime/status.sh +194 -0
- package/internal/modules/runtime/stop.sh +55 -0
- package/internal/modules/runtime/supervisor.sh +216 -0
- package/internal/modules/runtime/update.sh +26 -0
- package/package.json +41 -0
- package/runtime/config/.gitkeep +0 -0
- package/runtime/host/.gitkeep +0 -0
- package/runtime/host/healthcheck-codex-app-server.ts +22 -0
- package/runtime/host/ping-pong-codex-app-server.ts +66 -0
- package/runtime/host/probe-codex-app-server.ts +115 -0
- package/skills/archive-reader/SKILL.md +9 -0
- package/skills/feishu-production-debug/SKILL.md +37 -0
- package/skills/feishu-production-debug/references/feishu-debug-order.md +49 -0
- package/skills/feishu-production-debug/references/platform-permission-baseline.md +23 -0
- package/skills/issue-to-spec-triage/SKILL.md +44 -0
- package/skills/issue-to-spec-triage/references/triage-rules.md +66 -0
- package/skills/memory-digest/SKILL.md +9 -0
- package/skills/post-implementation-closure/SKILL.md +39 -0
- package/skills/post-implementation-closure/references/closure-checklist.md +45 -0
- package/skills/post-implementation-closure/references/doc-drift-map.md +49 -0
- package/skills/product-spec/SKILL.md +244 -0
- package/templates/env.example +5 -0
- package/templates/routines/nightly-memory-digest.yaml +10 -0
- package/templates/workspace/AGENTS.md +26 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# Runtime Abstraction Phase 1
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
- Target project: `work-ally`
|
|
6
|
+
- Audience: product owner / implementation engineer
|
|
7
|
+
- Scope: runtime contract, Codex adapter refactor, bridge decoupling, compatibility guardrails
|
|
8
|
+
- Status: planning
|
|
9
|
+
- Goal: introduce a formal runtime abstraction layer behind the current Codex implementation without changing shipped product behavior
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
Phase 1 是一次**重构型 spec**,不是功能扩展 spec。
|
|
14
|
+
|
|
15
|
+
它要解决的问题不是“现在就支持 Claude”,而是:
|
|
16
|
+
|
|
17
|
+
> 先把 `work-ally` 里和底层 runtime 相关的隐式假设收成稳定 contract,并把当前 Codex 路径改造成第一套正式 implementation。
|
|
18
|
+
|
|
19
|
+
这条 spec 有一个硬约束:
|
|
20
|
+
|
|
21
|
+
> **Phase 1 做完后,现有用户功能、默认行为、产品语义都不应变化。**
|
|
22
|
+
|
|
23
|
+
也就是说:
|
|
24
|
+
|
|
25
|
+
- 现在用 Codex 的用户不需要学习新概念
|
|
26
|
+
- Feishu 侧现有 thread / approval / user input / progress / recover / routine 行为都应维持
|
|
27
|
+
- Phase 1 的价值是架构清晰度、测试边界和未来扩展能力,而不是对外新 feature
|
|
28
|
+
|
|
29
|
+
如果未来永远不做 Claude,Phase 1 仍然值得做;因为它本身就能让 `work-ally` 从“Codex 绑定实现”升级成“Codex-first 的 runtime bridge”。
|
|
30
|
+
|
|
31
|
+
## Background
|
|
32
|
+
|
|
33
|
+
当前仓库已经有一些 runtime seam,但它们仍然是隐式的、工程方便层的:
|
|
34
|
+
|
|
35
|
+
- `bridge/src/receiver.ts` 中存在 `RuntimeLike`
|
|
36
|
+
- `bridge/src/server.ts` 中已经可以在 fake / codex 之间切换
|
|
37
|
+
- `bridge/src/fake-runtime-client.ts` 已经承担了大量 integration 测试职责
|
|
38
|
+
|
|
39
|
+
但与此同时,当前 shipped 能力又明显依赖 Codex 语义:
|
|
40
|
+
|
|
41
|
+
- thread / turn 连续性
|
|
42
|
+
- approval / user input
|
|
43
|
+
- interrupt / recover
|
|
44
|
+
- progress heartbeat
|
|
45
|
+
- runtime connection lifecycle
|
|
46
|
+
- routine 执行与只读运行约束
|
|
47
|
+
|
|
48
|
+
这就形成了一个典型问题:
|
|
49
|
+
|
|
50
|
+
- 不抽象,后续任何第二 runtime 接入都会重新痛一次
|
|
51
|
+
- 抽象过猛,又容易把现有 Codex 行为打散,伤到主线稳定性
|
|
52
|
+
|
|
53
|
+
因此必须先有一份明确的 Phase 1 spec,把“怎么抽”和“什么绝对不能动”一次写清楚。
|
|
54
|
+
|
|
55
|
+
## Problem Statement
|
|
56
|
+
|
|
57
|
+
Phase 1 要解决四个问题。
|
|
58
|
+
|
|
59
|
+
### 1. 当前 runtime contract 是隐式的
|
|
60
|
+
|
|
61
|
+
现在 bridge、server、routine、tests 对 runtime 的要求分散在多个文件里,没有一份正式合同说明:
|
|
62
|
+
|
|
63
|
+
- runtime 必须提供什么
|
|
64
|
+
- runtime 可选提供什么
|
|
65
|
+
- bridge 允许按什么能力降级
|
|
66
|
+
|
|
67
|
+
### 2. 代码里还存在 Codex-specific 主逻辑分叉
|
|
68
|
+
|
|
69
|
+
当前一些行为仍然通过具体实现类型判断,例如:
|
|
70
|
+
|
|
71
|
+
- 直接依赖 `CodexRuntimeClient`
|
|
72
|
+
- 用 `instanceof` 判断是否启用某些 runtime 特性
|
|
73
|
+
|
|
74
|
+
这会让未来的第二 runtime 接入变成“到处补例外”。
|
|
75
|
+
|
|
76
|
+
### 3. 没有明确的兼容性护栏
|
|
77
|
+
|
|
78
|
+
当前虽然知道“不能把 Codex 搞坏”,但没有一份明确的产品级、测试级护栏说明:
|
|
79
|
+
|
|
80
|
+
- 哪些能力必须零回归
|
|
81
|
+
- 哪些行为允许内部重构但对外不变
|
|
82
|
+
- 哪些文档和验收口径需要跟着更新
|
|
83
|
+
|
|
84
|
+
### 4. 后续扩展路径还没被产品化定义
|
|
85
|
+
|
|
86
|
+
Phase 1 之后的产品应该是什么?
|
|
87
|
+
|
|
88
|
+
正确答案不是“现在支持多 runtime”,而是:
|
|
89
|
+
|
|
90
|
+
- 产品口径升级为 runtime bridge
|
|
91
|
+
- Codex 成为第一套 reference implementation
|
|
92
|
+
- 后续 runtime 可以按 contract 接入
|
|
93
|
+
|
|
94
|
+
如果这点不写清楚,Phase 1 很容易被误读成“为未来可能存在的功能做技术预埋”。
|
|
95
|
+
|
|
96
|
+
## Product Decision
|
|
97
|
+
|
|
98
|
+
### Decision 1: Phase 1 是必做的内功,不依赖 Claude 是否成立
|
|
99
|
+
|
|
100
|
+
Phase 1 的成立条件不包含 Claude。
|
|
101
|
+
|
|
102
|
+
它本身就是一个独立成立的产品改进:
|
|
103
|
+
|
|
104
|
+
- 明确 runtime contract
|
|
105
|
+
- 收紧代码边界
|
|
106
|
+
- 固化回归护栏
|
|
107
|
+
- 保住 Codex 当前稳定体验
|
|
108
|
+
|
|
109
|
+
### Decision 2: Phase 1 严禁用户语义变化
|
|
110
|
+
|
|
111
|
+
这条 spec 的最重要约束是:
|
|
112
|
+
|
|
113
|
+
> 不允许把“架构重构”包装成“顺手改行为”。
|
|
114
|
+
|
|
115
|
+
Phase 1 期间禁止借机改动:
|
|
116
|
+
|
|
117
|
+
- 用户入口命令语义
|
|
118
|
+
- 默认 approval / sandbox 行为
|
|
119
|
+
- `/status` 的核心语义
|
|
120
|
+
- Feishu 进度、恢复、审批、user input 的产品合同
|
|
121
|
+
- routine 的运行模式与只读边界
|
|
122
|
+
|
|
123
|
+
### Decision 3: Codex 是第一套正式 adapter,不是历史包袱
|
|
124
|
+
|
|
125
|
+
Phase 1 不是把 Codex 边缘化,而是把它提升成:
|
|
126
|
+
|
|
127
|
+
- 第一套正式 runtime adapter
|
|
128
|
+
- capability 最完整的 reference implementation
|
|
129
|
+
- 所有未来 runtime 的对照基线
|
|
130
|
+
|
|
131
|
+
### Decision 4: 抽象只到 `work-ally` 真正需要的层级
|
|
132
|
+
|
|
133
|
+
Phase 1 不做:
|
|
134
|
+
|
|
135
|
+
- 通用模型平台
|
|
136
|
+
- provider 配置中台
|
|
137
|
+
- 跨 runtime 原生 thread 迁移
|
|
138
|
+
- 大而全多引擎控制面
|
|
139
|
+
|
|
140
|
+
只做:
|
|
141
|
+
|
|
142
|
+
- `work-ally` 真正依赖的 runtime contract
|
|
143
|
+
- bridge 对 runtime 能力的消费边界
|
|
144
|
+
|
|
145
|
+
## Goals
|
|
146
|
+
|
|
147
|
+
1. 在仓库内建立正式 runtime contract
|
|
148
|
+
2. 把当前 Codex 路径改造成 contract 下的第一套正式 implementation
|
|
149
|
+
3. 让 bridge / server / routine / tests 依赖 contract,而不是直接依赖 Codex 实现类
|
|
150
|
+
4. 为未来第二 runtime 接入留出明确扩展口
|
|
151
|
+
5. 在整个 Phase 1 过程中保持现有产品功能和行为稳定
|
|
152
|
+
|
|
153
|
+
## Non-goals
|
|
154
|
+
|
|
155
|
+
Phase 1 不做:
|
|
156
|
+
|
|
157
|
+
- 新增第二 runtime 的正式支持
|
|
158
|
+
- 对用户开放 runtime 切换能力
|
|
159
|
+
- 自建统一 prompt / persona / provider 平台
|
|
160
|
+
- 重写 approval / recovery / scheduler 产品语义
|
|
161
|
+
- 借重构名义推进新的用户功能
|
|
162
|
+
|
|
163
|
+
## Scope
|
|
164
|
+
|
|
165
|
+
### In scope
|
|
166
|
+
|
|
167
|
+
1. 定义正式 runtime contract 与 capability profile
|
|
168
|
+
2. 定义 runtime-native IDs 与 `work-ally` product IDs 的边界
|
|
169
|
+
3. 重构 `CodexRuntimeClient` 为正式 Codex adapter
|
|
170
|
+
4. 升级 fake runtime,使其跟正式 contract 对齐
|
|
171
|
+
5. 让以下模块只依赖 contract:
|
|
172
|
+
- `Receiver`
|
|
173
|
+
- `RuntimeApp`
|
|
174
|
+
- routine 执行入口
|
|
175
|
+
- runtime status / recovery orchestration
|
|
176
|
+
6. 补齐回归测试与验收基线
|
|
177
|
+
7. 回写相关 planning / README / implementation 口径
|
|
178
|
+
|
|
179
|
+
### Out of scope
|
|
180
|
+
|
|
181
|
+
1. Claude Runtime Host
|
|
182
|
+
2. 第二 runtime 的生产接入
|
|
183
|
+
3. 用户可见 runtime selector
|
|
184
|
+
4. 跨 runtime 会话迁移
|
|
185
|
+
|
|
186
|
+
## Runtime Contract
|
|
187
|
+
|
|
188
|
+
Phase 1 需要定义一份正式 contract。建议至少包含下面这些对象。
|
|
189
|
+
|
|
190
|
+
### 1. Core interfaces
|
|
191
|
+
|
|
192
|
+
- `RuntimeAdapter`
|
|
193
|
+
- `RuntimeCapabilityProfile`
|
|
194
|
+
- `RuntimeSessionStatus`
|
|
195
|
+
- `RuntimeTurnResult`
|
|
196
|
+
- `RuntimeProductEvent`
|
|
197
|
+
|
|
198
|
+
### 2. Product-owned identifiers
|
|
199
|
+
|
|
200
|
+
由 `work-ally` 自己持有:
|
|
201
|
+
|
|
202
|
+
- `conversation_ref`
|
|
203
|
+
- `session_key`
|
|
204
|
+
- delivery target
|
|
205
|
+
- assistant / workspace 绑定关系
|
|
206
|
+
|
|
207
|
+
由 runtime 提供并由 adapter 挂接:
|
|
208
|
+
|
|
209
|
+
- `runtime_name`
|
|
210
|
+
- `runtime_session_id` / `runtime_thread_id`
|
|
211
|
+
- `runtime_turn_id`
|
|
212
|
+
- runtime-native gate IDs
|
|
213
|
+
|
|
214
|
+
原则:
|
|
215
|
+
|
|
216
|
+
> `work-ally` 不把自己的产品主身份交给 runtime 托管。
|
|
217
|
+
|
|
218
|
+
### 3. Required capabilities
|
|
219
|
+
|
|
220
|
+
正式 runtime 至少必须满足:
|
|
221
|
+
|
|
222
|
+
1. `healthcheck`
|
|
223
|
+
2. `start_session`
|
|
224
|
+
3. `run_turn`
|
|
225
|
+
4. `interrupt_turn`
|
|
226
|
+
5. `read_session_status`
|
|
227
|
+
6. `disconnect`
|
|
228
|
+
|
|
229
|
+
关于 `resume_session`:
|
|
230
|
+
|
|
231
|
+
- Phase 1 文档中要明确它是重要能力
|
|
232
|
+
- 但是否把它列为所有正式 runtime 的硬门槛,可留给后续产品判断
|
|
233
|
+
- 对 Codex adapter 而言,仍必须保留当前 resume 语义
|
|
234
|
+
|
|
235
|
+
### 4. Optional capabilities
|
|
236
|
+
|
|
237
|
+
可选能力至少包括:
|
|
238
|
+
|
|
239
|
+
- structured progress stream
|
|
240
|
+
- turn result recovery
|
|
241
|
+
- connection lifecycle events
|
|
242
|
+
- finer-grained active flags
|
|
243
|
+
- runtime-native metadata
|
|
244
|
+
|
|
245
|
+
bridge 可以基于 capability profile 做降级,但降级语义必须明文定义。
|
|
246
|
+
|
|
247
|
+
### 5. Product gate semantics
|
|
248
|
+
|
|
249
|
+
Phase 1 先把合同定义好:
|
|
250
|
+
|
|
251
|
+
- bridge 依赖的是“产品级 gate semantics”
|
|
252
|
+
- 不要求所有 runtime 的原生 gate 事件长得一样
|
|
253
|
+
|
|
254
|
+
但在 Phase 1 内,Codex adapter 仍应完整保留当前 approval / user input 行为。
|
|
255
|
+
|
|
256
|
+
## Compatibility Guardrails
|
|
257
|
+
|
|
258
|
+
这是 Phase 1 的核心章节。
|
|
259
|
+
|
|
260
|
+
### 1. 必须零回归的能力面
|
|
261
|
+
|
|
262
|
+
Phase 1 完成后,以下能力必须零回归:
|
|
263
|
+
|
|
264
|
+
- thread / session 连续性
|
|
265
|
+
- approval flow
|
|
266
|
+
- user input flow
|
|
267
|
+
- interrupt / stop
|
|
268
|
+
- turn recovery
|
|
269
|
+
- `/status` 输出的核心语义
|
|
270
|
+
- progress heartbeat
|
|
271
|
+
- routine / scheduler 执行链路
|
|
272
|
+
- runtime connection lifecycle 可见性
|
|
273
|
+
|
|
274
|
+
### 2. 不允许变化的用户口径
|
|
275
|
+
|
|
276
|
+
以下对外口径不得在 Phase 1 被静默改变:
|
|
277
|
+
|
|
278
|
+
- 用户入口仍只有 `ally.sh`
|
|
279
|
+
- 当前默认底层 runtime 仍是 Codex
|
|
280
|
+
- 现有 Feishu 回复、审批、异常回告语义不变
|
|
281
|
+
- 现有 desk / workspace / runtime 资产边界不变
|
|
282
|
+
|
|
283
|
+
### 3. 不允许为了抽象而削平 Codex 体验
|
|
284
|
+
|
|
285
|
+
如果某抽象会让 Codex 当前 richer semantics 被迫退化成最小公分母,就应视为错误抽象。
|
|
286
|
+
|
|
287
|
+
产品判断非常明确:
|
|
288
|
+
|
|
289
|
+
> Phase 1 的抽象必须服务于稳定扩展,而不是反向阉割当前最成熟的实现。
|
|
290
|
+
|
|
291
|
+
## Implementation Direction
|
|
292
|
+
|
|
293
|
+
### Step 1: Contract first
|
|
294
|
+
|
|
295
|
+
先定义类型和接口,不先大改实现。
|
|
296
|
+
|
|
297
|
+
需要先落地:
|
|
298
|
+
|
|
299
|
+
- runtime contract types
|
|
300
|
+
- capability profile
|
|
301
|
+
- bridge 消费 contract 的最小接口
|
|
302
|
+
|
|
303
|
+
### Step 2: Codex adapter
|
|
304
|
+
|
|
305
|
+
把当前 Codex 路径收成正式 adapter,例如:
|
|
306
|
+
|
|
307
|
+
- `CodexRuntimeAdapter`
|
|
308
|
+
|
|
309
|
+
要求:
|
|
310
|
+
|
|
311
|
+
- 现有行为不变
|
|
312
|
+
- 现有测试继续成立
|
|
313
|
+
- 不再让外层主逻辑直接依赖 `CodexRuntimeClient`
|
|
314
|
+
|
|
315
|
+
### Step 3: Fake runtime alignment
|
|
316
|
+
|
|
317
|
+
把 fake runtime 升级成正式 contract 下的测试实现。
|
|
318
|
+
|
|
319
|
+
目标:
|
|
320
|
+
|
|
321
|
+
- integration tests 继续跑得动
|
|
322
|
+
- 后续第二 runtime 不需要重写整套测试思路
|
|
323
|
+
|
|
324
|
+
### Step 4: Bridge decoupling
|
|
325
|
+
|
|
326
|
+
逐步把以下模块切到 contract:
|
|
327
|
+
|
|
328
|
+
- `Receiver`
|
|
329
|
+
- `RuntimeApp`
|
|
330
|
+
- routine 入口
|
|
331
|
+
- recovery / status / lifecycle 编排
|
|
332
|
+
|
|
333
|
+
### Step 5: Documentation and acceptance
|
|
334
|
+
|
|
335
|
+
完成后同步回写:
|
|
336
|
+
|
|
337
|
+
- README 的长期产品口径
|
|
338
|
+
- implementation guide 中的架构边界描述
|
|
339
|
+
- planning 文档中关于 runtime 的术语
|
|
340
|
+
|
|
341
|
+
## Testing And Validation
|
|
342
|
+
|
|
343
|
+
Phase 1 必须把“零回归”做成明确验证项,而不是口头承诺。
|
|
344
|
+
|
|
345
|
+
### 1. Unit / integration baseline
|
|
346
|
+
|
|
347
|
+
至少保住当前这些方向的测试:
|
|
348
|
+
|
|
349
|
+
- runtime client / adapter
|
|
350
|
+
- approval flow
|
|
351
|
+
- user input flow
|
|
352
|
+
- control commands
|
|
353
|
+
- continuity flow
|
|
354
|
+
- progress heartbeat
|
|
355
|
+
- routine delivery
|
|
356
|
+
- recovery semantics
|
|
357
|
+
|
|
358
|
+
### 2. Manual acceptance baseline
|
|
359
|
+
|
|
360
|
+
至少需要重新走一轮最小人工验收:
|
|
361
|
+
|
|
362
|
+
- 正常对话
|
|
363
|
+
- 继续同一 thread
|
|
364
|
+
- `/new`
|
|
365
|
+
- approval
|
|
366
|
+
- user input
|
|
367
|
+
- interrupt
|
|
368
|
+
- runtime 短暂断连后的恢复语义
|
|
369
|
+
|
|
370
|
+
### 3. Refactor discipline
|
|
371
|
+
|
|
372
|
+
Phase 1 期间如果发现:
|
|
373
|
+
|
|
374
|
+
- 某抽象会导致现有测试大面积改写
|
|
375
|
+
- 某模块必须大量引入 runtime-specific 例外逻辑
|
|
376
|
+
|
|
377
|
+
应先停下来回看 contract,而不是硬往前推。
|
|
378
|
+
|
|
379
|
+
## Deliverables
|
|
380
|
+
|
|
381
|
+
Phase 1 完成时,应至少交付:
|
|
382
|
+
|
|
383
|
+
1. 一份正式 runtime contract
|
|
384
|
+
2. 一套 `CodexRuntimeAdapter`
|
|
385
|
+
3. 一套跟 contract 对齐的 fake runtime
|
|
386
|
+
4. 一组明确的 compatibility tests / acceptance baseline
|
|
387
|
+
5. 回写后的项目文档口径
|
|
388
|
+
|
|
389
|
+
## Acceptance Criteria
|
|
390
|
+
|
|
391
|
+
1. 仓库内存在正式 runtime contract,而不是分散的隐式假设
|
|
392
|
+
2. bridge / server / routine 主链路已依赖 contract,而不是直接依赖 Codex 类
|
|
393
|
+
3. Codex 现有用户路径零回归
|
|
394
|
+
4. fake runtime 已对齐 contract,测试夹具继续可用
|
|
395
|
+
5. Phase 1 结束后,用户默认仍只感知到 Codex 路径,没有新增学习成本
|
|
396
|
+
6. README / implementation / planning 对 runtime 的口径已经统一到“runtime bridge, Codex-first”
|
|
397
|
+
|
|
398
|
+
## Risks
|
|
399
|
+
|
|
400
|
+
### 1. 抽象过早,做成平台化工程
|
|
401
|
+
|
|
402
|
+
会拖慢节奏,也会偏离 `work-ally` 的产品边界。
|
|
403
|
+
|
|
404
|
+
### 2. 抽象过薄,只是换名字
|
|
405
|
+
|
|
406
|
+
如果只是把类名改掉,而没有 contract 和 capability profile,未来第二 runtime 接入时仍然会重新痛一次。
|
|
407
|
+
|
|
408
|
+
### 3. 兼容性护栏不够硬
|
|
409
|
+
|
|
410
|
+
如果没有测试和人工验收护栏,Phase 1 很容易在“内部看起来更优雅”的同时,悄悄损伤 Codex 主线体验。
|
|
411
|
+
|
|
412
|
+
## Open Questions
|
|
413
|
+
|
|
414
|
+
1. `resume_session` 是否应在长期上被定义为正式 runtime 的硬门槛
|
|
415
|
+
2. `/status` 中是否要在 Phase 1 就先补一层 runtime capability 摘要,还是等第二 runtime 真出现再加
|
|
416
|
+
3. README 是否在 Phase 1 完成后就更新为 runtime bridge 口径
|
|
417
|
+
|
|
418
|
+
## Product Judgment
|
|
419
|
+
|
|
420
|
+
Phase 1 不是在给 Claude 铺路而已。
|
|
421
|
+
|
|
422
|
+
它本身就是一个独立成立的产品整理动作:
|
|
423
|
+
|
|
424
|
+
> 把 `work-ally` 从“Codex 绑定实现”收成“Codex-first 的 runtime bridge”,同时不让当前用户承担任何行为变化成本。
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# SPEC: Runtime Connection And Turn Recovery Semantics
|
|
2
|
+
|
|
3
|
+
更新时间:2026-03-14
|
|
4
|
+
状态:Draft / In implementation
|
|
5
|
+
|
|
6
|
+
## 1. 背景
|
|
7
|
+
|
|
8
|
+
两份 incident / analysis 已经把问题说清楚了:
|
|
9
|
+
|
|
10
|
+
- 当前 bridge 已经有 runtime 断连可见性、stale turn suppression、bounded recovery
|
|
11
|
+
- 但最终正确性仍然过度依赖在线事件顺序
|
|
12
|
+
- 一旦 `turn/completed` 丢失、transport 抖动、渠道发送失败,系统就会对三件事失去确定性:
|
|
13
|
+
- 这条 inbound message 是否真的进入了 Codex turn
|
|
14
|
+
- 这轮 turn 最终是否已经完成
|
|
15
|
+
- 完成后的结果是否真的送到了用户面前
|
|
16
|
+
|
|
17
|
+
因此,本专题不再把问题理解成“补一个 recovery patch”,而是收口为:
|
|
18
|
+
|
|
19
|
+
> bridge 需要最小的 inbound acceptance + turn execution + delivery ledger,并把最终 turn 真相切到 pull-primary,才能把异常路径从“靠猜”变成“有据可查”。
|
|
20
|
+
|
|
21
|
+
## 2. 问题定义
|
|
22
|
+
|
|
23
|
+
当前缺口不是没有 recovery,而是没有一份足够收敛的 durable truth model 来回答下面五个问题:
|
|
24
|
+
|
|
25
|
+
1. 这条用户消息是否已经被 bridge 接住
|
|
26
|
+
2. 它是否已经真正进入 Codex thread,并绑定到某个 turn
|
|
27
|
+
3. 当前处于 running / waiting / pending_recovery / recovery_required / completed 哪一态
|
|
28
|
+
4. 终态结果是否已经被 bridge 持久化
|
|
29
|
+
5. 用户所在渠道是否真的收到过这份结果
|
|
30
|
+
|
|
31
|
+
如果没有这套模型,bridge 就只能做到:
|
|
32
|
+
|
|
33
|
+
- 在线时尽量转发
|
|
34
|
+
- 异常时尽量猜测
|
|
35
|
+
- 猜不到就要求用户重发
|
|
36
|
+
|
|
37
|
+
这不足以支撑 `work-ally` 作为稳定协作入口的产品定位。
|
|
38
|
+
|
|
39
|
+
## 3. 目标
|
|
40
|
+
|
|
41
|
+
1. 在不把中间层做成厚重任务引擎的前提下,补齐最小的 inbound acceptance + turn execution + delivery ledger
|
|
42
|
+
2. 把 turn 终态确认从 push-first 调整为 pull-primary, push-assisted
|
|
43
|
+
3. 明确区分“入站确认状态”“执行状态”和“送达状态”
|
|
44
|
+
4. 让 stale / superseded / recovery_required 都成为持久事实,而不是只留在日志里
|
|
45
|
+
5. 继续坚持 `Connection state != Task state`
|
|
46
|
+
6. 为后续 `/status`、异常透明化、迟到结果策略提供稳定基础
|
|
47
|
+
|
|
48
|
+
## 4. 非目标
|
|
49
|
+
|
|
50
|
+
本期不做:
|
|
51
|
+
|
|
52
|
+
- 不实现 exactly-once 提交协议
|
|
53
|
+
- 不实现断点续跑执行引擎
|
|
54
|
+
- 不实现自动重投 worker
|
|
55
|
+
- 不新增复杂监控面板
|
|
56
|
+
- 不把 threadId / turnId 暴露给普通飞书用户
|
|
57
|
+
- 不把 approval / user-input 请求重构成完全离线恢复协议
|
|
58
|
+
|
|
59
|
+
## 5. 核心判断
|
|
60
|
+
|
|
61
|
+
### 5.1 pull-primary, push-assisted
|
|
62
|
+
|
|
63
|
+
- 最终答复、最终失败/中断状态、recovery 对账,以 `thread/read(includeTurns=true)` 主动拉取为准
|
|
64
|
+
- `turn/completed`、`item/*`、`thread/status/changed` 不再承担最终真相职责;它们最多是缓存或实时体验线索
|
|
65
|
+
- approval / user input 继续走在线事件流承接,因为当前协议没有等价的稳定 pull 列表接口来取回 request payload 与 callback id
|
|
66
|
+
- runtime transport 生命周期默认只作为内部可观测性,不再直接翻译成面向用户的“连接已断开 / 已恢复”产品文案
|
|
67
|
+
|
|
68
|
+
### 5.2 事件是线索,不是最终账本
|
|
69
|
+
|
|
70
|
+
以下能力都只是账本收敛的输入,不是唯一真相:
|
|
71
|
+
|
|
72
|
+
- `turn/completed`
|
|
73
|
+
- `thread/status/changed`
|
|
74
|
+
- runtime push item events
|
|
75
|
+
- runtime reconnect lifecycle
|
|
76
|
+
|
|
77
|
+
其中真正承担 durable terminal truth 的,是 bridge 主动发起的 `thread/read(includeTurns=true)` 对账。
|
|
78
|
+
|
|
79
|
+
### 5.3 Session Store 需要从“会话台账”升级到“acceptance + turn ledger”
|
|
80
|
+
|
|
81
|
+
当前 session store 已经负责:
|
|
82
|
+
|
|
83
|
+
- conversation -> thread 映射
|
|
84
|
+
- active turn
|
|
85
|
+
- approvals / user inputs
|
|
86
|
+
- inbound dedupe
|
|
87
|
+
|
|
88
|
+
本期在此基础上增加两层最小持久事实:
|
|
89
|
+
|
|
90
|
+
- `inbound-ledger/`:每条 inbound message 一份 JSON,记录该消息是否已被 bridge 接住、是否已真正进入某个 turn
|
|
91
|
+
- `turn-ledger/`:每个 turn 一份 JSON,记录 bridge 已经天然知道的执行与送达事实
|
|
92
|
+
|
|
93
|
+
不新增第二套 runtime,也不把 bridge 做成任务引擎。
|
|
94
|
+
|
|
95
|
+
### 5.4 执行完成不等于送达完成
|
|
96
|
+
|
|
97
|
+
bridge 至少要区分:
|
|
98
|
+
|
|
99
|
+
- runtime 已经产生终态结果
|
|
100
|
+
- 用户已经在渠道里看到结果
|
|
101
|
+
|
|
102
|
+
否则 channel 抖动会被误读成“模型没做完”。
|
|
103
|
+
|
|
104
|
+
### 5.5 stale suppression 不是“静默忽略”,而是 superseded
|
|
105
|
+
|
|
106
|
+
一旦会话已被新消息推进:
|
|
107
|
+
|
|
108
|
+
- 对用户:旧 turn 输出必须被抑制,避免串话
|
|
109
|
+
- 对账本:旧 turn 必须进入 `superseded`
|
|
110
|
+
|
|
111
|
+
## 6. V1 Inbound Acceptance Ledger 合同
|
|
112
|
+
|
|
113
|
+
每条 inbound message 至少记录:
|
|
114
|
+
|
|
115
|
+
- `messageId`
|
|
116
|
+
- `threadId`
|
|
117
|
+
- `turnId`
|
|
118
|
+
- `createdAt`
|
|
119
|
+
- `updatedAt`
|
|
120
|
+
- `acceptedAt`
|
|
121
|
+
- `executionStatus`
|
|
122
|
+
- `received`
|
|
123
|
+
- 以及与 turn ledger 对齐后的 `running / waiting_approval / waiting_user_input / pending_recovery / recovery_required / completed / failed / interrupted / superseded`
|
|
124
|
+
|
|
125
|
+
它回答的问题是:
|
|
126
|
+
|
|
127
|
+
- 这条消息是否只是到达 bridge
|
|
128
|
+
- 它是否已经真正绑定到某个 `turnId`
|
|
129
|
+
- 如果 bridge 中途抖动,这条消息是否允许被重新处理
|
|
130
|
+
|
|
131
|
+
## 7. V1 Turn Ledger 合同
|
|
132
|
+
|
|
133
|
+
每个 turn 至少记录:
|
|
134
|
+
|
|
135
|
+
- `turnId`
|
|
136
|
+
- `threadId`
|
|
137
|
+
- `messageId`
|
|
138
|
+
- `promptPreview`
|
|
139
|
+
- `executionStatus`
|
|
140
|
+
- `running`
|
|
141
|
+
- `waiting_approval`
|
|
142
|
+
- `waiting_user_input`
|
|
143
|
+
- `pending_recovery`
|
|
144
|
+
- `recovery_required`
|
|
145
|
+
- `completed`
|
|
146
|
+
- `failed`
|
|
147
|
+
- `interrupted`
|
|
148
|
+
- `superseded`
|
|
149
|
+
- `runtimeStatus`
|
|
150
|
+
- `replyPreview`
|
|
151
|
+
- `error`
|
|
152
|
+
- `resultPersistedAt`
|
|
153
|
+
- `deliveryStatus`
|
|
154
|
+
- `not_ready`
|
|
155
|
+
- `pending`
|
|
156
|
+
- `delivered`
|
|
157
|
+
- `suppressed`
|
|
158
|
+
- `delivery_unavailable`
|
|
159
|
+
- `deliveredAt`
|
|
160
|
+
- `supersededByMessageId`
|
|
161
|
+
- `supersededByTurnId`
|
|
162
|
+
- `supersededReason`
|
|
163
|
+
|
|
164
|
+
## 8. 状态流转
|
|
165
|
+
|
|
166
|
+
### 8.1 正常路径
|
|
167
|
+
|
|
168
|
+
1. `noteInboundObserved` -> inbound ledger 进入 `received`
|
|
169
|
+
2. `turn/start` 成功返回 `turnId` 后,入站账本绑定 `threadId / turnId / acceptedAt`
|
|
170
|
+
3. 启动 pull-primary final-state poll;在线 `turn/completed` 只作为 fast-path
|
|
171
|
+
4. approval / user input / progress 仍通过 push 通道实时承接
|
|
172
|
+
5. terminal result persisted -> `completed / failed / interrupted`, `deliveryStatus=pending`
|
|
173
|
+
6. 渠道发送成功 -> `deliveryStatus=delivered`
|
|
174
|
+
7. 渠道发送失败但属于 non-fatal channel delivery -> `deliveryStatus=delivery_unavailable`
|
|
175
|
+
8. 若上一轮终态结果已持久化但当时未稳定送达,则下一条 inbound 到来时优先自动补发;只有补发仍失败时才退回系统说明
|
|
176
|
+
|
|
177
|
+
### 8.2 recovery 路径
|
|
178
|
+
|
|
179
|
+
1. runtime infra error 进入 recovery attempt -> `pending_recovery`
|
|
180
|
+
2. recovery 成功补读终态 -> 正常收口到 terminal state
|
|
181
|
+
3. recovery 失败并提示用户重发 -> `recovery_required`
|
|
182
|
+
|
|
183
|
+
### 8.3 session advanced 路径
|
|
184
|
+
|
|
185
|
+
如果旧 turn 已被新消息推进:
|
|
186
|
+
|
|
187
|
+
- 旧 turn 输出对用户不可见
|
|
188
|
+
- 账本标记 `executionStatus=superseded`
|
|
189
|
+
- `deliveryStatus=suppressed`
|
|
190
|
+
- 记录 `supersededByMessageId / supersededByTurnId / supersededReason`
|
|
191
|
+
|
|
192
|
+
## 9. 实现要求
|
|
193
|
+
|
|
194
|
+
### 9.1 Session Store
|
|
195
|
+
|
|
196
|
+
- 增加 `inbound-ledger/` 目录
|
|
197
|
+
- 增加 `turn-ledger/` 目录
|
|
198
|
+
- 提供最小 inbound acceptance API:
|
|
199
|
+
- observed / received
|
|
200
|
+
- accepted_to_turn
|
|
201
|
+
- execution_status synced from turn ledger
|
|
202
|
+
- 提供最小 turn ledger API:
|
|
203
|
+
- running
|
|
204
|
+
- waiting_approval
|
|
205
|
+
- waiting_user_input
|
|
206
|
+
- pending_recovery
|
|
207
|
+
- recovery_required
|
|
208
|
+
- terminal persisted
|
|
209
|
+
- delivered / delivery_unavailable
|
|
210
|
+
- superseded
|
|
211
|
+
|
|
212
|
+
### 9.2 Receiver
|
|
213
|
+
|
|
214
|
+
- 在 inbound receipt claim 时先记录 `received`
|
|
215
|
+
- 在 `onTurnStarted` 时把 inbound 与 `threadId / turnId` 绑定
|
|
216
|
+
- 在 approval、user-input、recovery、final delivery 等关键路径更新 ledger
|
|
217
|
+
- stale suppression 不只写 archive event,还要把旧 turn 标记为 `superseded`
|
|
218
|
+
- 对 recovery required、final reply、completion without reply、terminal error 等用户可见消息,记录 delivery outcome
|
|
219
|
+
- 对 `delivery_unavailable` 的上一轮终态结果,在后续 inbound 进入时优先自动补发;只有补发失败时才发解释性系统说明
|
|
220
|
+
|
|
221
|
+
### 9.3 Runtime Client
|
|
222
|
+
|
|
223
|
+
- 一旦 `turn/start` 返回 `turnId`,立即启动 bounded pull poll
|
|
224
|
+
- `turn/completed` 与 runtime push item 事件继续保留,但不再作为 final reply / terminal status 的可信来源
|
|
225
|
+
- 断连后不立即把活动 turn 判死,而是优先等待 pull-primary 对账
|
|
226
|
+
- 对用户不再主动转发 runtime transport 生命周期,只保留任务状态语义
|
|
227
|
+
- 不额外承担 delivery ledger 逻辑
|
|
228
|
+
|
|
229
|
+
## 10. 验收标准
|
|
230
|
+
|
|
231
|
+
1. 收到 inbound 后,即使后续 ack 发送失败,仍能在 `inbound-ledger/<messageId>.json` 看见 `executionStatus=received`
|
|
232
|
+
2. `turn/start` 成功后,对应 inbound ledger 必须落成:
|
|
233
|
+
- `threadId` 与 `turnId` 已绑定
|
|
234
|
+
- `acceptedAt` 已写入
|
|
235
|
+
3. 即使在线 `turn/completed` 丢失,只要 `thread/read(includeTurns=true)` 已经看到该 turn 终态,`runTurn()` 仍能正常返回最终结果
|
|
236
|
+
4. runtime infra error 触发 recovery required 后,对应 turn ledger 必须落成:
|
|
237
|
+
- `executionStatus=recovery_required`
|
|
238
|
+
- `deliveryStatus=delivered` 或 `delivery_unavailable`
|
|
239
|
+
5. recovery 成功补发最终结果后,对应 turn ledger 必须落成:
|
|
240
|
+
- `executionStatus=completed`
|
|
241
|
+
- `deliveryStatus=delivered` 或 `delivery_unavailable`
|
|
242
|
+
6. 旧 turn 被新消息推进后,对应 turn ledger 必须落成:
|
|
243
|
+
- `executionStatus=superseded`
|
|
244
|
+
- `deliveryStatus=suppressed`
|
|
245
|
+
7. 多轮 ping-pong 后,不残留错误 active turn,且账本不把新 turn 覆盖成旧 turn
|
|
246
|
+
8. 若上一轮终态结果已持久化且 `deliveryStatus=delivery_unavailable`,下一条 inbound 到来时会优先自动补发上一轮结果;只有补发仍失败时才提示用户
|
|
247
|
+
9. 文档明确说明:connection 恢复 != task 恢复;执行完成 != 用户已收到;bridge 收到 inbound != 已进入 Codex turn
|
|
248
|
+
|
|
249
|
+
## 11. 风险与边界
|
|
250
|
+
|
|
251
|
+
### 风险 1:会不会把中间层做太厚
|
|
252
|
+
|
|
253
|
+
当前判断:不会。
|
|
254
|
+
|
|
255
|
+
原因是这层 ledger 只记录 bridge 已经天然知道的事实,不新增第二套任务执行语义,不替代 runtime。
|
|
256
|
+
|
|
257
|
+
### 风险 2:为什么不直接做自动重投
|
|
258
|
+
|
|
259
|
+
因为那是下一层能力。
|
|
260
|
+
|
|
261
|
+
本期先把“我是否知道这轮发生了什么”补齐;真相没收干净之前,先堆自动重投会继续放大歧义。
|
|
262
|
+
|
|
263
|
+
## 12. 结论
|
|
264
|
+
|
|
265
|
+
本专题从“连接恢复语义”进一步收束为一句更准确的话:
|
|
266
|
+
|
|
267
|
+
> bridge 不是只负责转发事件,而是要为每条 inbound 与每一轮 turn 维护最小的确认、执行与送达账本,并把最终 turn 真相切到主动拉取。
|
|
268
|
+
|
|
269
|
+
这样即使 runtime 断连、事件迟到、会话前进,系统也能明确知道:
|
|
270
|
+
|
|
271
|
+
- 这条用户消息是否真的进入了 Codex
|
|
272
|
+
- 这轮做到哪一步
|
|
273
|
+
- 用户有没有真的收到
|
|
274
|
+
- 这轮是不是已经被后续回合覆盖
|