a8f3793865
project_generic_submit_runtime_observation_locked 把 currentAction 改写成 「Fast GDD 审批观察已落盘」,然后用 pending.action_id 调 append_game_creator_agent_runtime_task_projection_once。但那把幂等键是 (runId, actionId, phase),提交点已经在 phase=completed 上用同一个 actionId 写过一条 currentAction=「Fast GDD v1 已完成 create-only 提交」。三项全同即判为 同一条投影,9 个比对字段里 currentAction 不同 —— 必然硬报错,不是偶发。 后果是撕裂写:报错发生在 standalone pending 已经被改成 observed-approved 之后, v4 batch 还停在 ready/executing。两个恢复锚点从此不一致,恢复扫描只认原始 executing 形状,把策划子 Run 打成 needs-reconciliation;而重放路径的 phase == "completed" 闸门又因此永远过不去,撕裂再也修不回来。做方案链路的审批 因此从来没有成功过一次。 改法是让审批投影沿用提交点的 currentAction。9 字段全同,helper 视为重放直接 返回 Ok,链路继续往下推进 batch、清锚点、唤醒。审批这件事由 gdd_decided 审计 记录和 plan.submit_gdd.observed 事件承载,本来就不需要再占一条 task 投影—— 全仓库另外 9 个调用点都是「一个 action 一条投影」,只有这里想写第二条。 同一处还补上诊断。project_receipt_locked 里 13 处失败原本全部塌缩成一个 recovery_pending bool,其中两处是显式 let _ = error; 丢掉错误原文。receipt 已经 是用户决策的线性化点,这些失败都不能报成命令错误,于是唯一逃出来的症状就是 recoveryPending=true —— 说不出是哪一步、为什么。真因就是这样被藏了整条链路。 现在每处先写一条 agent.runtime.plan.gdd_projection_gap 记录再置位,带 step 标签 和脱敏后的错误原文;记录是 best-effort 的,诊断不能把已提交的 receipt 变成失败。 真机验证(gpt-5.6-luna,未开 GUI):turn outcome=settled、 reconciliationAgentCount=0,state/phase=approved、approvedGddRef.version=1、 recoveryPending=false、两个锚点残留 0/0、project-planning 终态 idle/completed、 gdd_projection_gap 0 条、game/fast_gdd.md 落盘。修前同一条链路 2/2 复现 needs-reconciliation。 顺带给 buildCargoCliArguments 加 --quiet,压掉每次 spawn 重印的 cargo 进度行。 注意它不压 rustc 警告,只在重新编译时才有区别。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>