Files
Jyotisha/docs/tasks/TASK-rectification-futile-collect-stop-20260929.md
T
Jesse_ChenandClaude Opus 5.5 ea21743b09 fix(rectification): stop spoken collect once the training gate opens (BUG-1084..1087)
Once the discriminator training gate is open, only choice cards are asked
and the range card goes out when they are exhausted; targeted lines, their
re-ask and guided windows no longer hold the card or invite more events.
Delivery body says how many choice questions were used instead of the event
fit percent; narration names an excluded cluster instead of "range
unchanged"; a delivered turn no longer carries a collect question.

Offline replay (v4, 3 radii x 2 directions): truth in range 20/20 in every
cell; guided-window injections give the same width in truth and opposite
directions, so red line 1 was revised by product to truth-in-range only.
Skill 10.0.31 -> 10.0.32 (10.0.31 kept as deprecated for pinned cases).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-29 10:06:57 +08:00

12 KiB
Raw Blame History

TASK · 生时校正:停掉无效的补经历循环(止血单,2026-09-29)

基线

  • origin/staging @ 47eda7e1(写作时 head;代码与线上部署同批,开工时以最新 origin/staging 为准)。
  • 分支 codex/rectification-futile-collect-stop-20260929,工作树 .worktrees/rectification-futile-collect-stop-20260929。
  • 串行:本单先做。研究单 TASK-rectification-typed-event-scoring-research-20260929.md 与本单不改同一批文件,可以并行开工;研究单若进入实现阶段,排在本单合入之后。
  • 不得改冻结计分文件(scripts/research/sealed_holdout_rerun.py::PRODUCTION_FILES 的 10 个文件,含 event_probes.py、refinement_packet.py、decision_policy.py),见 ERR-110。本单只动前端与 Agent 提示。

事故实证

产品 2026-09-29 staging 真机(窗口 14:35–15:05,31 分钟):开场一次说了 12 件带年份的经历,之后答了约 10 张卡(其中若干「先跳过 / 记不清」)。界面显示「已对照 22 件」「事件吻合率 95%」,范围始终是 14:35–15:05 整窗。每道题的旁白都是「已记录,范围没变;15:00–15:03 领先,14:40–14:43 落后」。右栏写「可再补一件记得时间的感情或关系变化」。最后一轮同时出现「再问下去也分不开了」和一道新的采集题「身体这边再问一次」。

离线复现(Claude,虚构出生日 1993–1995 年 12 个日期,北京,窗口 ±15 分钟,事件形状同真机:8 件只记得年份,4 件记得到月;脚本口径同 scripts/research/fewer_probes_card_replay.py,交付区间 = unionStillValidRange):

口径 结果
12 件经历进引擎后的范围 12 例中 11 例 = 整窗 31 分钟,另 1 例 29 分钟
候选段先验分(relative_support) 约 10 段,全部落在 9–11 分,淘汰要落后 8 分
原始分差距最大的一例 原始分 13.6 vs 28.5(相差一倍),换成百分比后 15 vs 7,只剪掉 2 分钟
可出的带年月选择题 每例 2–8 道
选择题全部按真值作答后的宽度 中位 17 分钟;≤10 分钟 2/12;1 例仍 31
去掉 4 件「记得到月」的经历(只留 8 件年份) 选择题 5/12 例变多,最终宽度中位 13 分钟(比 12 件时更窄)

根因

  1. 开场之后的口述采集不收窄范围。 打字说的经历只经引擎打分,引擎分按 decision_policy.py::_relative_support 正比例换成百分比,差距被压到 1–2 分,够不到 MIN_SEPARATION_LEAD = 8(BUG-560,blocked:换尺度未过校准)。core/build-state.ts::buildInferenceState 又对 classified_from === "evidence" 的「是」跳过(注释称「引擎已计入」),所以这些经历在推断账本上约等于 0。能动分的只有点选卡(每题 ±2)。
  2. 补来的经历反而挡题。 已入账年份会被 _existence_blocked_years 挡掉同领域相邻年份的选择题(上表最后一行)。
  3. 流程仍一路邀请补经历。 09-16 D2/D6 与 09-26 D2 让交付卡等「七条线 + 一次重问」问完(core/rectification-decision.ts::mayDeliverOnPrecision、v9/collection-question-pool.ts::cardHoldingLinesExhausted);09-26 D4 的不可分句写着「补一件带年月的经历能帮助分开」(user-copy.ts::rangeDeliveryIndistinct);右栏读引擎 refinement_packet.py 的「可再补一件…」;输入框占位「继续说你记得的人生经历…」。
  4. 旁白误报「范围没变」。 中间某段被排除、剩余区间变成不连续两段时,core/credible-range.ts::unionStillValidRange 返回 null;v9/probe-explain.ts::explainRangeChange 遇 null 返回空串,v9/choice-action.ts::composeChoiceNarration 便落到「已记录,范围没变;X 领先,Y 落后」。
  5. 交付正文的数字误导。 user-copy.ts::deliveryTurnNarration 写「对照了 N 件经历,事件吻合率 P%」,N 含不起作用的口述经历,P 与范围宽窄无关;Agent 提示 frontend/src/mastra/agentic-rectification.ts 同样要求第二句写吻合率。

