feat(rectification): 出卡加精度门槛,补经历改成系统点名
Independent Staging Quality Gate / validate (push) Failing after 6m28s
Independent Staging Quality Gate / publish (push) Skipped

宽度超过 10 分钟或头名并列时不再出交付卡,改为按大运边界逐条问、
用类型芯片和年/月选择器录入。跳过的线换问法再问一次;答「这类事
都没有过」的不再问。用户说「没有了」仍立刻给目前范围。Skill 10.0.27。

BUG-740~743
This commit is contained in:
jesse-ux
2026-09-16 18:35:27 +08:00
parent 317e9f1886
commit cfb41daf3d
75 changed files with 4763 additions and 383 deletions
+69 -4
View File
@@ -10705,8 +10705,8 @@
- 根因:`rangeNarrowHint``targetedCollectPool` 时传入空的 `declinedTopics`,有意忽略拒答。
- 修复:传入真实 `declinedTopics`。一条都不剩时写「能问的都问完了」,不再暗示还有没问的线。
- 验证:`frontend/tests/rectification-tiebreak-before-card-20260914.test.ts`
- 防复发:交付文案不得列出已拒答或已回答的线
- 相关记录:BUG-661、BUG-662
- 防复发:交付文案不得列出已答「没有发生过」的线。跳过的线按服务器计划最多再问一次,不在交付文案里当还开着的线列出。2026-09-16 产品修改防复发口径,见 `TASK-rectification-precision-gate-guided-collect-20260916.md` D4
- 相关记录:BUG-661、BUG-662、BUG-741
- 复发自:无
- 修复版本:待发布
@@ -10737,8 +10737,8 @@
- 根因:BUG-687 把空池收口写成终局句。采集线关闭不等于校正结束:交付后 Case 仍是 `candidate_ready`,输入框不禁用,新的带年月证据会改账本指纹并让快照过期。缺的是邀请;过期快照若仍带着 `tied_first` 停止原因,缺口状态机会继续停在 `delivered`
- 修复:空池文案改为不限领域的补充邀请:先请记得确切哪一天的事,再退年月;举七条线之外的例子;不承诺定到分钟。并列且线已关闭时,邀请出现在交付卡正文,不躺在浅色说明里。快照因新证据过期时,决策不再把 `tied_first` 等耗尽停止原因带进采集,缺口才不会停在交付态。
- 验证:`frontend/tests/rectification-open-collect-invite-20260914.test.ts`
- 防复发:采集线关闭不等于校正结束;交付卡必须给出不限领域的补充邀请,且补充必须可见地生效。不得把邀请写成「再说一件就能定到分钟」。不得把已经拒答的线再列一遍(BUG-687)。
- 相关记录:BUG-687、BUG-646、BUG-651、BUG-653、BUG-688、BUG-590
- 防复发:采集线关闭不等于校正结束。2026-09-16 起自由文本邀请删除,改为系统点名的引导题 + 年/月选择器(BUG-740)。不得把已经答「没有发生过」的线再列一遍(BUG-687)。
- 相关记录:BUG-687、BUG-646、BUG-651、BUG-653、BUG-688、BUG-590、BUG-740
- 复发自:BUG-687(空池收口写成终局句)
- 修复版本:待发布
@@ -11550,3 +11550,68 @@
- 相关记录:BUG-732(引入这条真实库合同但未在有 Docker 的机器上跑)
- 复发自:无
- 修复版本:待发布
## BUG-740 | 精度未达仍出交付卡,卡下只有自由文本邀请
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`decideRectification``guided_collect_windows`、引导采集池、范围交付卡
- 用户现象:30 分钟窗给了 5 件带年月经历后直接出卡,区间 20 分钟、5 候选并列约 26%/26%/20%。卡下是「你要是还记得确切哪一天的事,不限领域,说出来我接着算」。
- 触发条件:七条定向线关闭、自动题池空、头名并列。
- 根因:`tied_first` 耗尽分支没有任何宽度或领先度条件。自动题池空之后没有有方向的题源。
- 修复:出卡须宽度 ≤10 分钟且前两名相对可能性差 >3 个百分点且不并列;未达时按引擎边界窗口逐条点名,用类型芯片 + 年/月选择器录入。用户说「没有了」仍按现行规则出卡。自由文本邀请删除。
- 验证:`frontend/tests/rectification-precision-gate-20260916.test.ts``frontend/tests/rectification-guided-collect-20260916.test.ts``tests/test_event_probes_guided_windows.py`
- 防复发:耗尽/offer 出卡必须过 `precisionGateMet`,除非用户停止或引导题源已空。不得再把自由文本邀请当作精度未达时的下一步。
- 相关记录:BUG-689、BUG-653、BUG-654、BUG-687
- 复发自:BUG-689(空池邀请没有方向,且没有精度门槛)
- 修复版本:待发布
## BUG-741 | 「跳过」和「没有发生过」同样永久关闭整条线
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`targetedDomainClosed`、定向存在性题、时间点题
- 用户现象:点「这条先跳过」或「记不太清楚」后,那条线再也不会出现。时间点题答「那个时候没发生」后,整条感情线也被当成没有。
- 触发条件:定向存在性题选 C/D;或 `source=event_probe` 的年月是非题选「明确没有发生」。
- 根因:`declined``skipped` 同样写入关闭集合。存在性题干只覆盖一两个例子却按整个领域记「没有」。时间点负答案没有与领域关闭隔离。
- 修复:`declined` 永久关闭;`skipped` 换一种更具体的问法再问一次,再次跳过才关闭。存在性题问整个领域、任何时间,B 写成「这类事都没有过」。时间点题的负答案不关领域。
- 验证:`frontend/tests/rectification-guided-collect-20260916.test.ts`
- 防复发:关闭集合不得把一次跳过当成拒绝。时间点题不得写入会让 `targetedDomainClosed` 判定领域关闭的状态。七条线一张表,不得按单个领域写死。
- 相关记录:BUG-687、BUG-643、BUG-740
- 复发自:无
- 修复版本:待发布
## BUG-742 | 定向存在性题 B/C/D 回执文案与状态对调
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`targetedCollectExistenceAck``RECTIFICATION_USER_COPY.collectDeclinedAck` / `collectSkippedAck`
- 用户现象:答「没有发生过」听到「记下了,这方面先跳过」。
- 触发条件:定向存在性题选 B。
- 根因:B 落 `declined`、C/D 落 `skipped` 是对的;回执把 declined 写成「先跳过」。不是 D 落成 declined。
- 修复:B 回「记下了,这条按没有发生过记」;C/D 回「记下了,这题先放着,后面换个问法再问一次」。
- 验证:`frontend/tests/rectification-guided-collect-20260916.test.ts` 断言两句回执。
- 防复发:declined 回执不得写「跳过」;skipped 回执不得写「没有发生过」。
- 相关记录:BUG-741
- 复发自:无
- 修复版本:待发布
## BUG-743 | 性格题 ±1 写入 posterior_score,可能把卡在 8 分边界的簇推过线
- 状态:investigating
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`applyProbeOutcome``unionStillValidRange`
- 用户现象:性格题答完后范围从 20 分钟弹到 28 分钟,下一题又缩回。
- 触发条件:未淘汰簇落后头名刚好 8 分,性格题给其中一侧 ±1。
- 根因(代码路径已确认,真机未复现):`varga_style``PROBE_WEIGHT.yearless = 0.5``SCORE_DELTA` 写进同一份 `posterior_score``unionStillValidRange``peak - posterior_score < MIN_SEPARATION_LEAD`。风格题只该改排序。本轮不改打分,未改并集规则。
- 修复:无。已排除:性格题不会淘汰(`yearless` 不增加 `strong_conflict_count`)。未排除:并集是否因此扩/缩。
- 验证:未附回归。不得为收口编根因。
- 防复发:风格微调若并入范围计算,必须用一份不含风格分的分数做并集。
- 相关记录:BUG-651、BUG-629、BUG-740
- 复发自:无
- 修复版本:无
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,57 @@
# 进度 · 出卡精度门槛 + 引导式补经历(2026-09-16
基线:`origin/staging` @ `20435a19`(任务书提交;代码基线其父 `071317f7`)。合入前需 rebase `317e9f18`(顶栏 preventScrollstaging 已快进 1 笔)。
分支:`codex/rectification-precision-gate-guided-collect-20260916`
BUG740743(开工时最大号 BUG-739)。
相关单已合入 staging,本单在其上实现,未回退。
## 做了什么
- T1`deliveryMaxWidthMinutes: 10` 写入 `references/rectification_policy.v1.json`Python / TS 各读一次。`decideRectification` 的 tied_first / exhausted / offer 出卡都要 `precisionGateMet || userStopped || guidedCollectExhausted``user_uncertainty_too_high` 未动。`withholdAdoptOnUnnarrowedRange` 未动。`stillNeedNarrowing` / `datedMethodCollectOpen` 在门槛已达时不再挡住出卡。`decideFromDossier` 的宽度回退到候选分数并集,避免 inference 没有 `credible_range` 时门槛恒为假。
- T2:新增 `guided_collect_windows``min_boundary_days=0`、含小运与 D9/D10 那罗延),挂进 packet。未改 `MIN_BOUNDARY_DAYS` 与自动题生成。离线回放脚本 `scripts/research/guided_collect_holdout_replay.py`
- T3:引导题排在自动题之后、定向七条线之前。录入卡 `event-date-picker.tsx` + `event-date-entry-card.tsx`。年份范围出生年到今年。删除自由文本邀请常量。常驻条加「已对照 N 件」。
- T4 / T4bskipped 换问法再问一次;declined 不重问。存在性题改问整个领域。时间点负答案不关领域。`remainingTargetedDomains` 不再按分盘层剔除。只有 `target_domain` 的拒答也关闭该线。
- T5Skill 10.0.27。hash `7e5417419ffad9bb34b78318f541484821bb22476655092047006b3a05aff020`
- T6:回执文案对调已核实并随 T4 修(BUG-742)。性格题范围回弹代码路径已看到,真机未复现,记 BUG-743 investigating。
- T7BUG_HISTORY / CHANGELOG / DESIGN / VOICE / 真机清单 / 本进度。
## 测试
### 前端
- `tsc --noEmit`0 错。
- `npm run lint`0 error(既有 warning 未顺手清)。
- 定向套件(本单相关):`rectification-guided-collect-20260916``rectification-precision-gate-20260916``rectification-eight-method``rectification-occupation-coverage-exit``rectification-probe-pool-exhausted-20260911``rectification-collect-stall``rectification-exhaustion-exit-20260906``rectification-tiebreak-before-card-20260914`**fail=0**
- `page.tsx`:只加 `birthDate` 一处 prop`Home()``useState` / `useRef` 未增长。
- 全量 `npm test`:本机无 Docker、Windows 无 symlink 权限。与 holdout 并行时还出现过 `spawn UNKNOWN` / OOM,不能当回归清单。无 Docker 的失败与基线同类(compose 起不来、symlink EPERM)。
### Python
- `pytest tests/test_event_probes_guided_windows.py tests/test_rectification_event_probes.py tests/test_candidate_discriminator_contract.py tests/test_rectification_refresh_r3_r4.py`**56 passed**。
- `run_quality_gate.py --profile quick`:卡在本机 venv 缺 `mcp` 包(`interpretation_source_inventory_gate`),与既有环境缺口一致,不是本单引入。
### T2 离线 holdout(不是合入门槛)
`minute_rectification_holdout_v4.json` 20 例,六题后按 `guided_collect_windows` 注入真值侧带月事件。550 s,错误 0。原始表 `docs/research/guided_collect_holdout_2026_09_16.json`
| 半径 | 20 例达标 | 达标例所需件数中位 | 未达 |
| --- | ---: | ---: | ---: |
| ±10 | 3 | 0(六题后已经达标,没有靠引导件补上) | 17 |
| ±30 | 1 | 0 | 19 |
| ±60 | 0 | — | 20 |
没有一例是「六题后未达、再补引导件后达标」。Picasso / Freud 三档窗口数都是 0(年龄带把边界年裁掉)。产品据此决定要不要调 10 分钟门槛。
### 未测
- `next build` 首屏 gzip ±2%:本机未跑。选择器在校正对话里,不进 `/` 首屏。
- 真机清单:`docs/testing/rectification-guided-collect-20260916.md`,留给产品负责人。
- 历史校正会话打开:Skill 合同测了版本绑定;无登录态,浏览器级留给清单第 6 条。
## 偏离
- T2 离线 20 例三档都跑完,未用让步(只跑 ±10/±30)。
- T6 性格题回弹不阻塞合入。
- 选择器年份原先误写成 1950,已改成档案出生年→今年。
- 既有测试里「训练门开即出卡 / leftover 不再问」与 D1/D5 冲突的断言,已按「原值 / 新值 / 原因」改。
+1 -1
View File
@@ -251,7 +251,7 @@
| `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` warning119→**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→0tests 侧 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,924security 测试一字未改 **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` | | **出卡加精度门槛 + 引导式补经历**:真机 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 起 | 待领取 | 与 BUG-661663 / 626~634 诸单同文件,本单优先;开工先核对它们是否已合入 |
| `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-740743 | 待验收 | `codex/rectification-precision-gate-guided-collect-20260916` |
## 命名与归档
@@ -0,0 +1,10 @@
# 真机清单 · 出卡精度门槛 + 引导式补经历(2026-09-16
在 staging 用受控账号走一遍生时校正。不要把真实出生资料写进任何记录。
1. **门槛未达不出卡。** 给两三件带年月的事、几个领域,让自动点选题问完。若目前范围仍宽于 10 分钟或头名并列,不应出现「目前范围」交付卡和采用按钮。
2. **引导题带年月区间。** 下一问应是「某年某月到某月之间,有没有…」,选项是「有,我来填时间 / 这段没有 / 记不清 / 这条先跳过」。
3. **选择器录入后范围变化。** 点「有,我来填时间」,用类型芯片和年/月选择器提交一件事。应看到记下了年月,账本更新,范围可能变。输入框始终能打字。
4. **说「没有了」出卡。** 在引导阶段打「没有了」或「就这些」,应立刻出现目前范围卡和采用按钮,不再追问第二遍。卡上没有「你要是还记得确切哪一天」这类邀请。
5. **跳过线重问一次。** 某条存在性题点「这条先跳过」,稍后应换一种更具体的问法再问同一条线;再点跳过才不再问。
6. **历史会话可开。** 打开一条绑定旧 Skill 版本的生时校正,应能进入对话,不得停在「暂时无法打开」。