- README.md is now the product/repo front door (architecture, repo map, local dev, test tiers, delivery flow, doc map). Engine positioning, VedAstro/Codex setup and the oracle/benchmark command reference move verbatim to docs/engine/README.md, docs/engine/vedastro-gateway.md and docs/benchmark/README.md. Capability badges realigned with the registry (91/78/8/0); tests/test_readme_badges.py was red on staging. - AGENTS.md: Part A (environment truth, delivery, worktrees, record placement, bug workflow, growth freeze, frontend red lines, privacy, pre-work check, test tiers) and Part B (reading-rigor constraints). GitHub issue-tracker/triage boilerplate removed: GitHub is a read-only mirror. All strings locked by tests/ are preserved. - CLAUDE.md added: roles, three working modes, task-brief sections, acceptance criteria, session discipline; imports AGENTS.md. - 50 tracked TASK-*/PROGRESS-* files and 3 never-committed briefs move to docs/tasks/ with an index; REPO_LAYOUT.md merged into README. Docs-only change (no gated path touched). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
7.8 KiB
任务书 · 首次真实走查抛光:题干必达、时序、去重、采用后续流、门一致性(2026-09-02)
基线:origin/staging 当前 tip(含 PR #47/#48/#49 全部合并)。
0. 背景
2026-09-02 产品负责人在真实 staging 环境完整走查生时校正(case a17efc37-1494-4d13-91a9-d719838ef66c,快照向发起人索取)。三轮修复全部生效:收窄有进度播报、offer 出牌、采用 04:53 成功、ledger 含 dasha-transition-proximity、品质题生成、matrix-scoring-7 / policy-v3 在线。本轮修走查暴露的 5 个抛光问题,全部已静态定位。不改任何决策门语义与真实性边界(问题 E 除外,它是把两个已存在的权威对齐,需产品选边)。
问题 A(P0)· 选择卡出现过"无题干"——静默降级必须 fail-closed
现象:第一道区分题(D9 相处方式)卡片只有 A-D 选项,无题干;同一 focus 的题干也没写进 turn 历史(后续各题的题干均由 answer_choice 路径正常写入并显示)。
定位:卡片组件渲染 card.prompt(rectification-choice-card.tsx:51 的 <legend>),无题干 = focus 创建时 schema.prompt 为空。serverOwnedChoiceCopy(choice-card.ts:433)在 frame.prompt/period 缺失或超出 4-80 字符窗时静默 return null;server-focus.ts:80-84 拿到 null 后 focus 仍带空 prompt 建立 → 卡出、题干丢;turn-exit 的题干持久化因 question?.prompt 空同步被跳过——一个根因两个症状。message/agent 路径创建的第一个 choice focus 命中此路径(answer_choice 路径正常,说明缺口在 agent 后 persistNextInterviewIfIdle → persistServerOwnedFocus/persistFocusAfterChoice 这条创建链上;按符号追)。
修法:
- choice focus 创建 fail-closed:
serverOwnedChoiceCopy返回 null 时不得建立可渲染的 choice focus——回退为 spoken collect(spokenCollectFallbackFollowup已存在)或跳过该 probe 记入 dropped(reason 如unrenderable_choice_copy),二选一并写明理由。 - 排查 null 的实际成因(该 D9 probe 的
question为"亲密关系里,你更接近哪一种相处方式?",14 字在窗内——大概率是 choice_frame 组装时 prompt 字段没接上,而不是超长),修实际断点。 - 不变量测试:任何
choice_card非空 ⇒choice_card.prompt非空;任何 active choice focus ⇒projectCurrentQuestion(...)?.prompt非空。用走查 case 的 probe 形状做回归。
问题 B(P1)· "界面上有下一问"先于问题出现——时序与措辞双修
现象:模型正文说"界面上继续有下一问",但题干 turn 在流结束后的 turn-exit 才持久化,用户当下看不到。
修法:
- 措辞:
agentic-rectification.ts指令补一条——正文不得断言界面当前状态("界面上有/出现了…"),过渡用中性表述("接下来我们继续"类);VOICE.md 同步。 - 时序:turn-exit 持久化题干/focus 后,在关闭流之前向前端 emit 一个已允许的公开事件(如 question.ready,走
safePublicEvent白名单)或由前端在done事件后立即刷新 case 快照。选实现小的,说明理由。前端已有刷新机制的话只需确认时机覆盖。
问题 C(P2)· 同域采集问句逐字复读
现象:"感情这边,还记得哪年认真在一起、分开,或结婚吗?"在历史里逐字出现两次(用户第一次用工作事件回答,感情域仍未覆盖,重问正确,但复读机器感强)。
修法:同一域的 collect 问句在已问过且未被拒答时重问,需换第二措辞(copy 模块每域加一条 retry 变体,如"回到感情这边——刚才说的工作我记下了,哪年认真在一起或分开还记得吗?")。判定用结构化状态(该域 collect focus 曾建立过),不做正文匹配。
问题 D(P1)· 采用后没有切入前事核对,旧采集问题挂在卡下
现象:采用 04:53 成功后,current_question 仍是采用前的"钱的方面…"采集 focus,显示在候选卡下方、脱离对话流;预期是 verify_adopted_time:按采用分钟反推最多两件前事核对(reverse_verify 链路已实现但没被接上)。
修法:
- 采用(accept RPC 成功)后的下一次 turn-exit / GET 投影:关闭或替换采用前的 collect focus,按
next_user_action.id=verify_adopted_time建立 reverse_verify 焦点(remainingReverseVerifyProbes已存在,MAX_REVERSE_VERIFY=2);无可用前事探针时给出start_consultation引导,不留旧问题。 - UI:当前问题槽在候选卡区域之后渲染时必须仍在对话流内(作为最新一条内容),不得视觉上悬挂在卡片外;具体实现交给前端组件(
rectification-agentic-chat.tsx的 currentQuestion 渲染位置)。 - 不变量:
accepted_time非空 ⇒current_question为 reverse_verify 类或空且next_user_action ∈ {verify_adopted_time, start_consultation};不得为采用前的 collect focus。
问题 E(P1,需产品选边)· coverage 门与 offer 工具不一致
现象:走查中 occupation(职业)从未被问,TS overlay 判 can_adopt: false(coverage 未完成),但模型 offer 工具 + 引擎 accept_allowed=true 照常出牌且采用成功——coverage 门被 offer 链路绕过。结果可用但两个权威打架,且 skill 文本写"职业挡出牌"。
二选一(在 PR 里写明选择与理由,默认选 1):
- 对齐引擎(推荐):coverage(含 occupation)从
deliveryCapability的采用门移除,只保留为问询路由优先级(没问过职业时优先问,但不挡出牌);skill 10.0.14 文本中"职业挡出牌"一句需在下次 skill 版本 bump 时同步修订(本轮先在 PR 记录偏差,不 bump skill)。 - 对齐 TS:offer 工具服务端校验 coverage,未完成时拒绝 offer。风险:重新引入"差一问才能出牌"的摩擦,与 Round A 的用户体验目标相悖。
无论选哪个:overlay 与实际可执行动作必须一致——不允许再出现 can_adopt:false 与"卡已出、采用成功"并存。
硬红线
- 不改采用/确认门的真实性语义(问题 E 按上面二选一后对齐,不新增放宽);确认门恒 fail-closed。
- 问题槽服务端唯一所有不变;所有判定结构化,不做正文字符串匹配。
- 引擎(Python)不动。
./node_modules/.bin/tsc --noEmit通过(不要用npx tsc);rectification-*/consultation-*/consult-*/chat-*测试 fail=0;改动的既有断言逐条三栏说明(旧→新→保留语义)。- 无凭据不得声称已真实环境验证;修完把走查 case 形状的前后对照贴 PR。
开工前置
git fetch origin --prune
git worktree add -b codex/rectification-walkthrough-polish-20260902 \
../.worktrees/rectification-walkthrough-polish-20260902 origin/staging
读 frontend/AGENTS.md、docs/BUG_HISTORY.md(BUG-456/460/463/468/469 链)、frontend/docs/VOICE.md。行号是线索,按符号名定位。
验收标准
- 问题 A 的两条不变量全绿;D9 probe 形状回归:卡必有题干,历史必有题干 turn。
- 问题 D 的采用后不变量全绿;走查 case 形状:采用后
current_question切换为前事核对。 - 问题 E 所选方案落地后:overlay 的
can_adopt与 offer/accept 实际可执行性一致(合成两个方向的测试)。 - tsc + 四组测试 fail=0;BUG_HISTORY 追加条目(编号接现有最大号之后,先 grep 确认,避免再撞号)。
- 建议真实环境复测清单(人工):完整走一遍并确认——首道选择卡有题干;无"界面上有下一问"式断言;同域重问换措辞;采用后立即出现前事核对问题且在对话流内。