决策记录(产品 2026-09-29)

  • D1 采集只为开闸。 口述采集(七条线定向题、跳过线重问、引导窗口题、任何「再补一件」邀请)只在训练门未开(trainingGateOpen === false:训练事件 < 3 或领域 < 2,见 candidate_contrast.py::discriminator_gate_open)时发起。门一开,只问点选卡(带年月存在题、质量题、风格题);点选卡问完(refreshExhausted)即出交付卡。
    • 推翻:09-16 精度门任务书 D2/D4/D5 与 09-26 TASK-rectification-fewer-probes-card D2 中「七条线及其一次重问问完才出卡」「跳过线重问一次」;09-26 D4 不可分句里「补一件带年月的经历能帮助分开」。BUG-747~752 的防复发条里凡要求「七条线全轮到」的,本单起不再适用,执行方在各条下追加「2026-09-29 产品修订:见本任务书 D1」,不删原文。
    • 用户自己主动打字补经历仍照常收下入账,只是不再索要。
  • D2 交付正文改口径。 删掉「事件吻合率」和「对照了 N 件经历」。第二句改为「用了 M 道选择题」(M = 本 Case 计分的点选答案数,不含跳过 / 记不清)。范围一分没缩时,要直说「这个窗口按现在的方法缩不下去」,不得暗示补经历能分开。具体措辞对照 frontend/docs/VOICE.md,写进 VOICE。
  • D3 旁白不得在范围变化时说「范围没变」。 剩余区间变成多段时说出被排除的那段(如「已记录,排除了 14:40–14:43」)。
  • D4 交付轮不得同时带采集题。
  • 不做:不改打分、先验尺度、MIN_SEPARATION_LEAD、淘汰次数、采用 / 确认门、45 天闸门;不改冻结文件;不动研究单范围(让打字经历计分)。

硬红线

  1. 离线回放:v4 开放集(references/real_case_calibration/minute_rectification_holdout_v4.json)±10 / ±30 / ±60 三档,按 D1 建模「门开后不再注入口述 / 引导经历」,与基线比:真值在区间比例不降、宽度中位不变宽,平均提问数下降。任何一格变差就停,把数字写进 PROGRESS 回报,不得调参数凑。
  2. 不放宽任何置信度边界(AGENTS §8.4、Part B4)。
  3. 全量前端测试用 Node 22(/exec-daemon/node),与开工基线逐条一致、新增失败 0;改动既有断言写「原值 / 新值 / 原因」三栏;tsc 0、lint 0 error;/ 仍 Static;首屏 gzip ±2%。
  4. 改 Agent 提示或 Skill 文本按 CHANGELOG 规则 bump,并在 bump 后验证旧校正会话仍能打开(BUG-621 教训)。
  5. 隐私:测试夹具只用虚构数据;Bug 历史不写真机会话的任何事件内容。

2026-09-29 修订(执行中,产品决定)

  • 产品决定:删掉门开后的引导补经历题,接受回放结果。
  • 硬红线 1 改为:v4 开放集 ±10 / ±30 / ±60 × truth / opposite 六格里,每一格「真值在区间」都不低于基线;宽度中位只上报,不作门。 原文「宽度中位不变宽」作废,不删。
  • 理由:执行方回放(docs/research/futile_collect_stop_replay_2026_09_29.json)六格真值在区间全部 20/20。引导窗口题按真值方向(truth)和按反方向(opposite)注入,得到的宽度几乎一样(例:±60 一例 D1 95 分钟,truth 注入 45、opposite 注入 43;另有注入后反而变宽的 53→59、57→85、5→11),说明它们带不来方向信息,只是把边缘簇推出 8 分线。宽度中位 ±1~3 分钟的差是噪声,不是信息。
  • 根因 4 / T3 更正:core/candidate-window.ts::unionWindowIntervals 按窗口段(segment_index)合并成首尾包络,同一段内中间簇被排除时,unionStillValidRange 的元组不变,不会变成 null;只有跨午夜多段时才是 null。所以「范围没变」主要来自首尾不变,而不是 null 分支。T3 的修法改为按候选比较:答题前后「仍在范围内的候选」差集即被排除的段(probe-explain.ts::excludedClusterRanges)。
  • 对照件(holdout)验证线的口述采集题不在 D1 范围内,照旧(只在不能采用时出现)。

