文档:DirectProject 队列条目事件投影、resolved_text 持久化与埋点归宿主收口
- ADR 状态改为 2026-09-30 落地完成,§2 补入队侧的“用户条目校验与冻结”,§5 埋点段去掉渲染侧 discard 与句柄表措辞 - ADR 词表收口:并发拒单/放行补拒单出口/放行期拒单三处改成入队失败与放行失败口径 - ADR §9 与实施计划同步归位后的符号名:active_turn_id_at、stale_turn_for_release、kick_queue_dispatch、complete_turn - 实施计划状态改为第 0–7 步全部落地,进度表第 6/7 步补落地说明与提交号,新增「2026-09-30 收口记录」 - 实施计划顶部路径口径补 thread_manager 之外去掉 direct_ 前缀的函数改名对照 - decision-log 2026-09-30 条目把“设计稿,尚未实施”换成落地提交链与验证结论,并补 09-24 条目指向落地证据
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# 【ADR】DirectProject命令入队化与待发消息队列归宿主
|
||||
|
||||
状态:已接受(2026-09-24 设计定稿;**2026-09-30 落地完成**;**2026-09-30 修订**:队列条目不再另存产物,
|
||||
状态:已接受(2026-09-24 设计定稿;**2026-09-30 落地完成**,含当日修订条目:队列条目不再另存产物,
|
||||
引用的解析文本持久化进条目、`prompt` 与 canonical 形状放行时重投影,埋点候选 / settle 两阶段链退役
|
||||
(见 §3 / §4 / §5 与「备选方案与取舍」6–9 条)。实施顺序与验收见
|
||||
(见 §3 / §4 / §5 与「备选方案与取舍」6–9 条)。实施顺序、落地进度与验证证据见
|
||||
[`【实施计划】DirectProject命令入队化与待发消息队列归宿主-2026-09-24`](../technical/【实施计划】DirectProject命令入队化与待发消息队列归宿主-2026-09-24.md))
|
||||
|
||||
## 背景
|
||||
@@ -32,11 +32,11 @@
|
||||
### 2. 命令 = 入队
|
||||
|
||||
`chat_with_game_creator_direct_codex` 改义改名(建议 `enqueue_direct_codex_turn`),主体是今天"接单前"那条链**原样**跑完:
|
||||
`clientTurnId` 校验 → 工作流恢复 → 用户条目校验 → prompt 投影 → 前置条件 → 工程准备;通过后**只入队**——
|
||||
`clientTurnId` 校验 → 工作流恢复 → 用户条目校验与冻结(引用解析文本写进条目,§5)→ 前置条件 → 工程准备;通过后**只入队**——
|
||||
追加 `queue.enqueued`,不登记占用、不落盘用户条目、不发回合事件、不起 codex。
|
||||
任何一步失败就是**入队失败**,走命令返回的 typed 载荷(`DirectTurnRejection` → `DirectTurnEnqueueFailure`),用户就在现场。
|
||||
|
||||
入队按 `clientTurnId` 幂等,判重范围是"在队 ∪ 正在跑的那一轮";重复入队返回同一次成功,不再是并发拒单。
|
||||
入队按 `clientTurnId` 幂等,判重范围是"在队 ∪ 正在跑的那一轮";重复入队返回同一次成功,不再是并发入队失败。
|
||||
|
||||
### 3. 队列归 Thread Manager
|
||||
|
||||
@@ -62,7 +62,7 @@ Thread Manager 在一个回合收口**之后**原子地做:取队首 → 登
|
||||
并在同一临界区写 `queue.removed{ dispatched }`(chip 消失与气泡出现在同一批 consume 里,中间没有空窗)。
|
||||
|
||||
**放行不重跑任何检查,也不存在"放行失败"这种状态**:放行之后的一切失败都是**回合失败**,走既有 `turn.completed.failure` 通道;
|
||||
不新增任何失败通道,也不为放行补拒单出口。
|
||||
不新增任何失败通道,也不为放行补失败出口。
|
||||
|
||||
prompt 同样靠**重投影**,不靠另存:`userItem` 是唯一输入。引用 part 的解析文本(素材摘要 + 引用 UI 设计文档时要展开的
|
||||
代码上下文,渲染它要往项目里写 `ui/generated-*.js`)由入队检查写进该 part 自己的 `resolved_text`,
|
||||
@@ -104,20 +104,20 @@ prompt 同样靠**重投影**,不靠另存:`userItem` 是唯一输入。引
|
||||
- `DirectTaonierActiveInvocationGuard` 的**身份**与 Thread Manager 的 `active_turn.turn_id` 是同一件事的两份记录
|
||||
(GUI 路径下同源字符串),而 09-23 ADR 立的是"同一件事只许有一处真相"。CLI 退役后它的硬阻塞消失:五个读者
|
||||
(`direct_execution` / `direct_tool_bridge` / `direct_validation` / `direct_project_context` / 付费美术重生成)
|
||||
已改读 Thread Manager 的活动回合身份(`direct_active_turn_id_at`),守卫连同它的测试一起删掉,不再有第二份
|
||||
已改读 Thread Manager 的活动回合身份(`active_turn_id_at`),守卫连同它的测试一起删掉,不再有第二份
|
||||
进程内记录。
|
||||
- 删守卫的前置判据**已核实(2026-09-30)**,不需要新增"取消路径补无条件终态":`d833ca9d3` 的兜底路径本来就
|
||||
同时做三件事——释放占用、往事件流补一条 `turn.completed{aborted}`(否则前端会永远停在运行中)、调
|
||||
`complete_direct_thread_turn` 解除占用。删掉的只有 `DirectTaonierActiveInvocationGuard` 那张进程内表;
|
||||
`complete_turn` 解除占用。删掉的只有 `DirectTaonierActiveInvocationGuard` 那张进程内表;
|
||||
唯一独有的东西是 60 秒启动窗口闸门,改挂在 Thread Manager 的占用登记年龄上
|
||||
(`direct_stale_turn_for_release` 的 `NeverReachedExecutor` 分支)。连接死亡那条失败事实由 app-server
|
||||
(`stale_turn_for_release` 的 `NeverReachedExecutor` 分支)。连接死亡那条失败事实由 app-server
|
||||
连接层自己落地(`ab970b9fd`),与守卫无关。
|
||||
|
||||
## 备选方案与取舍
|
||||
|
||||
1. **状态归宿主、放行留前端**(再用一条 `claim` 命令做 CAS 认领):前端机器原样保留,但队列的继续推进依赖至少一个窗口活着,
|
||||
且"谁去认领"要靠竞态解决——正是要消掉的东西。作废。
|
||||
2. **入队只做形状校验、把前置检查留到放行**:会造出"放行期拒单"——一个没有调用方在等的失败,得为它发明新通道;
|
||||
2. **入队只做形状校验、把前置检查留到放行**:会造出"放行失败"这种状态——一个没有调用方在等的失败,得为它发明新通道;
|
||||
而且"首个回合还在建工程、第二条已经排队"这类合法流程会被入队误拒。作废(检查跟着入队走)。
|
||||
3. **一条 `queue.changed{items:[…]}` 快照事件**代替两条细粒度事件:reducer 更傻,但每次变更搬全量、与既有细粒度事件风格不一致。不选。
|
||||
4. **`reason` 用字符串**:前端只能猜、无法穷举、无法在类型层穷尽分支。不选,用 typed 枚举。
|
||||
@@ -153,10 +153,10 @@ prompt 同样靠**重投影**,不靠另存:`userItem` 是唯一输入。引
|
||||
- **失去手工验证手段**:CLI 退役同时带走"真实二进制驱动执行层生产验证"这条手工路径(夹具脚本一并退役)。
|
||||
它不在 CI,损失的是排障时的一次性手段,不是门禁。
|
||||
- **埋点**:成绩由宿主在回合终态直接写,中间不再有候选与 settle:放行那一刻读一次 `identity_generation`、终态再读一次,变了就整条不记。
|
||||
于是前端不再生成、持有或回传任何埋点身份(`analyticsAttemptId` 命令参数、`beginDirectRunAnalytics`、句柄表与
|
||||
"入队失败就删掉句柄"一并退役),队列事件也不需要埋点字段。判据口径随放行搬家:从"发送时与终态同代"改成"放行时与终态同代",
|
||||
入队后、放行前发生的账号切换因此不再丢弃这一轮的成绩——那一轮确实是在新身份下跑的。
|
||||
平台会话代际翻转的 `discard` 判定仍是渲染侧职责(结算时必须由渲染侧给出)。
|
||||
于是前端不再生成、持有或回传任何埋点身份(`analyticsAttemptId` 命令参数、`beginDirectRunAnalytics`、句柄表、
|
||||
settle 调用与"入队失败就删掉句柄"一并退役),队列事件也不需要埋点字段。判据口径随放行搬家:从"发送时与终态同代"
|
||||
改成"放行时与终态同代",入队后、放行前发生的账号切换因此不再丢弃这一轮的成绩——那一轮确实是在新身份下跑的。
|
||||
代际比对本身也不再是渲染侧职责:放行侧读一次代次、终态侧再读一次,都在宿主内完成。
|
||||
|
||||
## 明确不做
|
||||
|
||||
|
||||
Reference in New Issue
Block a user