merge: accept cross-midnight gate fix and sync approved cache task
Resolve BUG-985 using independent third-environment review recorded in 0ca3871d. Retain staging's complete BUG-984 task and approved read-only policy.
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -13018,7 +13018,7 @@
|
||||
|
||||
## BUG-985 | 同日不变性回归写死浮点分数哈希导致跨机门禁失败
|
||||
|
||||
- 状态:blocked
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-20
|
||||
- 最近更新:2026-09-20
|
||||
- 影响面:`tests/test_dasha_transition_proximity_cross_midnight.py` 及快速门 bridge;阻塞 `aa46da10` 的合入验收,不是打分修复本身的回归。
|
||||
@@ -13027,8 +13027,8 @@
|
||||
- 根因:把“同环境新旧实现相同”的相对不变量写成跨环境绝对不变量。四位分数本身就可能不同,不是序列化尾噪。BUG-733 的既有防复发与同机差分测试仍在,但没有阻止新文件重引绝对浮点哈希,属同形复发。
|
||||
- 修复:保留三个 ordinal 和 121 个候选;A 使用真实 contexts,B 仅在 transition helper 边界去掉 `candidate_at` 进入既有 legacy 回退,主事件引擎继续使用完整 contexts;同机分数与矩阵 canonical 字节均严格相等,不加容差、不删测试、不 skip/xfail。bridge 顶部记录重复收集原因与独立用例数。
|
||||
- 验证:Windows 原测试 18 通过;隔离 Linux 原测试 14 通过/4 失败,复现跨环境差异。修改后两环境定向(含 memoization)均 32 通过、校正 glob 均 216 通过;内存回退候选日期后两环境均同日三项绿、真实跨午夜一项预期红。生产红线文件与历史 golden 本轮不改。
|
||||
- 验收缺口:Linux 是同一物理机上的容器,不冒充任务书要求的第二台独立机器;另一台 Linux 机器/runner 的本轮提交绿测未取得,因此不提前标 resolved。Windows quick 两侧缺 mcp;完整门禁结论见进度记录。
|
||||
- 独立机器验收闭环:2026-09-20 产品提供并批准第三套独立 Linux/Python 3.13 环境 review(记录于 `0ca3871d` 的任务索引):定向 18 项全绿;日期回退同日 3 绿、跨午夜相关 4 红;校正 glob 从 staging 200 通过到修复版 216 通过,零新增失败。两台机器要求已满足,本项 resolved 仅指测试缺陷,不代表 BUG-981/984 部署与缓存闭环。完整 quick 的既有环境失败仍见进度记录。
|
||||
- 防复发:同日/不变性类回归一律用同机相对比对,不得写死跨机浮点字面量;参照 `tests/test_rectification_engine_memoization.py` docstring 的跨机舍入教训。同日不变性与跨午夜正确性必须分开,以日期回退探针分别验证绿/红;桥接覆盖和重复计数必须明示。
|
||||
- 相关记录:BUG-981、BUG-733、BUG-712;F3 同步确认 BUG-984 为 BUG-981 端到端阻塞项。
|
||||
- 复发自:BUG-733(同进程可证的等价关系被跨机 golden 代替)。
|
||||
- 修复版本:`codex/rectification-cross-midnight-gate-fix-20260920` 本地实施,待独立机器验收及交付;详见 `docs/tasks/PROGRESS-rectification-cross-midnight-gate-fix-20260920.md`。
|
||||
- 修复版本:`25232ce4`,第三环境 review 通过;本次按产品授权合入 staging,详见 `docs/tasks/PROGRESS-rectification-cross-midnight-gate-fix-20260920.md`。
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# PROGRESS · 跨午夜门禁浮点断言修复(2026-09-20)
|
||||
|
||||
## 2026-09-20 独立 review 后交付追加
|
||||
|
||||
产品已提供第三套独立 Linux/Python 3.13 环境复验并允许合入,证据在 staging `0ca3871d` 的任务索引:定向 18 项通过,回退同日 3 绿/跨午夜相关 4 红,校正 glob 200 → 216 全绿。BUG-985 改 resolved,旧双机缺口解除;下文保留原执行时历史。同步 `a3577ce2` 时缓存补单按产品要求完整取 staging 版(已吸收原分支六行),不丢策略 b 授权。此次仅交付已 review 通过的原核心修复与测试修复,BUG-984 随后另树执行,不宣称生产端到端完成。
|
||||
|
||||
## 基线、范围与交付
|
||||
|
||||
- 执行单:`TASK-rectification-cross-midnight-gate-fix-20260920.md`(F1–F4)。用户要求同步代码执行该单,不扩大到 BUG-984 缓存实施。
|
||||
|
||||
@@ -291,14 +291,9 @@
|
||||
| `TASK-owner-case-purge-20260919.md` | `PROGRESS-owner-case-purge-20260919.md` | **上游库主案例与本机路径残留清除(只含本仓)**:镜像同步带进库主本人案例(敏感案例标识与本机路径)并被 `origin/staging` 命中,涉及无引用的 `versions/` 三快照、前端 fixture、Python 测试、整机扫描台账、会话转录及上游 SKILL 快照。运行时无特判不用动。产品拍板整体删除不留匿名版;fixture 统一虚构常量;`import_yinduzhanxing.py` 加隐私排除项 + 新增仓库级隐私守卫测试;上游 SKILL 快照等库主清完再重导入(BLOCKED 记录)。上游仓的清理指令另见 `UPSTREAM-INSTRUCTION-owner-case-purge-20260919.md`(交给库主,不在本仓执行)。BUG-972/973 | **已验收通过(2026-09-20,`497798ac`);未合入 staging,等产品放行** | 两轮:首轮未通过(1 个隐私守卫冲突:新增路径规则与答案键守卫冲突,该守卫在快速门 glob 内,合入会让门禁红)→ 修复单 `TASK-owner-case-purge-fix2-20260919.md` → `497798ac` 通过。Claude 在 Linux 全依赖环境独立复验:快速门 Python 步 859 passed / 0 failed(上一轮就是这步红),Python 全量 63 红与基线逐条相同、0 新红,收集数与删除清单已记录;tsc 0 / lint 0 error、120 warning 同基线 / `npm test` 失败清单为基线子集(少 1 条工作流 YAML,非回归)/ `○ /` Static、首屏 gzip 与基线字节相同(前端自首轮提交起零改动)。上游指令文件已逐字节还原为基线原文;12 个已删测试名与计数已落进度记录;BLOCKED 两条已划掉。校正 Skill 哈希包、注册表、上游快照、`frontend/src`、主 API 全程 0 改动;库主本机用户名 0 命中。遗留 P3:进度记录和 BUG 状态文字待后续对账修正 |
|
||||
| `TASK-consult-smalltalk-fastpath-20260920.md` | `PROGRESS-consult-smalltalk-fastpath-20260920.md` | **普通对话寒暄轮快速通道**:真机一句「你好」触发完整窗口排盘(活动面板「已完成 4 步」)+ `## 先回答你的问题` + 400 字判词 + 扣 1 点。三层叠加:`index.ts` 两处「every turn 必调排盘」(BUG-922)与 `contractReady()` 的 `requireTool` 把排盘变成硬合同;`product-voice.ts` OPENER SHAPE 标「三种模式共用」;唯一的 chit-chat 豁免句只在 `natalSpokenReportContract` 里、只拼进本命 Agent(BUG-977)。计费侧「写回复」与「扣点」绑在 `complete_consultation_response` 同一次调用,`cancel` 只退款不写消息,所以今天没有「不扣点但保留对话」的通道。**产品拍板 a:不扣点、不排盘、回一句白话**;**分流不得用正则/关键词/长度阈值**,改为进 Agent 之前一次极短的结构化模型调用(复用本轮已选模型),fail-open 一律落回完整路径;BUG-922/923 的三处合同一个字不改;新增 `complete_consultation_free` 迁移。BUG-976/977 | 本地实现及独立审查完成,两项 SDK 隐私/成本问题已修复;Linux 最终全量 3530/3530 → 3566/3566、标准 DB 39/39 → 40/40、tsc 0、lint 0 error/120 既有 warning;两侧首页 Static,首屏 gzip +0.0493%;**已验收通过(2026-09-20,Claude 独立复验 `539d4dae`)**:同机两侧对照 tsc 0 / lint 0 error·120 warning / npm test 基线 3530 与候选 3563 失败名单逐条相同(31 条均为无 Docker)/ 两侧 `○ /` Static、首屏 gzip +299 B(+0.0483%)/ 部署 SHA 与迁移已核对;红线四文件零改动。剩真人模型语义、延迟 P50、余额与刷新走查(无受控账号) | `codex/consult-smalltalk-fastpath-20260920`;实际基线 `fcad06372`;逐项测试对照见 PROGRESS,真人清单见 `docs/testing/consult-smalltalk-fastpath-20260920.md` |
|
||||
| `TASK-rectification-validation-integrity-20260920.md` | `PROGRESS-rectification-validation-20260920.md` | **生时校正验证体系补缺(纯离线评测,不改打分不改产品)**:会议要求把「推断真实出生时间」与「用户认可的参考盘」分开证明。核对结论——**产品口径侧四条已落地**(`accepted`≠`confirmed` 两条写入路径、确认门 fail-closed 且 `holdout` 为 `not_ready` 使 `confirmation_allowed` 不可能为真、采用不写 `reported_birth_time`、无任何把采用率当准确率的指标;运行时也无按生日走捷径的分支);**缺口全在评测本身**。三条:① 封存契约 `rectification_sealed_holdout.v1.json` 的三个打分哈希互不相同(封存 `f41c298d` / 契约记录 `99730c84` / 基线实测 `b15d9ea1`),`official_eval_trial_count: 0`——当前实现**从未产出过一次有效官方盲测**,唯一跑过那次已被资料审计作废(top-1 `0.15`,发布门要 `0.60`),可见的 `0.45` 自带「不得当发布指标」标记(BUG-978);② 全部离线评测的候选窗**以真值为圆心**(`_candidate_moments()`、`request_from_case()` 的 `true_time`),生产以申报时间为圆心(`ENGINE_SEARCH_RADIUS_MINUTES = 15`)——「真值掉出窗外」这一失败模式从不可见(BUG-979);③ v3 封存但每例仅 3 事件、v4 有 7+ 事件却已被看过并用于调参,**无口径干净又贴近真实会话的封存集**;六题回放的 `0.80/0.55/0.35` 是「真值方向最优答」的上帝视角上界,±30/±60 仍低于发布门(BUG-980)。T1 申报偏差敏感性 sweep、T2 有效重跑 + 契约对齐 + **防复发新测试**、T3 只出 v5 采集协议、T4 记录。**硬红线:不得改 12 个打分文件、不得用封存集调参、不得把 `status` 改 `ready`。** 家庭信息(父母职业/兄弟姐妹)在拿到基线数字前不开工——现有七领域全是带日期事件,静态属性没有输入口。前置:owner-case-purge 三提交仍未合入 staging。BUG-978~980 | **已验收通过(2026-09-20,Claude 独立复算)**;独立盲测仍 blocked;门禁/部署待核验 | `932f2fff`。Claude 独立复核:T1 完整重跑 900 组合**逐例 8 字段 0 差异**、summary/specification 全等,另从 900 条逐例重算 45 格表与发布表逐位相同;T2 独立复跑 0.45/0.50/6.45/0/1.0/0.0 与哈希全序 0.05/0.10 全部一致;12 个打分文件字节未动、`status=not_ready`、`confirmation_coverage_rate=0`、实跑 `holdout_passed()`=False;新增/触及 Python 测试本机 38 条全绿;freshness 测试比对时排除 `frozen_at_utc`(BUG-693/694 教训已用上)。**执行方正确推翻任务书 T2.3**:「首次口径干净的官方盲测」与 BUG-428 防复发(已看过结果的案例不得再计入盲测)冲突,已核 BUG-428 原文,是任务书写错。环境缺口:本机 frontend 无 node_modules,tsc/lint/npm test/build 未能复核,采信执行方自报。遗留 → `TASK-rectification-cross-midnight-dasha-20260920.md`(BUG-981) |
|
||||
| `TASK-rectification-cross-midnight-dasha-20260920.md` | — | **跨午夜候选的 Dasha 边界错一天(生产打分)**:`scoring_service.py` 调 `merge_transition_proximity()` 只传**一个** `birth_date`,该函数用它算全部候选的 Vimshottari / Narayana 起始日期,候选之间只靠 `_context_time()` 的 `HH:MM` 区分、**日期被丢掉**。窗口跨午夜时午夜后候选的 dasha 边界整体错一天。Claude 验收时在生产调用链独立复现:窗口 `23:50→00:10`、21 个候选,**恰好那 11 个跨日候选分数错、10 个同日候选逐位相同**(幅度 +0.0267 / −0.0133,本例头名未变)。算术上界 = `cap/kernel_width`,day 精度 0.067 分/件,18 件可累计约 1.2 分,而随分钟变化项总量仅约 2.1 分 —— **上界是推的不是实测,真实幅度本单必须实测**。踩中路径:`late_night` 时段 `23:00–03:59`、`unknown` `00:00–23:59`、23:45 后或 00:15 前申报的 ±15 窗。连带发现:`calculation_spec()` 不含打分实现身份,修复后同一 spec hash 对应不同分数,历史 Case 静默失去可复现性(同 BUG-427 类型)。**产品 2026-09-20 已就三点拍板:A 修、B 修完重新冻结并重跑 T1/T2、C 让新旧结果可区分。** C 的做法经查证已修正:`calculation_spec_hash` 全在 **V4** 链路、**V9 零引用**,原提案 bump `INPUT_CONTRACT_VERSION` 对真实历史无效已作废;改为随修复 bump `engine_version`(`v9EngineVersion()` 缺省串用于 started/failed,成功回执与 minute 缓存身份实际来自后端;已同步 `ALGORITHM_VERSION`,旧「只写不比」假设作废),**不得动 `skill_version`**(BUG-621:open RPC 要求绑定 Skill 等于当前版本,bump 会让历史校正打不开)。硬红线:只改「按候选日期取 dasha 起始」,不得动 kernel/cap/share 任一常数;确认门不变。BUG-981 | **已 review:核心修复通过,但暂不合入** —— 阻塞于 `TASK-rectification-cross-midnight-gate-fix-20260920.md`(BUG-985) | 实现 `aa46da10`(分支 `codex/rectification-cross-midnight-20260920`,未合入 staging)。Claude 独立 review:修复后整窗打分与**逐候选独立重算 21/21 一致**;非跨午夜分数基线 vs 修复**逐位不变**(我测半径 10 六例 + 半径 60 三例,执行方证据覆盖 19 例 / 2299 候选全部 `bytes_equal`);kernel/cap/share/`PRECISION_WEIGHTS` 一个未动;`status=not_ready`、coverage 0、`holdout_passed()` False、官方试次 0;决策 C 执行正确(`ALGORITHM_VERSION` 7→8,`INPUT_CONTRACT_VERSION` 与 `skill_version` 未动,golden 里 `calculation_spec_hash` 不变可证);既有断言改动均带三栏说明且为加强。**P1 阻塞**:新增的 `test_same_day_public_aa_scores_keep_pre_fix_bytes` 写死 121 个浮点分数的 SHA-256,在 Claude 机器上 ordinal 2/3 红、**基线与修复分支同样红**(非修复所致),且经 `test_rectification_cross_midnight_gate.py` re-export 落入快速门 glob —— 同 glob 基线 214 passed/0 failed、`aa46da10` 4 failed,推 staging 会让门禁红。执行方自报未通过的 BUG-984 经独立确认成立且更重:`block_scan` 只比 evidence 指纹不读打分身份,而 `late_night`(299 min)/`unknown`(1439 min) 均 >120 走该分支、又恰是最易跨午夜的窗口 |
|
||||
| `TASK-rectification-cross-midnight-gate-fix-20260920.md` | `PROGRESS-rectification-cross-midnight-gate-fix-20260920.md` | **review 修复单:门禁级浮点哈希断言(`aa46da10` 的合入阻塞项)**:新增回归把 121 个分数的 SHA-256 写死成字面量,于是断言范围把跨机 libm/pyswisseph 差异也圈了进去。实测该组 121 个分数**全无浮点尾噪**(`repr(s)==repr(round(s,4))` 121/121),所以差异是第 4 位真的不同,靠改序列化消不掉。同一提交刚改过的 `test_rectification_engine_memoization.py` docstring 正好写着「跨机舍入已漂 1.1e-3,不得整体 `==` 比较」——教训被引用了又被踩。执行方自己的证据 JSON 用的却是正确做法(`scores_bytes_equal` = 同机基线 vs 当前)。**根因**:要证的是相对不变量(同机基线 vs 当前),却实现成绝对不变量(当前 vs 某台机器的历史哈希)。F1 改用生产代码已有的 legacy 回退路径做同机 A/B 对照(去掉 `candidate_at` 即修复前行为),验收要求**两台浮点环境不同的机器各跑一次**、且回退核心修复后该测试仍绿(证明它守的是同日不变性而非跨午夜回归的替身);F2 bridge 重复收集(4 failed = 2×2);F3 查证 `block_scan` 重算是否经过被修 helper —— 会则 BUG-981 在 late_night/unknown 路径等于没上线、BUG-984 升为阻塞项;F4 记录。**硬红线:不得删测试/skip/把哈希改成本机当前值消红,不得改已验收的打分代码。** 串行:本单 → `aa46da10` 合入 → BUG-984 补单。BUG-985 | **本地实现完成,待补验,未合入 staging** | 同机 Windows/Linux 浮点行为实证不同,修复后两环境定向各 32 通过、校正 glob 各 216 通过,回退探针同日 3 绿/跨午夜 1 预期红;容器不是第二台独立机器,该条保持 blocked。F3 已证实 BUG-984 阻塞 BUG-981 端到端验收;unknown 全天初始窗本身同日,纠正原推断。完整门禁与独立复核结果见 PROGRESS。 |
|
||||
|
||||
### 跨午夜执行轮独立验收补单
|
||||
|
||||
| 任务书 | 状态 | 范围 |
|
||||
| --- | --- | --- |
|
||||
| `TASK-rectification-cross-midnight-dasha-fix-20260920.md` | 待产品确认后实施 | BUG-984:时段旧缓存不做算法身份失效、聚合回执可能取开始阶段新版而掩盖旧成功结果;原任务 T4 不判全通过。BUG-982/983 为另行登记的簇跨度与凌晨日期锚点问题,不在此补单顺改。 |
|
||||
| `TASK-rectification-cross-midnight-dasha-20260920.md` | — | **跨午夜候选的 Dasha 边界错一天(生产打分)**:`scoring_service.py` 调 `merge_transition_proximity()` 只传**一个** `birth_date`,该函数用它算全部候选的 Vimshottari / Narayana 起始日期,候选之间只靠 `_context_time()` 的 `HH:MM` 区分、**日期被丢掉**。窗口跨午夜时午夜后候选的 dasha 边界整体错一天。Claude 验收时在生产调用链独立复现:窗口 `23:50→00:10`、21 个候选,**恰好那 11 个跨日候选分数错、10 个同日候选逐位相同**(幅度 +0.0267 / −0.0133,本例头名未变)。算术上界 = `cap/kernel_width`,day 精度 0.067 分/件,18 件可累计约 1.2 分,而随分钟变化项总量仅约 2.1 分 —— **上界是推的不是实测,真实幅度本单必须实测**。踩中路径:`late_night` 时段 `23:00–03:59`、`unknown` `00:00–23:59`、23:45 后或 00:15 前申报的 ±15 窗。连带发现:`calculation_spec()` 不含打分实现身份,修复后同一 spec hash 对应不同分数,历史 Case 静默失去可复现性(同 BUG-427 类型)。**产品 2026-09-20 已就三点拍板:A 修、B 修完重新冻结并重跑 T1/T2、C 让新旧结果可区分。** C 的做法经查证已修正:`calculation_spec_hash` 全在 **V4** 链路、**V9 零引用**,原提案 bump `INPUT_CONTRACT_VERSION` 对真实历史无效已作废;改为随修复 bump `engine_version`(`v9EngineVersion()` 缺省串用于 started/failed;成功回执及 minute 缓存身份来自后端,旧「只写不比」假设作废),**不得动 `skill_version`**(BUG-621:open RPC 要求绑定 Skill 等于当前版本,bump 会让历史校正打不开)。硬红线:只改「按候选日期取 dasha 起始」,不得动 kernel/cap/share 任一常数;确认门不变。BUG-981 | **核心修复与 BUG-985 本次交付合入 staging;端到端仍受 BUG-984 阻塞** | 实现 `aa46da10`(分支 `codex/rectification-cross-midnight-20260920`,未合入 staging)。Claude 独立 review:修复后整窗打分与**逐候选独立重算 21/21 一致**;非跨午夜分数基线 vs 修复**逐位不变**(我测半径 10 六例 + 半径 60 三例,执行方证据覆盖 19 例 / 2299 候选全部 `bytes_equal`);kernel/cap/share/`PRECISION_WEIGHTS` 一个未动;`status=not_ready`、coverage 0、`holdout_passed()` False、官方试次 0;决策 C 执行正确(`ALGORITHM_VERSION` 7→8,`INPUT_CONTRACT_VERSION` 与 `skill_version` 未动,golden 里 `calculation_spec_hash` 不变可证);既有断言改动均带三栏说明且为加强。**P1 阻塞**:新增的 `test_same_day_public_aa_scores_keep_pre_fix_bytes` 写死 121 个浮点分数的 SHA-256,在 Claude 机器上 ordinal 2/3 红、**基线与修复分支同样红**(非修复所致),且经 `test_rectification_cross_midnight_gate.py` re-export 落入快速门 glob —— 同 glob 基线 214 passed/0 failed、`aa46da10` 4 failed,推 staging 会让门禁红。执行方自报未通过的 BUG-984 经独立确认成立且更重:`block_scan` 只比 evidence 指纹不读打分身份,而 `late_night`(299 min)/`unknown`(1439 min) 均 >120 走该分支、又恰是最易跨午夜的窗口 |
|
||||
| `TASK-rectification-cross-midnight-gate-fix-20260920.md` | `PROGRESS-rectification-cross-midnight-gate-fix-20260920.md` | **review 修复单:门禁级浮点哈希断言(`aa46da10` 的合入阻塞项)**:新增回归把 121 个分数的 SHA-256 写死成字面量,于是断言范围把跨机 libm/pyswisseph 差异也圈了进去。实测该组 121 个分数**全无浮点尾噪**(`repr(s)==repr(round(s,4))` 121/121),所以差异是第 4 位真的不同,靠改序列化消不掉。同一提交刚改过的 `test_rectification_engine_memoization.py` docstring 正好写着「跨机舍入已漂 1.1e-3,不得整体 `==` 比较」——教训被引用了又被踩。执行方自己的证据 JSON 用的却是正确做法(`scores_bytes_equal` = 同机基线 vs 当前)。**根因**:要证的是相对不变量(同机基线 vs 当前),却实现成绝对不变量(当前 vs 某台机器的历史哈希)。F1 改用生产代码已有的 legacy 回退路径做同机 A/B 对照(去掉 `candidate_at` 即修复前行为),验收要求**两台浮点环境不同的机器各跑一次**、且回退核心修复后该测试仍绿(证明它守的是同日不变性而非跨午夜回归的替身);F2 bridge 重复收集(4 failed = 2×2);F3 查证 `block_scan` 重算是否经过被修 helper —— 会则 BUG-981 在 late_night/unknown 路径等于没上线、BUG-984 升为阻塞项;F4 记录。**硬红线:不得删测试/skip/把哈希改成本机当前值消红,不得改已验收的打分代码。** 串行:本单 → `aa46da10` 合入 → BUG-984 补单。BUG-985 | **已 review 通过;本次交付合入 staging,BUG-985 resolved** | 实现 `25232ce4`(分支 `codex/rectification-cross-midnight-gate-fix-20260920`)。F1 改为同进程 A/B:在 `scoring_service.merge_transition_proximity` 调用边界剥掉 `candidate_at` 走生产既有 legacy 回退,对比 121 个分数与整份贡献矩阵的 canonical 字节;另加 `legacy_calls == [121]` 与 `static_contexts is contexts` 两道防空转保险。Claude 复核:写死哈希字面量 **0 残留**;**第三套环境(Linux + Python 3.13,与执行方 Windows 3.11.7 不同)定向 18 条全绿** → 两机验收闭环;**回退日期修复探针:同日 3 条全绿、跨午夜相关 4 条转红**,证明同日不变性与跨午夜正确性已真正分开;快速门 glob staging `1b646659` 200 passed/0 failed → `25232ce4` 216 passed/0 failed(+16,零新增失败,总数未降);相对合并点仅动 2 个测试文件 + 文档,`scripts/`、前端、golden、打分常数零改动。BUG-985 记录含我要求的防复发条,并正确认定为 BUG-733 同形复发。**建议 BUG-985 由 `blocked` 改 `resolved`**(证据即第三环境复跑)。环境缺口:完整快速门在 Claude 机器 120 秒超时被杀,6→4 那组数以执行方记录为准 |
|
||||
| `TASK-rectification-cross-midnight-dasha-fix-20260920.md` | — | **BUG-984 缓存与结果身份补单(BUG-981 的端到端阻塞项)**:`scoreAndPersistCurrentEvidence()` 的 `block_scan` 分支只比 `evidenceLedgerFingerprint` 即返回 `cached:true` 与旧 `algorithmVersion`,该返回发生在 `readV9EngineScoringIdentity()` **之前**;`minute` 分支则有身份门。F3 已查证完整调用链到 `merge_transition_proximity()`,故核心修复合入后,**证据未变的历史跨午夜时段缓存命中仍返回修复前分数**——在本单闭环前不得声称跨午夜问题已修。边界已按源码收窄:`late_night`(23:00–03:59) 跨日;`unknown`(00:00–23:59) 虽 >120 分钟但**本身同日**,选中跨午夜子时段后才触发(此处修正了 Claude 先前把两者并列的说法)。产品 2026-09-20 放行且**同日拍板 F3 策略选 b**:版本接口取不到可信身份时,旧缓存**只读展示 + 显著标注「按旧算法产出」**,否决 a(重算,会把接口抖动放大成长等待,时段扫描受 `JYOTISH_HEAVY_COMPUTE_CONCURRENCY=2` 限流)与 c(照常复用,与已定原则冲突)。b 的三条边界:只读结果**服务端拒绝采用/确认**(靠删不靠藏,须有定向用例)、标注必须用户可见并对照 `VOICE.md`(涉界面同提交更新 `DESIGN.md`)、回执来源身份仍是产出它的版本。SQL 由 F2 优先在应用层解决,做不到**先停下报告**再定,不得自行开迁移。**四项全部可开工。**硬红线:不重标/不删历史结果,不 bump Skill,不改 V4 input contract,不引入按 `engineVersion` 拒绝打开历史会话。串行:BUG-985 合入 → 本单。BUG-984 | **待领取**(四项全部可开工) | — |
|
||||
|
||||
## 命名与归档
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# TASK · 跨午夜修复验收补单:缓存与结果身份(2026-09-20)
|
||||
|
||||
> 状态:待产品确认后实施;本文件仅记录验收未通过项,不代表批准扩大当前生产修复范围。原任务的候选级 Dasha 日期修复与评测继续完成,不能将本补单缺口冒写已通过。
|
||||
> 状态:**待领取,四项全部可开工**(2026-09-20 产品放行,F3 策略已于同日拍板选 b,见 §3.2)。
|
||||
> 本单是 BUG-981 的**端到端验收阻塞项**(F3 调用链已查证,见 §0):核心修复合入后,新建 / 无缓存 / 证据变化的 Case 走已修路径,但证据未变的历史跨午夜时段缓存命中仍返回修复前分数。在本单闭环前,对外只能说「新算的会对」,**不得声称跨午夜问题已修**。
|
||||
|
||||
## 0. 基线与串行依赖
|
||||
|
||||
@@ -26,9 +27,31 @@
|
||||
|
||||
## 3. 决策记录
|
||||
|
||||
产品原授权 C 要求新旧结果可区分,并禁止改 Skill 版本、V4 input contract 和新增历史打开相等门。本轮已同步既有后端算法身份和前端默认值,没有改缓存政策或数据库。
|
||||
产品原授权 C 要求新旧结果可区分,并禁止改 Skill 版本、V4 input contract 和新增历史打开相等门。原核心修复轮已同步既有后端算法身份和前端默认值,没有改缓存政策或数据库。
|
||||
|
||||
本补单建议:**所有评分缓存复用必须有实际计算身份;成功回执展示成功结果来源,不用开始阶段覆盖;无法取得可信当前身份时,不把旧缓存标为当前已验证结果。** 涉及版本接口失败时是否允许旧结果只读显示、是否新增向后兼容 SQL 迁移,需在本节由产品/架构明确后再实施,不能自行删历史结果或放宽门。
|
||||
**2026-09-20 产品放行本单**(Claude review `25232ce4` 通过、F3 调用链查证完成之后)。已定与未定分列如下。
|
||||
|
||||
### 3.1 已定(可直接执行)
|
||||
|
||||
**所有评分缓存复用必须有实际计算身份;成功回执展示成功结果来源,不用开始阶段覆盖;无法取得可信当前身份时,不把旧缓存标为当前已验证结果。**
|
||||
|
||||
由此可直接开工的是 F1(先红测时段旧缓存)、F2(成功回执身份)、F4(回归、记录、部署)。这三项不依赖 §3.2 的未决点。
|
||||
|
||||
### 3.2 已定:版本接口取不到可信身份时,旧缓存**只读展示并标注**(2026-09-20 产品拍板选 b)
|
||||
|
||||
`readV9EngineScoringIdentity()` 取不到可信当前身份时:
|
||||
|
||||
- **不拒绝、不强制重算**(否决 a)。理由:时段扫描是重计算且受 `JYOTISH_HEAVY_COMPUTE_CONCURRENCY`(默认 2)限流,把一次外部接口抖动放大成用户侧长等待,代价与本单要防的风险不对等。
|
||||
- **不照常复用**(否决 c,与 §3.1 直接冲突)。
|
||||
- **采用 b**:旧结果可以**只读展示**,但必须显著标注为「按旧算法产出」,且**不得被当作当前已验证结果**。
|
||||
|
||||
b 的三条边界,违反任一条即本单不通过:
|
||||
|
||||
1. **只读结果不得进入采用 / 确认路径。** 它不能被 `accepted`,更不能被 `confirmed`;交付卡、候选选择等任何写入入口都不得接受它。
|
||||
2. **标注必须是用户可见的,不是只写进回执。** 文案先对照 `frontend/docs/VOICE.md`;若涉及界面呈现,同一提交内更新 `frontend/DESIGN.md`(`AGENTS.md` §4)。
|
||||
3. **不得因为「只读」就放宽身份记录**:回执里该结果的来源身份仍必须是产出它的那个版本,不得被开始阶段的当前版本覆盖(这与 F2 是同一条原则)。
|
||||
|
||||
**SQL 迁移**:F2 优先在应用层解决。确实无法在应用层解开「成功回执身份 vs 聚合 `max(engine_version)`」时,**不要自行开迁移,先在进度记录里写清为什么应用层做不到并停下来报告**;获准后再做,且按 §4 必须向后兼容当前已部署版本并真跑 `npm run test:db`。
|
||||
|
||||
## 4. 硬红线
|
||||
|
||||
@@ -48,9 +71,16 @@
|
||||
|
||||
覆盖 started 新版本 / succeeded 旧缓存版本、diagnostics、失败重试与历史回执。用户看到的成功结果身份必须来自该成功结果,不能由字符串 `max` 决定。历史回执保持原值且旧会话仍可打开。若动 SQL,新增兼容迁移并真跑 `npm run test:db`。
|
||||
|
||||
### F3 · 失败与覆盖边界
|
||||
### F3 · 失败与覆盖边界(策略已定为 b,见 §3.2)
|
||||
|
||||
分别测试无环境覆盖、完整覆盖、部分覆盖、版本接口超时/错误。按已批准策略说明何时重算、何时只读旧结果、何时拒绝复用;每种状态不得混淆当前身份与来源身份。
|
||||
分别测试无环境覆盖、完整覆盖、部分覆盖、版本接口超时 / 错误四种状态。每种状态不得混淆当前身份与来源身份。
|
||||
|
||||
验收标准:
|
||||
|
||||
- 四种状态各有定向用例,断言身份取不到时走**只读展示**而非重算或静默复用。
|
||||
- **必须有一条用例断言:只读结果调用采用路径会被拒绝。** 不是「界面上没有按钮」,是服务端拒绝——参照本仓既有做法,入口靠删不靠藏。
|
||||
- 标注文案在用户可见层出现,且与 `frontend/docs/VOICE.md` 对照过;涉及界面则同一提交更新 `frontend/DESIGN.md`。
|
||||
- 只读结果的回执来源身份仍是产出它的版本,不被开始阶段版本覆盖。
|
||||
|
||||
### F4 · 回归、记录与部署
|
||||
|
||||
|
||||
Reference in New Issue
Block a user