任务分解

  • T1 D1 出卡时机(BUG-1084)
    • mayDeliverOnPrecision / cardHoldingLinesExhausted 及其调用方:训练门开后,定向七条线、重问、引导窗口都不再挡卡、不再发起;门未开时保持现状。
    • 输入框占位、RECTIFICATION_COLLECT_WAITING_PLACEHOLDER、step-state.ts 的 next 提示、answer-choice.ts 的「再说一件带年份的经历后…」在门开后都不再出现邀请句。
    • 右栏 refinement_packet 的「可再补一件…」:前端展示层按字段不渲染这一句(不得用中文正则匹配;Python 文件不动),研究单再决定引擎侧怎么改。
    • 验收:单测覆盖「门开 + 点选卡问完 → 交付」「门开 + 七条线未问 → 仍交付」「门未开 → 仍采集」;遍历七个领域的表驱动断言(沿用 BUG-747 的做法)。
  • T2 D2 交付正文(BUG-1085)
    • deliveryTurnNarration、Agent 提示第二句、rangeDeliveryIndistinct 改口径;skill-verification-report.ts 里 80% / 60% 吻合率的说法若会流进气泡,一并去掉(折叠报告里可保留,标清「这是经历吻合度,不是范围可信度」)。
    • 验收:文案合同测试断言交付气泡不含「吻合率」「补一件」「再说一件」;VOICE 与 DESIGN 同提交更新。
  • T3 D3 旁白(BUG-1086)
    • composeChoiceNarration / explainRangeChange 处理「前后区间段数或端点变化」:用 credible_intervals 比较,不再只比元组。
    • 验收:先写失败测试复现「中间段被排除 → 旁白说范围没变」,再修。顶栏在多段时显示什么,由执行方核实现状写进 PROGRESS;若也只显示首尾,本单只记录,不改 UI。
  • T4 D4 交付轮不带采集题(BUG-1087)
    • 按事故形状(交付卡已出、跳过线仍有一次重问)写回归测试,先红后绿;根因写进 BUG-1087。T1 落地后此路径多半不再可达,仍要留测试。
  • T5 回放与记录
    • 回放脚本放 scripts/research/(可在 fewer_probes_card_replay.py 上加一个 --collect-after-gate off 口径),JSON 结果进 docs/research/,数字进 PROGRESS。
    • CHANGELOG.md、frontend/DESIGN.md(交付卡 / 旁白)、frontend/docs/VOICE.md、docs/testing/rectification-futile-collect-stop-20260929.md 真机清单(至少:开场说 3 件两领域 → 只出点选卡 → 问完直接出卡;答题排除中间段时的旁白;交付后无采集题;旧会话可打开)。

让步顺序

时间不够时按此顺序保留:T1 > T2 > T4 > T3 > 回放以外的截图。T1 与回放缺一不可合入。

开工前置命令

git fetch origin --prune
export PATH=/exec-daemon:$PATH && node -v   # 22.x
git worktree add -b codex/rectification-futile-collect-stop-20260929 .worktrees/rectification-futile-collect-stop-20260929 origin/staging
cd .worktrees/rectification-futile-collect-stop-20260929/frontend && npm ci && npm test 2>&1 | tee /tmp/futile-baseline.log   # 记录基线通过 / 失败清单

BUG 编号

开工时核对 docs/BUG_HISTORY.md 最大号(写作时 BUG-1083 已被 TASK-mobile-chart-and-confirmed-edit-20260929 预留)。本单:BUG-1084(补经历循环)、BUG-1085(交付正文数字误导)、BUG-1086(多段时旁白说范围没变)、BUG-1087(交付轮带采集题)。四条已由 Claude 以 investigating 登记,执行方修复后补全并改状态。关联 BUG-560(blocked)、BUG-634、BUG-747~752、BUG-689。