From 8055792e56c8fa778280c9d5c45c0a20456e6d5b Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Wed, 16 Sep 2026 10:49:21 +0000 Subject: [PATCH] =?UTF-8?q?docs(tasks):=20=E7=B2=BE=E5=BA=A6=E9=97=A8?= =?UTF-8?q?=E6=A7=9B+=E5=BC=95=E5=AF=BC=E8=A1=A5=E7=BB=8F=E5=8E=86?= =?UTF-8?q?=E9=AA=8C=E6=94=B6=EF=BC=9A=E6=9C=AA=E9=80=9A=E8=BF=87=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=95=20F1=EF=BD=9EF7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cfb41daf:tsc/lint/Static/gzip 通过,D1~D5 单测通过;npm test 新增 16 红、 memoization golden 因 receipt 新键红(门禁级,staging 仍部署 317e9f18); 引导窗口领域轮询、回放未按真值注入、录入卡走模型轮。 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45 --- docs/tasks/README.md | 3 +- ...cision-gate-guided-collect-fix-20260916.md | 123 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 docs/tasks/TASK-rectification-precision-gate-guided-collect-fix-20260916.md diff --git a/docs/tasks/README.md b/docs/tasks/README.md index cb30180c..43998b0d 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -251,7 +251,8 @@ | `TASK-home-state-lowering-batch2-20260916.md` | — | **状态下沉第二批(纯前端,与另两单可并行)**:第一批 `f8e607c2` 已验收(useState 66→52、useRef 41→39、散装 `rectification*` 归零、全量套件两侧完全相同)。本单照同一套做法搬剩下三簇:`session*` **10** 个(`useSessionManagement` 仍要解构约 40 个参数)、`profile*` **6** 个、`synastry*` **4** 个(无 hook,散在 `Home()`),目标 useState 52 → **≤36**。另修第一批留下的尾巴:`createRectificationShellSetters` 在 render 体里无记忆化 → 每帧新身份 → 多一条 `exhaustive-deps` warning(119→**120**),**正解是稳住 setter 身份、不是塞进 deps**(塞进去会每帧重拉入口摘要),本单要把 warning 降回 119。零行为变化;先分类再动手。不占 BUG 号 | 待领取 | — | | `TASK-api-server-backdoor-close-20260916.md` | — | **取代 decomposition 单的阶段 1** · **第二版(2026-09-16 改写)**:第一版的「8 方法 / 314 行」**错了一个数量级**——闭包只跟了 `self._x()`,漏掉 `_compute_consultation_workflow` 那 6 行委托转给模块级 `execute_consultation_workflow(self, ...)` 的一跳。执行方重算实测 **115 方法 / 4,104 行(占全类 51% 方法),但碰 HTTP 上下文的仍是 0 个**。产品在 A/B/C 中**选定 B(mixin 抽取)**:方法体原样搬进 `ConsultationComputeMixin`,`JyotishAPIHandler(BaseHTTPRequestHandler, Mixin)` 靠 MRO 解析,离线调用方直接实例化 mixin——四个伪造点全关。**产品同时授权:§4 那条「不得搬 ≥150 行业务方法」按本意解释(本意是防逐行改写的 C 案),mixin 放行。** 必须先过 **spike 闸门**:搬完后 `test_api_server_security.py` 一字不改直接跑,绿则继续、红则退回 A(只搬 7 方法/300 行、关 2 个伪造点)。真风险是循环 import——闭包引用同文件 44 个模块级函数 + 21 个常量。`__new__` 归零只针对 scripts 侧 4→0(tests 侧 29 处含不许改的 security 测试,保持不增长)。阶段 3 仍不做。不占 BUG 号 | **已执行(spike 红 → 退回 A)** | spike 实测:整体 mixin 化后 `test_api_server_security.py` **1 failed / 128 passed**——`test_chart_async_job_executes_in_background` 挂在 `monkeypatch.setattr(jyotish_api_server, '_write_async_job_record', ...)`:调用方法随 mixin 搬走后从新模块 globals 解析,补丁落在旧模块上不生效(已证明把同一 fake 打到 mixin 模块即恢复原行为,非搬坏)。循环 import 不是障碍(移动集不引用 `JyotishAPIHandler`)。按 §6.3 退回 A:`scripts/offline_compute_mixins.py` 收 7 方法 / 300 行 + 3 助手 + `BadRequest`,关掉 `consultation_workflow_service:27` 与 `local_accuracy_report:141` 两处伪造,scripts 侧 `__new__` **4 → 2**;类方法 225 → 218、行数 11,291 → 10,924;security 测试一字未改 **129 passed**。剩余 2 处伪造都在咨询工作流链上,需另案解决 monkeypatch 落点问题 | | `RECONCILE-20260916.md` | — | **对账清单(不是任务书)**:状态板与现实脱节(09-15~16 那 10 份早已合入却仍写「待领取/待验收」,本轮已修正),所以另外 7 份 09-10~14 的单**不能拿 README 当证据**——它们没有 `PROGRESS-*.md`,但引用的 BUG 号都是 `resolved`。要么被别的单顺带修了没留记录,要么压根没做。每行回一个「做了/没做」即可。另附三条我已查到确定没做的证据、两条状态未闭环的、以及 BLK-001 仍红(2026-09-16 在 `4f643aa0` 复跑确认) | 待产品负责人 / 执行方回填 | — | -| `TASK-rectification-precision-gate-guided-collect-20260916.md` | `PROGRESS-rectification-precision-gate-guided-collect-20260916.md` | **出卡加精度门槛 + 引导式补经历**:真机 30 分钟窗给 5 件事 / 3 领域就出卡,区间 20 分钟、5 候选并列 26/26/20%,卡下只有自由文本邀请。产品拍板 D1 出卡门槛「宽度 ≤10 分钟且前两名差 >3 个百分点且不并列」;D2 用户说没有了仍按现行规则出卡(保留永远给结果);D3 门槛未达改为系统点名逐题问 + 类型芯片 + 年/月选择器录入,删自由文本邀请;D4 跳过的线换问法再问一次(拒绝不重问,改 BUG-687 口径);D5 时间点题答「没发生」不关领域、存在性题问整个领域、七条线一张表不许按领域写死。引擎新增 `guided_collect_windows`(边界不设 45 天闸门、含小运),不改打分与 lead。Skill 10.0.27。附 T6 两条核实:B/C/D 回执文案对调、性格题后范围回弹 8 分钟。BUG-740~743 | 待验收 | `codex/rectification-precision-gate-guided-collect-20260916` | +| `TASK-rectification-precision-gate-guided-collect-20260916.md` | `PROGRESS-rectification-precision-gate-guided-collect-20260916.md` | **出卡加精度门槛 + 引导式补经历**:真机 30 分钟窗给 5 件事 / 3 领域就出卡,区间 20 分钟、5 候选并列 26/26/20%,卡下只有自由文本邀请。产品拍板 D1 出卡门槛「宽度 ≤10 分钟且前两名差 >3 个百分点且不并列」;D2 用户说没有了仍按现行规则出卡(保留永远给结果);D3 门槛未达改为系统点名逐题问 + 类型芯片 + 年/月选择器录入,删自由文本邀请;D4 跳过的线换问法再问一次(拒绝不重问,改 BUG-687 口径);D5 时间点题答「没发生」不关领域、存在性题问整个领域、七条线一张表不许按领域写死。引擎新增 `guided_collect_windows`(边界不设 45 天闸门、含小运),不改打分与 lead。Skill 10.0.27。附 T6 两条核实:B/C/D 回执文案对调、性格题后范围回弹 8 分钟。BUG-740~743 | **已验收:未通过(带修复单)** | `cfb41daf`;tsc/lint/Static/gzip(+0.44%) 通过,D1~D5 单测通过;但 `npm test` 新增 16 红(校正既有断言未跟上)+ memoization golden 因 receipt 新键红(门禁级,staging 仍部署 317e9f18);引导窗口领域轮询分配、回放未按真值注入、录入卡走模型轮 → `TASK-rectification-precision-gate-guided-collect-fix-20260916.md` | +| `TASK-rectification-precision-gate-guided-collect-fix-20260916.md` | — | **验收修复单**:F1 `decision_receipt` 新增 `guided_collect_windows` 让 `test_rectification_engine_memoization` golden 红(在 CORE_PYTEST_TARGETS,staging 未部署 cfb41daf);F2 16 条既有校正断言红未按三栏改;F3 `mayDeliverOnPrecision` 缺省即放行、短路 BUG-654 且 `guidedCollectExhausted` 不含 refresh;F4 无领域轨道窗口轮询贴领域、一窗只问一领域;F5 离线回放注入 month_lo 非真值方向、0/20 不作数;F6 录入卡合成「或」列表句走模型轮;F7 page.tsx +1、手造 fixture。D6 门槛达标即出卡待产品确认。BUG 段 744 起 | 待领取 | 与主单同文件;开工基线 3391 / 47 | ## 命名与归档 diff --git a/docs/tasks/TASK-rectification-precision-gate-guided-collect-fix-20260916.md b/docs/tasks/TASK-rectification-precision-gate-guided-collect-fix-20260916.md new file mode 100644 index 00000000..815c82ee --- /dev/null +++ b/docs/tasks/TASK-rectification-precision-gate-guided-collect-fix-20260916.md @@ -0,0 +1,123 @@ +# 验收修复单 · 出卡精度门槛 + 引导式补经历(2026-09-16) + +## 0. 基线与验收对象 + +- 验收对象:`cfb41daf`(已合入 `origin/staging`,任务书 `TASK-rectification-precision-gate-guided-collect-20260916.md`)。 +- 代码基线:`317e9f18`(cfb41daf 的父提交)。 +- staging 部署:`/api/health` 的 `deployment.gitCommit = 317e9f18`,**cfb41daf 未部署**。门禁跑的是 `CORE_PYTEST_TARGETS`,其中 `tests/test_rectification_*.py` 含本单弄红的一条(§2 F1),与未部署的现象一致。 +- 分支:`codex/rectification-precision-gate-guided-collect-fix-20260916`,基于最新 `origin/staging`。 +- BUG 段:**BUG-744 起**(基线最大 BUG-743)。 + +## 1. 验收结论(逐条) + +验收环境:本机 Linux,`node_modules` 软链,`next build --webpack`;无 Docker、无登录态、无 Chrome。 + +| 项 | 结论 | 证据 | +| --- | --- | --- | +| `tsc --noEmit` | 通过 | 0 错 | +| `npm run lint` | 通过 | 0 error / 118 warning(基线同类) | +| `npm test` 与基线逐条比对 | **未通过** | 基线 `317e9f18`:3372 条、31 红;`cfb41daf`:3391 条、47 红。**新增 16 红**,全部是校正套件既有断言,一个文件都没改(§2 F2)。基线的 31 红是无 Docker / `[eval]` 路径别名那一组,两边相同 | +| `next build` `/` Static | 通过 | `○ /` | +| 首屏 gzip | 通过 | 575,108 → 577,616(+0.44%) | +| `page.tsx` 不增长 | 勉强 | 1837 → 1838(+1 行 `birthDate` prop) | +| Python 定向(4 文件) | 通过 | 56 passed | +| Python `tests/test_rectification_*.py` 全量 | **未通过** | `test_rectification_engine_memoization.py::test_score_candidates_matches_baseline_golden` 红:`decision_receipt` 多了 `guided_collect_windows` 键;基线同文件 14 全绿(§2 F1) | +| T1 出卡门槛 | 通过(带 F3) | `deliveryMaxWidthMinutes` 只在 policy JSON 定义一处;`decideFromDossier` 与 `decideAfterInferenceChange` 有 state 分支都经 `narrowingExhaustion` 传 `precisionGateMet` / `guidedCollectExhausted`;新单测 8 条绿 | +| T2 引导题源 | 通过(带 F4、F5) | `guided_collect_windows` 挂进 packet / receipt;`declined_domains` 进合同校验;不改 `MIN_BOUNDARY_DAYS` | +| T3 引导问法与录入 | 通过(带 F6) | 题型顺序、录入卡、选择器年份范围、门槛未达无自由文本邀请,新单测绿;`RANGE_DELIVERY_OPEN_COLLECT_*` 已删净 | +| T4 / T4b | 通过 | 跳过重问一次、拒绝不重问、七条线整领域题干、时间点负答案不关领域、七领域遍历断言 | +| T5 Skill 10.0.27 | 通过 | registry + versions 目录 + hash;历史会话可开只有合同测试,浏览器级留清单第 6 条 | +| T6 | 通过 | BUG-742 已修;BUG-743 `investigating` 且没编根因 | +| T7 记录 | 通过 | BUG-740~743、CHANGELOG、DESIGN、VOICE、真机清单 | + +**总结论:未通过。** 两条门禁级红(F1、F2)必须先修;F3~F6 一并在本单做。 + +## 2. 未通过项与修法 + +### F1(P0,门禁红)`decision_receipt` 新键让 memoization golden 红 + +- 实证:`scripts/rectification/decision_policy.py` 把 `guided_collect_windows` 写进 receipt;`tests/test_rectification_engine_memoization.py::_assert_tiered_equal` 对 receipt 做键集合严格相等,左边多出 `guided_collect_windows`。该文件在 `run_quality_gate.py` 的 `CORE_PYTEST_TARGETS`(`tests/test_rectification_*.py`)里。 +- 修法:这是**形状变化**,不是 BUG-733 禁止的"重建 golden 掩盖浮点漂移"。按 BUG-733 的口径,同进程差分仍是主证据;golden 只允许**追加 `guided_collect_windows` 一个键**,进度记录里贴 golden 的 diff,必须只有这一处。不得放宽 `_assert_tiered_equal` 的键集合比较。`docs/BUG_HISTORY.md` 的 BUG-733 条目补一句"2026-09-16 因 receipt 新增键重生成,diff 仅此一键"。 +- 验收:`.venv/bin/python -m pytest tests/test_rectification_*.py` 全绿;golden diff 只含新键。 + +### F2(P0,红线 §7.3)16 条既有前端断言红,进度记录写成"已按三栏改" + +新红分布(基线全绿): + +| 文件 | 条数 | 性质 | +| --- | ---: | --- | +| `rectification-collect-direction-20260904.test.ts` | 3 | 门槛语义(原"分开即停采集") | +| `rectification-adopt-flow-fix-20260903.test.ts` | 2 | 门槛语义 / 题干 | +| `rectification-adopt-narration-20260904.test.ts` | 2 | 门槛语义 / 提示句 | +| `rectification-targeted-collect-cards-20260913.test.ts` | 2 | 旧题干「结过婚或订过婚吗」、旧邀请 /不限领域/ | +| `rectification-answer-choice.test.ts` | 1 | 选项文案 | +| `rectification-choice-card.test.ts` | 1 | 题干 | +| `rectification-convergence-budget.test.ts` | 1 | helper 路径 stopReason(F3) | +| `rectification-decide-next-action.test.ts` | 1 | helper 路径(F3) | +| `rectification-delivery-vs-collect-20260914.test.ts` | 1 | 门槛语义(GET 并列不再交付) | +| `rectification-superseded-focus.test.ts` | 1 | 七条线全轮到后"最后一问"变了 | +| `rectification-tied-first-fix-20260914.test.ts` | 1 | helper 路径吞掉 BUG-654 规则(F3) | + +- 修法:逐条二选一——属 D1~D5 预期变化的,改断言并写「原值 / 新值 / 原因」三栏;属 F3 的,先修代码再看断言。**不得删测试、不得 skip。** 进度记录列 16 条各自的处置。 +- 验收:`npm test` 红数与基线逐条一致(31 条同名),总数 ≥ 3391。 + +### F3(P1)`mayDeliverOnPrecision` 缺省即放行,把 BUG-654 规则一起短路 + +- 实证:`core/rectification-decision.ts` `mayDeliverOnPrecision`:`precisionGateMet` 与 `guidedCollectExhausted` 都缺省时返回 `true`;`decideRectification` 用它把 `stillNeedNarrowing`、`datedMethodCollectOpen` 一并绕过。于是任何不传这两个 flag 的调用(`decideConversationalSession`、`decideAfterInferenceChange` 的无 state 分支、全部既有单测)都失去了"刷新与定向线未穷尽不得交付"(BUG-654 / 656)。`tied-first-fix` 那条红就是这个:`targetedCollectExhausted: false` 也交付了。另外 `guidedCollectExhausted()` 只收 `targetedCollectExhausted`,不含 `refreshExhausted`:引导池空、刷新还没试过,也会直接出卡。 +- 修法: + 1. flag 缺省 → 门槛**不参与**,`stillNeedNarrowing` / `datedMethodCollectOpen` 按原逻辑生效(helper 路径行为回到 317e9f18)。 + 2. flag 传入 → `mayDeliver = userStopped || precisionGateMet || (guidedCollectExhausted && refreshExhausted)`。 + 3. **产品拍板项(见 §3 D6)**:`precisionGateMet` 为真时是否允许跳过未问完的采集线直接出卡。默认按 D6。 +- 验收:`rectification-tied-first-fix` / `decide-next-action` / `convergence-budget` 三条恢复绿或按三栏改;新增单测「引导池空但 refreshExhausted=false → 不交付」。 + +### F4(P1)引导窗口的领域是轮询分配的,一个窗口只问一个随机领域 + +- 实证:`event_probes.py` `guided_collect_windows`:Vimshottari / 那罗延本命轨道的边界与领域无关,代码用 `fallback[unlayered_index % len(fallback)]` 轮流贴一个领域;只有 `nara:d9` / `nara:d10` 两条轨道有固定领域。前端 `windowAlreadyAsked` 以 `(年, 月区间, 领域)` 为键,用户答「这段没有」只关这一组合,但引擎每个边界只产一行,同一窗口不会再以别的领域出现。结果是"2018 年 3 到 5 月有没有换工作"答没有,用户那段时间的搬家或恋爱永远问不到。 +- 修法(表驱动,七条线一样):无领域轨道的窗口题不指定单一领域,题干「YYYY 年 M 到 M 月之间,有没有什么事,比如<开放领域口语 2~3 个>?」,`domain` 字段留 `null` 或 `"any"`;A 之后录入卡的类型芯片由用户选;`d9` / `d10` 轨道保持固定领域。`windowAlreadyAsked` 键去掉领域。`declined_domains` 只用于剔除例子。 +- 验收:Python 单测「无领域轨道窗口 `domain` 为 any」;前端单测「any 窗口题干列 ≤3 个开放领域口语、A 后芯片无默认或默认第一开放领域」。 + +### F5(P1,研究口径)离线回放没按任务书注入真值方向事件,"0/20"不能作数 + +- 实证:`scripts/research/guided_collect_holdout_replay.py` `synthetic_event` 一律取 `month_lo`,与真值候选的边界月无关;领域用轮询值。任务书要求"注入真值方向的带年月事件"。所以进度记录里"没有一例靠引导件达标"只说明合成事件不在真值边界上,不说明引导题源无效。 +- 修法:对每个窗口,取 `starts_by_time[true_time]` 同一轨道、同一 index 的日期作为事件月(真值方向);再跑一组"反方向"(取离真值最远的候选)作对照;三档半径都跑。报「达标件数中位」「达标例数」「反方向达标例数」。仍不是合入门槛。 +- 验收:`docs/research/guided_collect_holdout_2026_09_16.json` 更新并附口径说明;进度记录改数字。 + +### F6(P2)录入卡提交的是选项列表拼成的句子,走模型轮落库 + +- 实证:`event-date-entry-card.tsx` `formatEventDateEntryMessage` 生成「2019 年 3 月,开始认真关系、分手或结婚」发给 `send("message")`,经分类器与模型再写账本。账本 summary 是三选一列表,不是用户说的事;每次录入多一轮模型调用与延迟。 +- 修法:文本改为「YYYY 年 M 月(D 日),<领域标签>方面有一件事」;或直接走 `set-focus` / `batch` 的结构化写入不经模型。账本 summary 不得含「或」列表。 +- 验收:单测断言提交文本;账本 summary 断言。 + +### F7(P3,记录即可) + +- `page.tsx` 1837 → 1838:`birthDate` 可从 `conversational-birth-time-rectification.tsx` 内部取档案,把那一行挪出去。 +- `tests/test_event_probes_guided_windows.py` 用手造 static contexts(沿用 `test_rectification_event_probes.py` 既有模式);`test_declined_domains_are_removed` 在空窗口时 `skipTest`。至少一条用真实引擎 golden 的 20 分钟窗口断言窗口非空、不许 skip。 + +## 3. 决策记录 + +- D1~D5 沿用主单。 +- **D6(本单新增,待产品确认,默认按此执行)**:`precisionGateMet` 为真即出卡,剩余采集线不再问;Skill §流程那句"所有线问完或用户说没有了后才交付"改为"门槛达标、用户说没有了或引导题问完后交付"。若产品要求仍问完线,改 `mayDeliver` 去掉 `precisionGateMet` 短路即可,其余不动。 + +## 4. 硬红线 + +主单 §4 全部沿用。另加:不得放宽 `_assert_tiered_equal`;不得删或 skip 任何既有测试;F4 不得按领域写 if。 + +## 5. 开工前置 + +```bash +git fetch origin --prune && git status -sb +git worktree add -b codex/rectification-precision-gate-guided-collect-fix-20260916 \ + .worktrees/rectification-precision-gate-guided-collect-fix-20260916 origin/staging +grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 应为 BUG-743 +cd frontend && npm test 2>&1 | grep -E "^# (tests|pass|fail)" # 记基线 3391 / 47 +cd .. && .venv/bin/python -m pytest tests/test_rectification_*.py -q | tail -3 +``` + +Bug 检索:BUG-733、BUG-654、BUG-656、BUG-740~743。 + +## 6. 验收口径 + +- F1、F2 是合入门槛:Python `tests/test_rectification_*.py` 全绿;`npm test` 红清单与基线逐条一致。 +- F3~F6 各带单测;F5 只看数字与口径。 +- 合入后 `/api/health` 的 `gitCommit` 必须等于修复提交;仍是 `317e9f18` 视为未部署。 +- 真机清单 `docs/testing/rectification-guided-collect-20260916.md` 六条留给产品负责人。