Files
Jyotisha/docs/tasks/PROGRESS-upstream-sync5-20261002.md
T

149 lines
18 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 · 上游同步第五轮 + 生时校正 4 件 3 域(2026-10-02)
- 任务书:`docs/tasks/TASK-upstream-sync5-20261002.md`(`origin/staging` `677d40f9`)。
- 执行方式:产品授权直接执行。Claude(PM)先在本会话移植上游代码(U2–U8 各一或两个提交);子代理完成 U8 后续、R1、测试修复、记忆化 golden、研究记录重新冻结、评测、golden、回测与记录。只 commit,未 push。
- 分支 / worktree:`codex/upstream-sync5-20261002` / `.worktrees/upstream-sync5-20261002`,基线 `677d40f9`(代码同已部署 `3d0c3cdf`)。
- 上游参照:`/workspace/yinduzhanxing` `origin/main` `c593354f`(只读;未从上游复制文案,本地 ref 未改)。
- BUG 编号:开工核对 `origin/staging` 最大号 BUG-1191;本单 BUG-1192~1198(提交前再核对,未被占用)。
## 提交
| 提交 | 项 | 内容 | BUG |
| --- | --- | --- | --- |
| `cb9d942b`(PM) | U2 | 8 星制 Chara Karaka 罗睺按 30° 减度数排位(上游 `197672e3`) | 1194 |
| `bdbff99a`(PM) | U3 | 五大人格燃烧顺 / 逆行表(上游 `eaf6918b`) | 1195 |
| `533c3a30`、`9959e514`(PM) | U6 | 诅咒格 / Rashi Tulya 健康措辞 + 测试(上游 `b40c7fde`、`28f41912`) | 1197 |
| `765ff66c`(PM) | U8 | Badhaka 12 上升测试(上游 `6abfe983`) | 1192 |
| `cf78d4ca`(PM) | U3 | 全引擎燃烧表统一到 `COMBUSTION_ORBS` / `is_combust`,含月亮、逆行与普通对话层(上游 `080c286c`,改编) | 1195 |
| `5172620c`(PM) | U5 | Yogini 按月宿起运(上游 `cb7fe017`) | 1196 |
| `45d6dbf6`(PM) | U7 | 水星燃烧时 Budha-Aditya 降为有条件(上游 `994638f0` 只取此段) | 1198 |
| `54f6930b`、`67aa1b33`(PM) | U4 | 三方净化、单宫主净化(上游 `9531d1dc`、`868f1dad`) | — |
| `7fb165ec` | U8 后续 | 诅咒格 Badhaka 宫按上升取 11/9/7、删早夭 / 早逝措辞 | 1192 |
| `758fee95` | R1 | 生时校正交付门槛 4 件 3 域;政策 v4;记忆化 golden v3;30 个前端测试文件 + 4 个 Python 测试 | 1193 |
| `1029cbaa` | R1 / ERR-110 | 研究记录重新冻结(标签 `upstream_sync5_2026_10_02`) | 1193 |
| `917e18a0` | — | 普通对话回测 golden 重生成 | — |
| `03d60e29` | U3 后续 | 两张燃烧表相等测试 | 1195 |
| `90dcafe7` | R1 后续 | 隐私扫描按行号钉的两处碰撞保持原行 | 1193 |
| (本提交) | — | 记录:BUG 历史、CHANGELOG、本文件、任务索引、回测第七轮 | — |
## 逐项
### U1 Narayana 默认版本 —— **不搬**(产品延后)
上游 `acdc3551` 只改了 `scripts/cmd_narayana_dasha.py` 一行:`variant_profile` 默认值 `legacy_local` → `kn_rao`。本仓的 `cmd_narayana_dasha.py` 根本没有 `variant_profile` 开关(上游更早加入的 K.N. Rao profile 本仓未同步),生时校正(`event_probes`、`active_rectification_event_engine`)直接调 `narayana_dasha.calc_narayana_mahadasha` 等函数,也不经过这个命令入口;要「默认 K.N. Rao」得先整体移植 profile 机制,不是一行默认值;而「产品是否改用 K.N. Rao 版本」是占星师待裁决项(乙表),改函数默认会同时改生时校正打分。本轮不移植,留待占星师确认后单独立单(需过 v5 评测与历史可打开核对)。
### U2 Chara Karaka 罗睺(BUG-1194)
PM 移植。生时校正只用 `jaimini.calc_arudha_padas`,不读 Karaka;77 例 A/B 分数相同。
### U3 燃烧(BUG-1195)
- PM 移植两提交。全引擎现在两张表:`jyotish_engine.COMBUSTION_ORBS`(全读、普通对话 graha drishti 层)与 `pancha_mahapurusha.COMBUSTION_ORB`(上游形状)。数值相同;`03d60e29` 加测试锁两表相等,并在每个容许度边界验证两个函数。`scripts/validate_yoga_accuracy.py` 另有一张简化表(只顺行),是离线校验脚本,不在产品路径,未改。
- 普通对话卡上的变化:9 位回测名人中只有齐达内一颗逆行金星由燃烧改为不燃烧。
### U4 八分法净化 —— 函数已加,未接入输出
上游只新增 `calc_trikona_shodhana` / `calc_ekadhipatya_shodhana`(上游仓内也没有调用方)。本仓同样不接入报告、数据卡与生时校正,SAV 原值不变;函数可供后续调用。`scripts/ashtakavarga.py` 在生时校正冻结身份里,字节变化按 ERR-110 重新冻结。
### U5 Yogini(BUG-1196)、U6 诅咒格措辞(BUG-1197)、U7 Budha-Aditya(BUG-1198)
PM 移植;测试见各提交。U5 上游对本仓不存在的测试文件的改动未带;U7 上游同一 hunk 里其它卡片闸门字段来自别的提交,未带。
### U8 Badhaka(BUG-1192)
- 核对:本仓两处 Badhaka。`yoga_engine.YogaContext.is_badhaka` 已按动 / 定 / 变取 11 / 9 / 7(上游测试 `765ff66c` 通过);`curse_yoga_detector` 亡灵格(Preta Yoga 两条)加重宫位写死 `[8, 11, 6]`、注释「11宫=Badhaka」—— 记忆里说的「写死 11 并输出过早死亡风险」就是这里(「过早死亡风险」已由 U6 去掉)。
- 修复:`yoga_engine.badhaka_house()` 成为唯一定义,`is_badhaka` 与诅咒格都调它;Preta 两条的加重宫位改为按上升展开(D9 检测用 D9 上升;上升未知时 Badhaka 宫不参与加重,原 `is_badhaka` 对未知上升返回 7 宫,现在返回 False)。
- 死亡措辞 grep:`rg "过早死亡|死亡风险|早夭|早逝|夭折|血脉.*(中断|停止)|死亡之神" scripts references/*.json` 后剩余:诅咒格「家族影响」两条(子女早夭、家族血脉停止)→ 改为责任 / 传承主题;`references/yoga_rules.json` 母亲不利格效果「母亲早逝 / Early loss of mother」→ 删除。剩余命中只在 `scripts/misconceptions.py`、`scripts/case_validator.py`(李小龙案例笔记,供内部案例校验,不进用户输出)与 `references/*.md` 讲稿资料。前端两份报告阅读 fixture(`report-reader-main-fictional*.json`)是历史引擎输出,仍含「母亲早逝」,未重采(不影响线上)。
- 测试:`tests/test_curse_yoga_badhaka_house.py`(12 个上升、未知上升、源码与实际输出正则扫描)。
### R1 生时校正 4 件 3 域(BUG-1193)
**门槛位置(改前 → 改后)**
| 位置 | 改前 | 改后 |
| --- | --- | --- |
| `references/rectification_policy.v1.json` `minConfirmationEvents / minConfirmationDomains` | 4 / 3(只被确认门读) | 不变,成为唯一定义 |
| `frontend/src/lib/rectification-agentic/core/types.ts` `MIN_TRAINING_EVENTS = 3`(收敛判定,只数训练件) | 3 件 | 删除;新 `MIN_DATED_EVENTS / MIN_DATED_DOMAINS` 读政策文件;收敛判定数训练 + 留出,并加领域条件 |
| `core/rectification-decision.ts` `MIN_STANDALONE_DATED_EVENTS / DOMAINS`(区间交付门、出牌前「继续采集」) | 3 / 2 | = `MIN_DATED_*`(4 / 3) |
| `v9/evidence-model.ts` `MIN_ACCEPTANCE_EVENTS / DOMAINS` + `trainingScoreableGate`(训练门:何时开始出选择题、出卡) | 3 / 2,只数训练件 | = `MIN_DATED_*`,数训练 + 留出的全部带日期主经历 |
| `v9/decision-from-dossier.ts` 推断后 `trainingGateOpen` | 训练件 3 / 2 | 训练 + 留出 4 / 3 |
| `scripts/rectification/decision_policy.py` `MIN_ACCEPTANCE_EVENTS / DOMAINS`(回执 `event_quality` / `domain_diversity`,决定 `acceptance_allowed` / `selection_allowed`) | 3 / 2,只数训练件 | = `MIN_CONFIRMATION_*`(政策文件),数全部可计分经历;`POLICY_VERSION` v3 → v4 |
| 其它(未改,含义不同) | `case_holdout.py` / `split-holdout.ts` 第 4 件起留出 1 件;`candidate_contrast.MIN_DISCRIMINATOR_*`(区分题供给);研究脚本 `holdout_v5_build` 7 件 4 域(数据集入选标准);`minute_rectification_holdout_validator` 每例 3 件(固定协议) | — |
- **计数口径**:产品口径「至少 4 件事」按用户给出的带日期主经历算,包括被留作 holdout 的那一件(留出规则不变:第 4 件起留 1 件)。若改成只数训练件,用户要说 5 件才够。
- **遗留(待产品)**:留出规则优先把只有一件的领域留作 holdout,刚好 4 件 3 域时,实际参与打分的常是 2 个领域 3 件事。要不要改成「训练件也要 3 个领域」(等于要 5 件以上),请产品定。
- **打分不变**:77 例 v5 用 `score_candidates`(±10,分钟步长 2,冻结日期)A/B 逐分相同;记忆化 fixture 分数与 v2 golden 相同,只有回执变(`policy_version` v4、`event_quality.minimum` 3 → 4、`domain_diversity.minimum` 2 → 3 且 2 域不再通过、代表候选 UUID 随 policy 命名空间变、`feature_hash` 随 ERR-111 变)。按 BUG-1181 先例「同输入出不同分才升算法版本」,**不升 `rectification-v5-matrix-scoring-11`**;`ALGORITHM_VERSION` 仍 scoring-10,policy 身份 v4。记忆化 golden 按先例由 `write_golden` 写 v3,v2 冻结并按 sha256 钉住(新测试断言 v2 / v3 分数相同、只回执 policy 变)。
- **历史 Case 能否打开(BUG-621)**:算法版本与 Skill 版本都没变;policy 版本只参与「缓存分数是否可复用」与候选 UUID,旧结果按存储的身份只读打开、重新比较时按 v4 算。前端 `rectification-history-open` / `engine-version-cross-midnight` / `dated-algorithm-generation` 等测试全过(npm test 失败名单与基线相同)。未做浏览器级验证。
- **采集文案**:`preciseGapNarration` 不再一律「再来一件……就能开始筛」,按缺口写「再来两件记得大概年月的事,其中至少一件不是上学或工作的,就能开始筛」「再来四件……、至少涉及三个方面,就能开始筛」,只差一件时仍是「再来一件……」。保留「就能开始筛」字样(多处合同测试按它识别缺口句)。`VOICE.md` 第 293 行同步。`user-copy.ts` 的 `insufficientEventsGate` / `insufficientDomainsGate`(「再来一件……」)只被 `acceptanceGateNarration` 用,而该函数在 `answer-choice.ts` 只 import 未调用,未改(死代码,记一笔)。遗留表单 `components/birth-time-life-events.tsx`(无引用方)文案与校验同步为 4 条、3 个领域。Skill 文本里没有写 3 件 2 域(只有「propose_allowed 需要可评分事件≥4、领域≥3」),Skill 版本不变。
- **采集流程**:训练门(`trainingScoreableGate`)同时决定「继续口述采集」与「开始出选择题 / 出卡」,门槛抬到 4 / 3 后,采集线会一直问到 4 件 3 域(原 3 件 2 域就转选择题)。BUG-1048 是出题闸门最小间隔问题,与件数无关;BUG-647 的「holdout 不饿死训练」不变(4 件时训练仍 3 件)。
**测试三栏(摘要;逐条注释写在测试里)**
| 文件 | 用例 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- | --- |
| `rectification-convergence-budget` | insufficient standalone evidence keeps collecting | {2/2}→dated、{3/1}→domains | {3/3}→dated、{4/2}→domains | R1 门槛下方各取一格 |
| 同上 | standalone delivery floor(改名 shares the 4/3 policy…) | 3、2 | 4、3 且与政策同源 | R1 单一定义 |
| 同上 | dossier wiring | 3 条 career → insufficient_domains | 3 career + 1 relationship → insufficient_domains | 3 件会先落 insufficient_dated_events |
| `rectification-decide-next-action` | discrimination waits for…(改名 four dated events across three domains) | three.open=true、3 件出区分题 | false、继续采集;新增 4 件 2 域门关 | R1 |
| `rectification-decision-authority` | invariant 2 | 事件 [0,2,3] × 领域 [0,1,2] | 事件 [0,2,3,4] × 领域 [0,1,2,3],3 件 2 域也必须挡 | R1(测试更严) |
| `rectification-eight-method` | three dated events with one holdout… | holdoutCount=0 | 1(补第 4 件,训练仍 3) | R1 |
| `rectification-occupation-dated-answer` | raises the training gate by one career event | 训练 2 → 3 | 训练 + 留出 = 改前 + 1,holdout=1 | R1 按训练 + 留出计 |
| `rectification-probe-pool-exhausted` | T4 标题 | 「对照了 4 件经历」 | 「对照了 5 件经历」 | 夹具多一件第 3 域经历 |
| `rectification-collect-stall` | revision 5… | holdout `e-rel-start` | holdout `e-finance`、`e-rel-start` 断言为训练 | 夹具补第 3 域后单件域被留出 |
| `rectification-block-scan` | 题名 three dated events in two domains… | — | four dated events in three domains(断言不变) | R1 |
| `tests/test_rectification_confirmation_and.py` | four events two domains(改名 neither selects nor proposes) | selection_allowed=True | False,`domain_diversity` 不过、minimum 3 | R1 |
| `tests/test_rectification_relative_support.py`、`test_rectification_v5_services.py` | policy 版本 | v3 | v4 | R1 |
| `tests/test_rectification_engine_memoization.py` | 当前 golden | v2 | v3(v2 冻结 + 分数相等测试) | R1 回执变 |
其余 23 个前端文件只改夹具(补第 4 件 / 第 3 域,保持原场景),每处带「R1(BUG-1193)」注释;没有删断言。
## 生时校正评测(v5 77 例)
- `python3 scripts/research/holdout_v5_baseline.py --dataset v5 --out-dir <dir>`,改前在 `origin/staging` `677d40f9` 一次性 worktree、改后在本分支 `917e18a0` 一次性 worktree(引擎与 R1 全部改动之后)各跑一次:sweep / cluster_width / futile_collect 三段 JSON 逐字节相同(只差耗时),数字与第四轮 `a18f8d4e` 相同。
| 指标(v5 77 例) | ±10 | ±30 | ±60 |
| --- | --- | --- | --- |
| 先验头名 前 / 后 | 0.1818 / 0.1818 | 0.0909 / 0.0909 | 0.0779 / 0.0779 |
| 六题回放头名 前 / 后 | 0.6364 / 0.6364 | 0.4935 / 0.4935 | 0.3117 / 0.3117 |
| 线上区间回放头名 前 / 后 | 0.6623 / 0.6623 | 0.5584 / 0.5584 | 0.4026 / 0.4026 |
| 覆盖 前 / 后 | 0.987 / 0.987 | 0.987 / 0.987 | 0.987 / 0.987 |
| 中位宽度(线上回放)前 / 后 | 13 / 13 | 33 / 33 | 65 / 65 |
红线(任一格下降 > 1 pp)未触发。
- **R1 对交付的影响**:评测按每例全部经历打分,不经过交付门,所以数字不随 R1 变。按数据集本身核算:77 例每例都有 ≥ 7 件、≥ 4 个领域的主经历,**给全经历时 0 / 77 被 4 件 3 域挡住**。若按经历发生先后逐件说出:旧门槛 3 件 2 域中位在第 3 件达到,新门槛中位在第 4 件;55 例只需多说 1 件,12 例多 2 件,2 例多 3 件,8 例要多 4–7 件(前几件集中在一两个领域,第 3 个领域出现得晚)。
- 另:77 例 `score_candidates` A/B(±10、冻结日期)逐分相同;reported offset 900 例 0 例变化、sealed holdout 20 例逐条相同(见重新冻结提交)。
## 普通对话 golden 与回测
- `consult-evidence-card-golden.json`、`consult-biography-backtest-golden.json` 用 capture 脚本各跑两次(`PYTHONHASHSEED=0`、缓存 TTL 0),逐字节相同。证据卡 golden 与提交版相同;回测 golden 只有齐达内逆行金星不再燃烧(graha drishti 四条路由各一处)。
- 名人回测第七轮:`docs/testing/consult-affliction-backtest-20261001.md`「改动后(第七轮,上游同步五)」。72 + 14 份全部读完。事业类型冲突 9 → 13 / 18(8 位名人卡未变,属模型波动);父母严重冲突 0、禁句 0、纠正追问 8 / 8、事业追问 6 / 6;对照组轻度误报 6 → 8、读反 2 → 5(都在健康开场)、1 份全篇两处请求。
## 门禁
| 项 | 结果 |
| --- | --- |
| ruff(门禁清单 5 个文件)、`py_compile scripts/*.py jyotish_vedic/*.py mcp_server.py` | 通过 |
| `run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime` | failures [],exit 0(1,046 passed、1 skipped;在含记录的提交上跑) |
| 隐私扫描 `tests/test_repo_privacy_markers.py` | 通过(R1 改测试时一度把按行号钉住的两处碰撞挤下一行,`90dcafe7` 修回) |
| Python 全量(`pytest tests -n 4`) | 63 个失败,全部在开工基线 67 个之内;基线里 5 个(prashna 系列,依赖本机文件)本次通过。新增失败 0 |
| `tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error(126 warnings) |
| `npm test`(Node 22) | 4,921 项,fail 24、cancelled 0;失败名单与同机 `origin/staging` 基线逐条相同(基线另有 1 条答题钟计时用例偶发失败);名字表只少 3 个改名用例(新名字都在) |
| `next build --webpack` | `/` 仍 `○ Static`;首屏 gzip 607,159 B,基线 607,110 B(+49 B,+0.008%) |
| 数据库套件 | 未跑(无 Docker;本单不改表结构、无迁移) |
## 上游未搬 / 不在本单
- U1 Narayana 默认(见上)。
- 任务书 §2.3 不搬:上游生时校正显式权重 / 行运锚点 / 双轨门、五大人格规则 profile、父母 / 事业盲测与现实校准合同。
- U7 同一 hunk 里上游其它卡片闸门字段(来自别的提交)。
- U4 两个函数不接入任何输出(上游同样未接)。
## 遗留 / 待产品
1. R1 计数口径:刚好 4 件 3 域时打分常只用 2 域 3 件(holdout 留走单件域)。是否要求训练件也 3 域。
2. `acceptanceGateNarration`(`user-copy.ts`)只 import 未调用,`insufficientEventsGate` / `insufficientDomainsGate` 两句仍写「再来一件」,属死代码;按「多余入口宁可删」可另开小单删除。
3. `report-reader-main-fictional*.json` 两份前端 fixture 是历史引擎输出,仍含「母亲早逝」;下次重采报告 fixture 时自然消失。
4. 名人回测事业类型冲突仍远高于通过线(13 / 18),需提示词或卡片单处理。
5. 真机:部署后在 staging 新建一次校正,只说 3 件(2 个方面),确认不出时间卡且提示写「还差……」;补到 4 件 3 个方面后出选择题 / 卡。历史校正记录能从列表打开。