Files
Jyotisha/docs/tasks/PROGRESS-consult-upstream-functional-v2-20261002.md
T

128 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROGRESS · 上游功能吉凶 v2 收尾:生时校正算法身份、普通对话 golden、第四轮残留、第五轮回测(2026-10-02)
- 执行方式:产品负责人要求子代理直接执行(Claude 子代理);无单独任务书,决策记录见下。只 commit、未 push。
- 分支 / worktree:`codex/consult-upstream-functional-v2-20261002` / `.worktrees/consult-upstream-functional-v2-20261002`
- 基线:`57782aea`(Claude/PM 按产品授权移植上游功能吉凶 profile v2、Pancha 自合修正、瑜伽引擎读同一吉凶表;父提交 `f8579466` = 事业单分支合入 `origin/staging`)
- BUG 编号:开工核对 `origin/staging` 与各 worktree 最大号 BUG-1179;本单 BUG-1180~1182,更新 BUG-1158(→ resolved)、BUG-1165(复发指向 1182)、BUG-1176(第五轮)。
- 上一单:`docs/tasks/TASK-consult-career-yoga-functional-20261002.md` / `PROGRESS-consult-career-yoga-functional-20261002.md`。
## 决策记录
- **D1 功能吉凶采用上游 profile v2**(产品 2026-10-02 授权,PM 已在 `57782aea` 移植):`bphs_ch34_general_with_sign_exceptions_v2`。推翻上一单第二次决策「吉 / 凶 / 中性分组不变」与 T1 分支逐格对照表方案。v5 77 例评测(PM 实测,命令 `python3 scripts/research/holdout_v5_baseline.py --dataset v5 --out-dir <dir>`):先验头名 ±10/30/60 0.1818/0.0779/0.0649 → 0.1818/0.0909/0.0779;六题回放 0.6364/0.4935/0.2597 → 0.6364/0.4935/0.3117;线上区间回放 0.6753/0.4935/0.3247 → 0.6623/0.5584/0.4026;覆盖 0.987/0.987/0.974 → 0.987/0.987/0.987。产品接受(一格 −1.3 pp)。
- **D2 生时校正算法身份升到 scoring-10**(本会话按先例决定,见 T1)。
- **D3 第四轮残留本轮修**(产品批准):事业落宫不翻成幕后、父母反向安慰、逆行禁句、两处请求;只改单一定义处的规则文字,不对模型输出做正则后处理。
## T1 生时校正打分合同(BUG-1181)
### 要不要升版本:要
- 先例:`TASK-rectification-engine-convergence-20260901` 硬红线 3「打分语义变化必须 bump `ALGORITHM_VERSION`」;跨午夜修复按此 7 → 8 → 9(BUG-981~985,`PROGRESS-rectification-cross-midnight-20260920.md`)。BUG-621 的教训是「升版本后历史必须还能打开」,BUG-984 已把版本不一致的历史结果做成只读 + 「重新比较」。
- 事实:功能吉凶分组经 `active_rectification_event_engine.py` 的 `*_functional_benefic_auxiliary` / `*_functional_malefic_auxiliary` 规则进入事件矩阵。同一输入(记忆化测试的公开虚构请求)候选 12:00 的分数 8.6274 → 8.4977;跨午夜虚构 golden 23:59 的分数 0.7893 → 0.9213。
- 不升的后果:`cachedEngineScoreIsReusable` 按算法身份 + 证据指纹决定能否复用,证据未变的历史 Case 会把旧分组的分数当当前结果。
- 结论:升到 `rectification-v5-matrix-scoring-10`;策略版本 `rectification-candidate-policy-v3`、输入合同 v5、Skill 版本都不变;历史结果不重标。
### 升版本时发现的第二个问题
前端五处、数据库一处用字面量 `=== "rectification-v5-matrix-scoring-9"` 判断「这是带日期窗合同的结果」(`engine-client.ts` score / diagnostics 的 `dated`、`tool-service.ts` 候选行解析与 legacy 段选择、`score-persist.ts` 是否先补日期窗、`rectification-candidate-result.ts`、`validate_dated_rectification_candidate`)。直接升到 10 会让新结果按旧的同日结果解析(跨午夜候选丢日期),数据库守卫对 scoring-10 失效。处理:按代数判断(≥ 9)。
### 改动
| 位置 | 改动 |
| --- | --- |
| `scripts/rectification/scoring_service.py` | `ALGORITHM_VERSION` → `rectification-v5-matrix-scoring-10`(注释写明原因) |
| `frontend/src/lib/rectification-agentic/core/candidate-window.ts` | 新增 `FIRST_DATED_SCORING_GENERATION = 9`、`isDatedScoringAlgorithmVersion()` |
| `engine-client.ts` / `tool-service.ts` / `score-persist.ts` / `rectification-candidate-result.ts` | 五处字面量改用上面的函数;`v9EngineVersion()` 缺省串 → scoring-10 |
| `frontend/supabase/migrations/20261002010000_rectification_dated_algorithm_generation.sql` | 只 `create or replace` `validate_dated_rectification_candidate`,守卫改 `~ '^rectification-v5-matrix-scoring-(9|[1-9][0-9]+)$'`;其余与 `20260920020000` 逐字节相同(去 CR 后 diff 只有这一行);不动表、列、权限、历史行;对当前已部署代码向后兼容 |
| `tests/golden/rectification_engine_memoization_v2.json` | 用测试文件自带的 `write_golden` 由真实引擎写出(scoring-10,`source_commit` = `57782aea`);v1(scoring-8)原样保留并以 sha256 钉住 |
| `frontend/tests/fixtures/rectification-midnight-date-anchor.delivery.scoring-10.native.json` | `python3 scripts/research/midnight_date_anchor_regression.py --baseline <本 worktree> --output <scratch> --golden --golden-path …`:真实引擎,虚构资料;同机独立进程 A/B 3 例 × 7 字段逐位相等。scoring-9 的旧 golden 保留不动 |
### 校正研究记录重新冻结(ERR-110 / ERR-114)
只改 `ALGORITHM_VERSION` 一行就让 `test_rectification_validation_integrity_gate.py` 等 8 项失败:`scoring_service.py` 在冻结身份 `PRODUCTION_FILES` 里。反过来,`57782aea` 改的 `functional_benefics.py` 不在清单里,分数变了门禁却没红(记 ERR-114)。按 09-29 BUG-1088 先例(`56b51e21`)处理:
| 步骤 | 内容 |
| --- | --- |
| 清单 | `sealed_holdout_rerun.py` `PRODUCTION_FILES` 补 `scripts/functional_benefics.py`;新增 `test_functional_roles_are_part_of_the_production_identity`(并进快速门 bridge) |
| 新标签 | 两个脚本的 `FREEZE` / `REPORT` 指向 `*_functional_v2_2026_10_02`;`IDENTITY_FORBIDDEN_PREFIXES` 加两个新前缀 |
| 冻结后重放(`PYTHONHASHSEED=0`) | `sealed_holdout_rerun.py --freeze` 后重放 20 例:与 09-29 逐条相同(top-1 0.45 / top-3 0.5 / MAE 6.45,影子 fact ranker 不读功能吉凶);`reported_offset_sweep.py --freeze` 后重放 900 例(6 分 12 秒):230 例变化,窗口内平均头名 ±15/30/60 不变(0.0636 / 0.06 / 0.05),交付覆盖 0.9864 / 0.99 / 1.0 → 0.9955 / 0.9967 / 1.0,平均分钟误差 10.02 / 16.88 / 26.96 → 10.31 / 16.72 / 25.71 |
| 合同 | `references/rectification_sealed_holdout.v1.json`:current_tree_scorer 的 extended_identity / source_report / metrics、current_tree_fixed_protocol_rerun、current_tree_reported_offset_replay 换成新记录;09-29 记录挪到 previous(`superseded_reason` 写明);`status: not_ready`、六个发布键不变;旧报告与冻结文件逐字节保留 |
这些记录是「已曝光、不可用于调参」的敏感性研究,不是发布指标,确认门照旧关闭。
### 改动的既有断言(原值 / 新值 / 原因)
| 文件 · 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `tests/test_sealed_holdout_contract_freshness.py` `IDENTITY_FORBIDDEN_PREFIXES` | 到 `quality_wording_2026_09_29` | 加 `functional_v2_2026_10_02` 两个前缀 | 新冻结标签(与 09-29 同法) |
| `frontend/tests/rectification-confirmation-gate.test.ts` 当前重跑报告路径(两处) | `…sealed_holdout_rerun_quality_wording_2026_09_29.json` | `…sealed_holdout_rerun_functional_v2_2026_10_02.json` | 同上;第一次快速门里 npm 多出这 1 项失败才发现(`406d81b8` 先例),改后 npm 全量与基线同名 |
| `tests/test_rectification_engine_memoization.py` 对比目标 | v1 golden(scoring-8)+ 投影 scoring-9 新增字段 | v2 golden(scoring-10)直接比;新增「v1 冻结且已不是当前」测试 | 分数变了,v1 不能再当当前;按「历史 golden 不改写、新增版本文件」处理 |
| `tests/test_dasha_transition_proximity_cross_midnight.py` | `== "…scoring-9"` | `== "…scoring-10"` | BUG-1181 |
| `tests/test_rectification_relative_support.py` | `"…scoring-9"` | `"…scoring-10"` | BUG-1181 |
| `frontend/tests/rectification-engine-version-cross-midnight.test.ts` | `LIVE_CURRENT = scoring-9`,scoring-9 dated golden 兼作「当前」 | `LIVE_CURRENT = scoring-10`;scoring-9 golden 记为 `DATED_HISTORICAL`;新增「scoring-9 缓存在 scoring-10 下不可复用」 | BUG-1181 |
| `frontend/tests/rectification-midnight-date-anchor.test.ts` 跨午夜贯穿 | 只跑 scoring-9 golden | scoring-9 与 scoring-10 两份都跑 | 证明新代仍按日期窗解析 |
| `frontend/tests/database-adopted-birth-date.test.ts` | 只验 scoring-9 去掉日期合同被拒 | 另验 scoring-10 / 11 被拒、scoring-8 仍按旧同日结果返回空 | 迁移守卫 |
### 验证
- 记忆化文件 22 项全过;`write_golden` 再写一次,`candidate_scores` / `decision_receipt` 相同,只有未参与比较的特征哈希不同(BUG-733 / 985 的已知跨进程浮点差,测试本就不比)。
- 红绿:把 `isDatedScoringAlgorithmVersion` 临时改回字面量 scoring-9,scoring-10 跨午夜贯穿测试即红;去掉迁移文件,`database-adopted-birth-date` 2 项即红;`57782aea^` 的旧代码跑同一记忆化请求得 8.6274,新代码 8.4977。
- 数据库(本机 PostgreSQL 17 + docker 替身,方法见记忆「local-postgres-without-docker」):`npm run test:db` 全量 80 项,基线 `57782aea` 一次性 worktree 与本分支都是 74 过 / 6 败,失败名单逐条相同(env validator、个人报告 RLS、会话标题 updated_at、admin 身份、staging 备份、stdin 大 SQL——替身不支持 pg_dump / 部署脚本等)。
- **历史打开(BUG-621 教训)**:`rectification-*.test.ts` + `skill-registry*.test.ts` 1,872 项 0 失败(含 BUG-621 按会话用绑定 Skill 打开、BUG-984 版本不一致只读 + 「重新比较」、历史回执原样读取);新增用例:真实 scoring-9 结果在 scoring-10 下 `read_only = true`、`can_recompare = true`、候选仍带日期,在 scoring-9 下不只读。
- 部署侧待办(不在本会话):核实 staging / 生产没有设置 `RECTIFICATION_ENGINE_VERSION` / `RECTIFICATION_ALGORITHM_VERSION`(`deploy/`、`.gitea/` 里没有);迁移随部署自动应用;真机走一遍「打开一条旧校正 → 只读 → 重新比较」。
## T2 普通对话 golden 与功能吉凶断言(BUG-1158)
- `PYTHONHASHSEED=0 JYOTISH_API_CHART_CACHE_TTL_SECONDS=0` 跑 `capture_consult_evidence_card_golden.py`、`capture_consult_biography_backtest_golden.py`,各两次逐字节相同;diff 只在功能吉凶字段(分组、`profile`、`role_basis`、`lagna_lord` 等新字段、Technique Audit 的 `key_functional_*`)。瑜伽字段无变化。
- 九位名人分组变化:乔布斯(处女)木星中→凶、太阳凶→中;奥巴马(摩羯)月亮中→凶;泰勒、琵雅芙(天蝎)太阳中→吉、火星吉→中、金星凶→中;嘉兰(双子)木星中→凶;卡罗(狮子)月亮凶→中;齐达内(金牛)太阳中→吉、火星凶→中、金星吉→凶;梦露、布什(巨蟹)不变。
- Python:全量跑过,功能吉凶相关测试(mcp strict 系列、consumer context、report parity、active rectification 等)没有新失败(见门禁)。pyjhora / oracle 测试的失败都在基线名单里。
- 前端改动的断言:`consult-card-affliction-data-20261001.test.ts` 乔布斯父亲代表星太阳 原值 `malefic` / 新值 `neutral` / 原因:v2 只管 12 宫的星不自动判凶(三栏写在测试注释)。
- 新增 `frontend/tests/consult-upstream-functional-v2-20261002.test.ts`:12 份 golden 的 profile、泰勒(天蝎)与乔布斯(处女)卡上分组。
## T3 第四轮残留
| 项 | 查到的原因 | 改动 |
| --- | --- | --- |
| a 事业 9/18「不是站台式 / 往深处做」(BUG-1176) | 规则说了「不断定公众 / 幕后」,但没点名 A10 / AL / 太阳 / 10 宫主落 4、6、8、12 宫这类读法本身就是在下类型结论 | `CAREER_FIELD_ASK_RULE` 加一句:这些落宫只说阻力或代价(要经手、要绕路、来得晚),不翻成「不在台前」「不在台面上」「不靠曝光」「幕后」「不是站台式」「往深处做」,也不把落宫翻成行业 |
| b 梦露 ×2 / 琵雅芙 ×1 母亲「在管、在安排、近」(BUG-1182) | 卡上没有解读性文字;**系统提示三处示例把「4 宫主落 10 宫」配成「母亲的注意力在你的前途上 / 离你近、上心」,梦露盘 4 宫主正落 10 宫**;`AFFLICTION_RANGE_RULE` 只禁安慰词,不禁拿宫主落宫 / 宫内吉星描写人物行为,也不管行动建议 | `AFFLICTION_RANGE_RULE` 加「不拿宫主落哪一宫、宫里有吉星去描写这个人对你做什么……行动建议也不写给他打电话、去问他」;三处示例括号写明「母亲这条线没有受冲」 |
| c 禁句 1(琵雅芙健康「逆行 → 拖出来」) | 通用读法只写「逆行不等于反复、打回来」 | 改为「也不等于拖得久、拖出来,推论里不拿逆行当理由(依据里可以列)」 |
| c 三份两处请求 | `AFFLICTION_RANGE_RULE` 要「这一段末尾」问,和事业段末那一问叠加 | 加「问过之后别的段落不再另问」 |
改动的既有断言:`consult-no-presupposition-20261001.test.ts` `AFFLICTION_RANGE_TEXT`(原值:止于「全篇这类请求最多一处。」/ 新值:加上面两句 / 原因:BUG-1182)与是非题例正则(原值 `/不是。(4 宫主落 10 宫)…/` / 新值 `/不是。(母亲这条线没有受冲;4 宫主落 10 宫)…/`);`consultation-voice-contract.test.ts` 父母例与是非题例两处(同上,三栏在注释)。`frontend/docs/VOICE.md` 同步(不揣测、§7 ③、§8、示例一节、对照表两行)。
回测脚本 `consult-biography-backtest.mts`:`--correction-domain` 支持逗号分隔多个领域,`--correction` / `--correction-texts` 支持 `领域:名人` 写法,一次跑完父母纠正与事业追问。
## T4 第五轮回测
详表见 `docs/testing/consult-affliction-backtest-20261001.md`「改动后(第五轮)」。key 只从环境变量读,没有写入文件、日志或提交;模型输出在 `scratch/consult-biography-backtest/round5-20261002/`(gitignore)。
| 通过线 | 第四轮 | 第五轮 | 达到 |
| --- | --- | --- | --- |
| 事业行业 / 类型与生平冲突 ≤ 1 / 18 | 9 / 18 | **5 / 18** | 否 |
| 事业段末问一句 ≥ 16 / 18 | 18 / 18 | **17 / 18** | 是 |
| 严重冲突 ≤ 5 / 72 | 12 / 72 | **5 / 72**(全在事业;父母 3 → 0) | 是(压线) |
| 对照组严重误报 0 | 0 | **0** | 是 |
| 对照组轻度误报 ≤ 2 | 3 | **4** | 否 |
| 禁句 0 | 1 | **0** | 是 |
| 每份只问一次 | 3 份两处 | **72 / 72 一处** | 是 |
追问:父母纠正 8 / 8、事业追问 6 / 6。未达的两项见测试文档「读出来的东西(第五轮)」:事业剩下的是同义词逃逸(「不靠场面」「不是一阵热闹」),对照组轻度误报是把「迹象」写成一句现实结论,交产品决定下一步(建议方向写在测试文档)。
## 门禁
| 项 | 基线(`57782aea` 一次性 worktree) | 本分支 |
| --- | --- | --- |
| `tsc --noEmit` | — | 0 错 |
| `npm run lint` | — | 0 error / 126 warning |
| `npm test`(Node 22) | 4,911 项:pass 4,846 / fail 24 / cancelled 0 / skip 41 | 4,921 项:pass 4,856 / fail 24 / cancelled 0 / skip 41;失败名单逐条同名(都是需要 Docker / PostgreSQL / 部署环境的套件) |
| `npm run test:db`(本机 PG17 替身) | 80:74 过 / 6 败 | 80:74 过 / 6 败,名单相同 |
| `next build` | `/` ○ Static | `/` ○ Static |
| 首屏 gzip(预渲染 `index.html` 引用的 32 个 `/_next/` 资源 gzip-9 求和,同法实测) | 635,351 B | 635,380 B(+0.005%) |
| Python 全量(`pytest tests -n 6`) | 67 项失败(`f8579466` 基线名单;`57782aea` 只多出 8 项记忆化失败) | 62 项失败,全部在基线名单内、新增 0;记忆化 8 项转绿;另有 5 项 prashna 研究测试转绿,与本单无关(工作树里 4 个 `references/oracle/prashna_*` 文件开工前已被改写,见下) |
| 快速门 `run_quality_gate.py --profile quick`(系统 python3 + Node 22) | — | pytest 1,043 passed / 1 skipped;门内 `npm test` 4,921 项 fail 24,名单与基线同名;门禁总状态因这 24 项环境失败为 failed(与上一单相同) |
环境:`frontend/node_modules` 用硬链接拷贝(`cp -al`),未提交。工作树里 `references/oracle/prashna_*_2026_07_20.json` 四个文件开工前就是已修改状态(来源不明,疑为别的测试运行改写),本单未提交。一次性基线 worktree `.worktrees/tmp-base-57782aea-20261002` 用完删除。
## 提交
`codex/consult-upstream-functional-v2-20261002`(未 push):`3733b978`(BUG-1181 算法身份、日期窗代数判断、迁移、记忆化 golden v2、研究记录重新冻结)、`3a40d422`(BUG-1180 回归测试)、`7806c72f`(普通对话 golden、第四轮残留规则、回测脚本)、`dae2b99f`(确认门测试读新冻结报告)及本文档提交。