From b900dff5c2ee8c76f1ce10c01a96794154742917 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Nov 2026 21:01:22 +0800 Subject: [PATCH 1/3] docs(tasks): brief for #217 reading-runtime-sources Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DbBXozsiu43ob7B8UZCmDM --- .../TASK-reading-runtime-sources-20261112.md | 115 ++++++++++++ ...ef-astrologer-acceptance-reply-20261112.md | 169 ++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 docs/tasks/TASK-reading-runtime-sources-20261112.md create mode 100644 docs/tasks/ref-astrologer-acceptance-reply-20261112.md diff --git a/docs/tasks/TASK-reading-runtime-sources-20261112.md b/docs/tasks/TASK-reading-runtime-sources-20261112.md new file mode 100644 index 00000000..930d3f7d --- /dev/null +++ b/docs/tasks/TASK-reading-runtime-sources-20261112.md @@ -0,0 +1,115 @@ +# TASK:报告解读运行时口径:废止旧成功率与旧 ABC 口径,拆分功能吉凶 profile,附录如实列核验行(2026-11-12) + +- Gitea:#217 +- 分支:`codex/reading-runtime-sources-20261112`,基于 staging `1ba0364a7a8c0f964c3e21c21cb304aaa1899375` +- Bug 编号:BUG-1861 +- 验收:Claude(jyotisha-e6) + +不得自行写「产品决定/裁定」。任务书没写到的取舍,一律选「需拍板」。 + +不得修改或删除既有断言来让测试通过。确需修改的,在 PROGRESS 里逐条写明原值、新值和原因。 + +占星师的引擎和资料(`scripts/jyotish_engine.py`、`scripts/yoga_engine.py`、`references/` 下她仓库已有的文件、`SKILL.md`)一律不改。产品差异只能放进单独的产品文件,并在 `references/product_runtime_contract.md` 公告(项目规则 2026-11-07)。 + +占星师回复原文:`docs/tasks/ref-astrologer-acceptance-reply-20261112.md`,由本分支第一个提交带入。下文的「她 §N」都指这份文件。 + +本任务**允许**修改 `references/product_runtime_contract.md`(产品文件),但只能改下文点名的地方。 + +## 背景 + +### A. 旧提示原文仍有运行效力(她 §4 末条) + +报告解读的系统提示由 `frontend/src/mastra/report-reading-skill.ts` 拼成:`SKILL.md` 加上 `REPORT_READING_REFERENCES` 里列的文件,最后加产品合同的 report-reading 块。 + +其中 `references/precision-reading-methodology.md`「三、九层复合方法」写有「做到第六层,平均85%的预测成功率」,另外好几处还用着旧的 A/B/C 置信度口径,例如: + +- `strict-workflow-router.md` 的 `Confidence label: A/B/C/insufficient` 和 `A/B/C/fail` +- `precision-reading-methodology.md` 的 `置信度:[A/B/C]` + +她要求保留原文以便追溯,但必须明确废止它们在运行时的效力,不能只靠末尾的新合同去隐式覆盖。没有验证设计、分母和适用范围,就不得向用户宣称准确率。 + +### B. 功能吉凶 profile 混用(她 §4) + +- 事实包 `functional.functional_profile` 选的是 `pvr_table30_v1`。 +- 提示里加载的 `references/functional-role-profile.md` 是**我们改过的** BPHS 表(`bphs_ch34_general_with_sign_exceptions_v3_166q4`)。它与她 `8aaf6099` 的同名文件有几处不同: + - 双子、处女上升的土星 mixed 两行; + - 34.20、34.35 两处注释; + - 她的「Revision v3」整段被换成了我们的 #163 说明。 +- 她的裁定: + - 按已选的 profile(PVR)给结论。 + - BPHS 修订作为另一个具名、带版本的 profile,附来源定位、完整差异和十二上升测试,另行送审。 + - 不接受「只有两个词差异」这种笼统说明。 + +### C. 核验行在附录里如实显示(她 §4,产品 2026-11-12 决定) + +她要求真实案例与 MEVG 的状态保留在用户可读的证据附录里。产品 2026-11-12 的决定如下: + +- **个人报告**里可折叠的「计算依据」附录如实列两行:「网上资料核对:未完成」「真实案例校准:未完成」,按实际状态写。 +- 正文和聊天回答照旧不提(BUG-1794 对正文仍然有效)。 +- 这属于 BUG-1794 在**附录**范围的部分回撤,要在产品合同里写明。 +- 年运报告的附录由 #210/#212 负责,本任务不管。 + +## 要改的文件 + +- `references/product_runtime_contract.md`: + - report-reading 块之前的 G 节公告区:新增「运行时废止」一段和「功能吉凶 profile」一段; + - BUG-1794 的两处注释(第 14、128 行附近):各追加一句附录例外,并写原值、新值和原因。 + - 其他段落一律不动。 +- `references/functional-role-profile.md`:恢复为她 `8aaf6099` 的原文,逐字节一致。原文见 `/workspace/yinduzhanxing`,用 `git -C /workspace/yinduzhanxing show 8aaf6099:references/functional-role-profile.md` 取得。 +- 新建 `references/product_functional_profile_bphs_v3_166q4.md`:我们当前的版本,加上文件头和差异表(见下)。 +- `scripts/functional_benefics.py`:`profile_source` 和 `rule_reference` 两处字符串指向新文件,只改字符串。 +- 「计算依据」附录的生成代码:自己定位,先看 `frontend/src/lib/report-toc-groups.ts`、`frontend/src/components/personal-report/`、`scripts/report_render/audit_chapters.py`;在 PROGRESS 写明改的是哪里。 +- 新建 `tests/test_functional_profile_split_20261112.py` +- 新建 `frontend/tests/report-reading-runtime-sources-20261112.test.ts` +- `frontend/tests/report-no-web-wording-20261109.test.ts`:只在它对附录也断言「不出现」时才收窄到正文,并在 PROGRESS 写明原值、新值和原因。 +- `docs/BUG_HISTORY.md`:末尾追加一条 +- `docs/tasks/PROGRESS-reading-runtime-sources-20261112.md` + +## 要做的 + +1. **盘点。** 在 `SKILL.md` 和 `REPORT_READING_REFERENCES` 列出的每份文件里,找出所有准确率、成功率、命中率的数字说法,以及所有 A/B/C 置信度口径的位置。每处记下文件、标题、行号和原文片段,列进 PROGRESS。 + - SKILL.md「阶段零 A/B/C 入口路由」是路由分类,不是置信度,不算。其他类似情况也照此分辨,并写明理由。 +2. **废止段。** 在产品合同的 G 节公告区写「运行时废止」: + - 逐条点名第 1 步找到的位置,说明「保留原文以便追溯,运行时无效」。 + - 置信度只按 `report_evidence_grade_v1` 的 A–D 上限,不得向用户宣称任何准确率或成功率。 +3. **profile 段。** 在 G 节写明: + - 报告的功能吉凶以事实包 `functional.functional_profile`(目前是 `pvr_table30_v1`)为准; + - `references/functional-role-profile.md` 是她的 BPHS 原文,只作对照; + - 产品修订的 BPHS 表是 `references/product_functional_profile_bphs_v3_166q4.md`,状态为待她审核,不进报告结论。 +4. **新 profile 文件。** 文件头写清以下内容: + - profile id; + - 来源:她 11-05 #166 Q4 裁定、BUG-1570、BUG-1590; + - 与她 `8aaf6099` 版本的**完整**差异表,逐行列出新增、删除和改写,被替换掉的「Revision v3」段也要列。 +5. **测试。** + - Python 测试: + - `references/functional-role-profile.md` 的 sha256 等于她 `8aaf6099` 版本的 sha256(把期望值写死在测试里,并注明来源提交); + - 十二个上升都用 `functional_benefics` 的 BPHS profile 求土星分类,双子、处女是 mixed,其余十个上升的结果写死成期望值(期望值取自现有代码,写进 PROGRESS); + - 对 Jobs 和 Obama 两张公开盘调用报告事实包(方法参照 `tests/test_reading_facts_v3_20261112.py`),`functional.functional_profile == "pvr_table30_v1"`。 + - 前端测试: + - `buildReportReadingSystemPrompt`(以实际函数名为准)的输出里,含有新的废止段和 profile 段; + - 附录渲染出「网上资料核对」「真实案例校准」两行,状态为「未完成」; + - 正文区域(解读的九节)仍然不出现这两个词。 +6. **附录两行。** + - 状态取自现有后台记录(回执或审计里的 MEVG / Real Case 行)。没有记录就写「未完成」,不得写成「已完成」或「通过」。 + - 行名用中文:「网上资料核对」「真实案例校准」。附录里不出现「MEVG」字样。 + +## 不要碰 + +- `frontend/src/lib/personal-report-reading.ts`(#207 和 BUG-1860 在改) +- `scripts/report_render/evidence_grade.py`、`reading_facts.py` +- 聊天的提示和回答 +- 冻结文件 +- 她的其他 references 文件(只恢复 `functional-role-profile.md` 这一份) + +## 自测命令 + +``` +python3 -m pytest -q tests/test_functional_profile_split_20261112.py tests/test_functional_yogakaraka_kendra_trikona.py tests/test_reading_facts_v3_20261112.py +python3 scripts/run_quality_gate.py --profile quick --skip-frontend-runtime +cd frontend && npx tsx --test tests/report-reading-runtime-sources-20261112.test.ts tests/report-no-web-wording-20261109.test.ts tests/report-reading-20261027.test.tsx && npx tsc --noEmit -p . && npx eslint . +``` + +## 何时停下来选「需拍板」 + +- 恢复她的 `functional-role-profile.md` 之后,聊天、生时纠正或盘面页的测试失败。说明这些地方实际读的是我们改过的表,先停下来报告。 +- 找不到「计算依据」附录的单一生成点,或者附录同时用于聊天。 diff --git a/docs/tasks/ref-astrologer-acceptance-reply-20261112.md b/docs/tasks/ref-astrologer-acceptance-reply-20261112.md new file mode 100644 index 00000000..0adfeede --- /dev/null +++ b/docs/tasks/ref-astrologer-acceptance-reply-20261112.md @@ -0,0 +1,169 @@ +# 报告解读层验收回复与年运七项裁定 + +日期:2026-11-12。对象:网站开发人员。 + +**结论:本轮可以确认部分交付结构已经改进,但报告解读层尚不能整体验收通过。年运七项问题已在下文给出实施口径,不必等待模板补齐才开工。** + +本次是提交材料与资料源的工程、语义合同审核,不是重新为样例人物解盘。没有访问网站服务器,没有运行网站代码,也没有验证部署。资料源基线为 `8aaf60991c32a84ac30d6d7b6a62c4f166507bce`;网站构建 `1ba0364a7a8c0f964c3e21c21cb304aaa1899375` 是来件声明,不能视为本仓已复现。 + +## 1. 审查对象与可复查入口 + +- `报告解读层-验收材料-请占星师审核-1112.md` +- `报告解读层-验收材料-1112.zip`,SHA256:`8e9352fc59623778b51b6fd923670e82e9075530730d000b0650d8e5e588ae94` +- `年运报告-请占星师裁定-1112.md` +- 上轮合同:`handoff/2026-11-12/preset_q3/README.md` +- 区间合同:`handoff/2026-11-09/interval_rectification/README.md` +- 年盘来源边界:`skills/tajika-annual/SKILL.md` 及其 usage/research 引用;`docs/research/tajika_source_adjudication_2026_11_06.md`。 + +同目录 `review_packet.py` 只读取 ZIP,不解压、不执行来件程序;使用 `python3 review_packet.py <验收ZIP绝对路径>` 可重新取得成员哈希、状态矛盾、段落标签与字面命中。它不是网站回归测试,也不自动判断整段占星语义正确。 + +### 已确认与尚不能确认 + +| 项目 | 本轮结论 | +|---|---| +| 提交 facts/caps/草稿/落库/成稿/提示词 | 已提供,可追踪部分处理阶段 | +| caps 与 facts 内 evidence_grades | A、B 均一致 | +| 提示词长度 | 92,392 个 Unicode 字符;长度不代表有效调用 | +| 无适配案例不升到 A/B | 样稿采取 C 上限,方向正确;不等于 C 内容都正确 | +| 技法未进路由与仓内不存在分开 | 方向正确;仍需说明相关技法为何未执行 | +| 历史回放、分段 withheld | 已有结构;放行规则仍有漏洞 | +| 后端拦截器、产品 Badhaka 实现、自动测试 | ZIP 未提供相关代码,不能签署代码验收 | +| 真实案例、用途区间稳定性、完整端到端复现 | 尚未完成 | + +## 2. 必须先修复的发布阻断项 + +### P0-1:不能把一分钟阈值冒充用途区间稳定性 + +`facts-A/B.json → birth_precision.purpose_stability` 都是 `not_evaluated`。但 `caps-A.json → claims.*.ledger.purpose_stability` 八项都是 `stable`;B 有七项 `stable`,仅 health_pressure 为 `boundary_sensitive`。 + +实际依据是 `birth_record_minute_v1` 下,分盘最近边界与固定 `tolerance_minutes=1.0` 比较。它只能描述该规则下的局部边界检查,不能证明用户真实出生区间内的解盘与推运结论稳定。timing_window 更不能无精度依赖便标为稳定。 + +改法:保留原边界数值与旧算法标识;用途稳定性必须来自真实输入区间、相关分盘/派生点/应期边界、区间内结论差异的独立评估。未做则仍是 `not_evaluated`,不能用 minute_confirmed 替代。未评估不意味着整份报告一律 D:保留不依赖这些边界的事实与条件性解读;会跨界的判断须分支或暂缓确定结论。 + +### P0-2:分级必须覆盖实际判断,不能只覆盖六个栏目 + +overview/advice/basis 的段落允许缺少 claimType,实际却出现职业方向、能力、结果强弱等实质判断。A2 的事业第三段含时间窗口,仍标为 `career_promise`,没有绑定 timing_window 的依赖。 + +改法:每条实质判断绑定 claim ID、所用 fact ID、规则 ID 与所需依赖;混合段落拆开,或采用依赖并集及最严格适用上限。摘要和建议引用已审核 claim,继承等级,不能另开豁免通道。纯事实描述、一般性操作说明不强迫变成预测 claim,但不得夹带新推断。 + +高严谨事业 D10+A10、财富 D2/D11、婚恋 D9+UL 等最低要求应落实到适用判断与执行审计。仅放入 checked 列表,不等于已经建立该结论的完整依赖;也不能将无关技法变为所有句子的硬门槛。 + +### P0-3:生成时快照与验收快照没有闭环 + +来件说明草稿生成后又重建 facts,新增/修改 Badhaka 状态,未重新生成模型内容。即使位置数字相同,`pending_astrologer_review` 等状态也会改变解释权限。不能据此宣称同一 facts→caps→生成→校验→展示全链已通过。 + +每次尝试须绑定 input、facts、caps、system prompt、规则版本、原始回复、修复记录和最终成稿哈希;补交生成当时的 facts。对当前快照重新校验,必要时重生成受影响段落。A2 draft 与 stored 不相等,请附字段级转换记录;这本身不证明错误,但需解释转换。公开样例输入还应补齐完整坐标/时区解析参数,当前省略坐标无法独立重算。 + +## 3. 成稿已经存在的错误,不接受仅靠降为 C 处理 + +| 定位 | 问题 | 必须如何修正 | +|---|---|---| +| final-A-2 财富 | “水星掌管第五宫与第十宫” | facts 中 owns_houses 为 `[1,10]`;第五宫是所在宫。宫主与落宫分别绑定字段 | +| final-A-2 财富 | “SAV 总分为337”推出“不缺维持力” | 该标准总和用作校验,不能充当个体强弱。解释须引用相关宫位分布、方法与条件 | +| final-A-2 健康 | “Badhaka(阻碍星)落在第七宫双鱼座,主星木星在第十宫” | 分开 Badhaka sthana(宫位)与 Badhakesh(宫主星)。A 是第七宫为阻碍宫,木星在第十宫 | +| final-A-2 依据 | “没有满足定义的功能吉凶组合” | 空 Yogakaraka 结果不等于没有功能吉凶星;按实际字段限定陈述 | +| final-A-2 历史回放 | 仍有“若有实际问题应依现实就医评估” | 面向已故样例的当前建议应去除,改成历史解释边界 | +| final-B-1 健康 | “运动或炎症类风险”等具体现实风险 | 现有结构与待审 Badhaka 不能直接支撑该结论;删除无依据的结果断言,保留结构与待核验主题 | + +B 的 D8 边界约 0.25 分钟,但 health_obstruction 文本引用 D8,所需依赖却仅含 D1/Badhaka。必须按实际引用补依赖,不能让段落借用未纳入精度检查的证据。 + +“C 级”“仅供参考”不是事实错误、医学化推断或无来源结论的免责补丁。结构成立、传统解释、事件兑现三层必须分开。 + +## 4. 两项专项答复及审计修正 + +### 功能吉凶 profile:不要二选一混用 + +当前 facts 明确选的是 `pvr_table30_v1`。仓内该表将双子、处女上升的土星列为 neutral。产品在 BPHS 文档中新增的 mixed,和源文档的 BPHS 回退规则,都不能覆盖 PVR 结果。 + +按已选 profile 返回计算结论;BPHS 修订作为另一个具名、版本化 profile,附来源定位、完整差异与十二上升测试后另审。产品文档变化不止两条土星标签,不接受“只有两个词差异”的笼统说明。自然吉凶与功能吉凶仍保持独立。 + +### Badhaka:可以纳入,不能冒充已审定健康结论 + +健康路由最低清单未显式列 Badhaka,不表示不能用。它可作为相关补充层;一旦段落确实引用它,就成为该条判断的依赖,而非所有健康结论的统一发布门槛。 + +按所选规则,A 的 dual 上升取第七宫、宫主木星;B 的 movable 上升取第十一宫、宫主火星,提交的位置关系可与 facts 对照。但产品计算代码未提交,`product_computation_pending_astrologer_review` 不能改称引擎已验证,也不能由宫位直接推身体疾病。下一包提供实现、profile、十二上升单测、星体与宫位区分测试。 + +### 状态与可见审计 + +- **已经计算但未读用:execution_status=executed,interpretation_usage=not_used。** 不可将其改成计算未执行。annual 来件“未使用,不写已执行”的表述须纠正。 +- `blocked` 是缺输入/调用/验证等具体阻碍;未运行的相关可用技法不能靠 `not_in_domain_route` 自动免责;`not_applicable` 需要范围或适用条件理由。 +- 真实案例与 MEVG 状态必须在用户可读的证据附录保留,不能只留后台;没有完成就如实显示,不伪造通过。 +- “检测器检出,待核实”是合法状态说明;不能因含“检测器”就过滤。死亡预测禁令也不应误杀“不得预测死亡”等边界陈述。用语境与结论类型检查。 +- A1 的依据章被 withheld 时,必须有确定性生成的最小证据审计替代;不能保留行动性结论却把其证据限制整体隐藏。 +- 原提示资料含旧 ABC 口径与“平均85%的预测成功率”等表述。保留历史原文可追溯,但需显式废止其运行效力,不得靠末尾新合同隐式覆盖。没有验证设计、分母与适用范围,不得向用户宣称准确率。 + +## 5. 年运 Q1–Q7 正式回复 + +### Q1:选 (a),同一逐结论证据合同 + +年运采用 `report_evidence_grade_v1`,替换“全篇最高 B”。后端定上限、前端保留标签;没有适配案例最高 C,关键依赖缺失的结果性判断不能由 C 放行。独立一致性必须实际执行且适用,Narayana 未决候选不能充当第二套确定证据。年运不是另一套放宽标准。 + +### Q2:选带条件的 (a),正文比较表保留研究方法 + +Yoga Pravesha、Nakshatra Pravesha 纳入具名比较表,显示回归时刻、位置/年份参数、方法与条件状态;全部原始结构留附录。不要混成一个“最佳年度”。当前属于有来源边界的研究链路,不能仅因计算可运行升级为外部事件验证。 + +Satabdika 按所选方法的 Moon/Lagna/D9 等实际适用条件检查;满足才运行,不满足写 not_applicable 并给条件依据;缺输入则 blocked,不能强行补齐。固定天数年钟与 `pvr_jhora_360_tithi` 角度年钟必须分开,360 tithi 不能写成360个民用日,也不能偷偷用365.25替代。多候选保留独立结构,不多数投票。 + +### Q3:按主题映射实际执行;不是“未做也可以随意阻塞” + +以下为综合年运覆盖相关主题时的要求。专题年运仅执行问题相关项;适用条件失败可 not_applicable,缺真实输入/工具可 blocked。单纯尚未开发/运行,要明确未完成,不能签署完整验收。 + +| 技法 | 实施裁定 | 可阻塞/不适用的真实条件 | +|---|---|---| +| Double Transit | 做对应事件主题的窗口交叉检查 | 未冻结事件类或缺行运数据;不得心动、成对、成婚混用 | +| Chara Dasha | 综合年运相关主题执行,profile 具名 | 必需输入缺失;流派差异保留,不直接等于不适用 | +| Yogini | 相关应期执行 | 实际输入/计算受阻须注明 | +| Ashtottari | 先检条件,满足时执行 | 条件不满足为 not_applicable,条件未知为 blocked | +| Kalachakra | 相关应期执行,保留分支与精度敏感性 | 缺所需月宿/参数或实现无法运行 | +| Bhrigu Pada | 相关主题执行;补回提问表遗漏项 | 真正无该主题才不适用,来源未闭环仅限制解释强度 | +| Sudarshana | 相关年度主题执行 | 明确说明缺失输入或不相关范围 | +| KP | 涉及事件/细时窗时执行并保留独立参数 | 出生精度不支持时分支/阻塞精确结论;不伪造精度 | +| 西方核心 | 全谱跨体系年运中运行相关项并单列 | 明确约定“仅印度占星”的产品路由可不适用;不得为省事省略或混入印度术语 | + +这张表不是年运完整清单。仍需运行既有路线中的本命基础、功能吉凶、相关分盘、力量、Yoga、Dasha、Gochara,以及适用的 Varshaphala、年主、Muntha、Tajika、Saham、Panchavargiya/Harsha、Patyayini/Mudda、Varsha Narayana、月盘/Tithi 等层。先返回仓内当前能力审计清单,再逐项记录执行,不凭旧文档数量声称全量。 + +Tithi 出生地与现居地是不同位置假设:现居地未提供时若用出生地回退,必须披露,不能当成“两地独立印证”。Varsha Narayana 应使用年度入口与年度时间轴,不以本命 Narayana 改标题顶替。 + +### Q4:接受 (a) 的前台去总评,修正“只保留后台” + +取消“年度能量 A–D”和笼统每月吉凶栏。用有证据的生活主题、条件窗口、冲突和核验问题呈现,不强行编造具体事件。证据 A–D 与运势好坏不是同一个量纲。 + +原始计算、方法差异和必要限制仍应在用户可展开/导出的证据附录可见,不只后台可见。旧模板的主观总评分无须继续计算来满足版式。 + +### Q5:结果文案选 (c) 不直接移植;结构可复用 + +核查源代码:四个年主/Muntha/Munthesh相关主题字典各只有一条,但年度 Dasha 行星—宫位主题表有九对,不能笼统说全部各一条。它们是有限覆盖模板,不是通用判词库;内部 partial_verified 字样也不能当成事件外部验证。 + +`_pl9_annual_dasha_results` 默认 `without_dasha_balance`,当前调用没有显式覆盖。不能因它在源仓就压过已批准的余额口径。 + +允许复用行结构、事实映射、时间边界和缺项表示;网站生产调用须显式传入已裁定的 balance profile、标识实际使用口径,禁止静默回退到另一套。无余额可作为具名对照,不得伪装主结果。不要盲目替换源引擎所有默认值,本轮没有授权改变冻结个人导出链。 + +没有对应文案模板时,照常保留真实周期和原始星体/宫位数据,再提供有来源的条件性解释或标为暂无判词;不得把“无模板”写成“没有计算”。不必等全部模板齐全才提供可用年运数据。 + +### Q6:两张指南表不作直接、已验证的结果规则 + +可以作为待逐条溯源的传统参考假设,不直接输出“事业突破”“财务好年”。规则需补来源定位、所用流派、必要条件、冲突处理与解释权限。年主/宫位/尊贵/相位结构成立,不等于生活事件兑现。 + +分别记录:①年盘内对 Muntha 的结构关系;②年盘 Munthesh 的状态;③实际行运对该年固定 Muntha 点/星座的经过;④Muntha 自身逐年的推进。四者不是同一事件,也不能重复计证。 + +不设只有土星、罗睺才算的全局白名单。按来源规则与主题选相关星体,但每条必须说明是同宫、同星座、精确度数接触还是某种相位;采用哪套角距/容许度,不能自行发明统一阈值。只有星座位置时,不得输出精确到日的度数交会。 + +行运要扫描覆盖区间,保留逆行重复命中、停滞、进入/离开边界与实际日期;单一观察日不代表全年。双方统一 ayanamsa、node mode、年盘位置方案;不能拿另一种回归盘中的点无说明混算。Moon/快速星体如使用,只是相应时间尺度的触发候选,不自动获得年度主导权。 + +### Q7:具名 Yoga 沿用五态;相位基础结构另列 + +具名 Tajika Yoga 沿用第七轮形成状态合同,不新建一套同名不同义的状态。相位基础层另外描述几何命中、入相/出相、精确/停滞及判断参数,不能把某种相位直接命名成成立的 Ithasala/Easarapha。 + +按具名方法检查有效容许度、速度关系、未来能否成相、第三星与干扰等所需条件。缺条件不是“已证明不成立”。2026-11-06 来源审查记录仍标记多项待裁定和不允许提升预测因子;必须保留该边界。 + +尤其核对 Ithasala 的容许度与未来成相、Nakta/Yamaya 的第三星速度、Manahoo 的作用方式、Khallsara/Rudda/Iqabala 的定义差异。可显示“按某 profile 检出的候选结构”,不得因一个 angle hit 提升事件等级。 + +## 6. 下一次验收包与执行顺序 + +1. 先修 P0:真实用途区间状态、逐 claim 依赖、生成快照一致性。旧样稿全部重新通过事实校验,修复上述实际错误。 +2. 提供 grade gate、事实校验、Badhaka 与状态映射的实现或可审查补丁;公开样例补完整可重算输入。不要提交私人案例与密钥。 +3. 回归至少覆盖:落宫/宫主错置;337误作个体强度;摘要绕过分级;事业段夹带未绑定时间窗;D8跨界;已故对象当前建议;合法状态词误杀;证据章 withheld;facts状态变更后旧草稿;PVR/BPHS profile 混用。 +4. 年运补:适用与不适用 Satabdika/Ashtottari、缺现居地、不同年钟、Mudda四边界、余额口径显式传递、相位命中但具名 Yoga 条件不全、多候选 Narayana。不以单一成功样例替代分支覆盖。 +5. 每份样例提供完整快照哈希、测试命令/结果、分段修复记录与可读审计附录。区分“本地测试通过”“暂存部署成功”“占星语义已审”三个结论。 + +本轮资料源预检通过,包含外部适配器诊断、远端可见性与既有治理测试。该结果只说明本仓预检,不是网站算法或新拦截器测试通过。本轮不修改冻结导出器、不改网站服务器、不重新输出个人命盘。 From ac4bf94db5e5f5748f290ec82cef7513192bb8b0 Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Thu, 12 Nov 2026 22:56:19 +0800 Subject: [PATCH 2/3] fix(report): isolate runtime sources and show recorded verification (#217) --- CHANGELOG.md | 6 ++ docs/BUG_HISTORY.md | 15 ++++ ...OGRESS-reading-runtime-sources-20261112.md | 51 +++++++++++++ frontend/DESIGN.md | 2 + .../personal-report-markdown-view.tsx | 29 ++++++-- .../lib/personal-report-reading-contract.ts | 4 +- frontend/src/lib/product-runtime-contract.ts | 1 + frontend/src/mastra/report-reading-skill.ts | 4 +- .../tests/report-reading-20261027.test.tsx | 2 +- ...t-reading-runtime-sources-20261112.test.ts | 56 ++++++++++++++ references/functional-role-profile.md | 25 +++---- ...roduct_functional_profile_bphs_v3_166q4.md | 73 +++++++++++++++++++ references/product_runtime_contract.md | 22 +++++- scripts/functional_benefics.py | 4 +- scripts/report_render/audit_chapters.py | 44 ++++++++--- .../test_functional_profile_split_20261112.py | 60 +++++++++++++++ tests/test_report_audit_chapters_20261107.py | 11 ++- tests/test_report_no_web_wording_20261109.py | 29 +++----- .../test_report_wording_sanitizer_20261111.py | 5 +- 19 files changed, 377 insertions(+), 66 deletions(-) create mode 100644 docs/tasks/PROGRESS-reading-runtime-sources-20261112.md create mode 100644 frontend/tests/report-reading-runtime-sources-20261112.test.ts create mode 100644 references/product_functional_profile_bphs_v3_166q4.md create mode 100644 tests/test_functional_profile_split_20261112.py diff --git a/CHANGELOG.md b/CHANGELOG.md index cf35c376..78ca54c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 印度占星 Skill 更新日志 +## 2026-11-12 — 个人报告按当前证据合同写作并单列核验状态 + +- 解读开头明确废止历史预测数字和旧分级口径,功能吉凶按事实包选中的版本解释。 +- 「计算依据」中的核验记录按实际状态显示,默认折叠,导出保留两行。 +- 本轮沿用当前 Skill 版本(BUG-1861)。 + ## 2026-11-12 — 年运报告将 Narayana 列为条件参考 - 未决种子的具名分支独立列出,窗口来源数及把握等级依据独立证据。 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index e6dedaa7..23febf5f 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -25098,3 +25098,18 @@ - 防复发:新增回归覆盖未评估、应期窗口、必需分盘贴边及缺失边界。保留旧测试的 D6/D30 上限检查,分别核对 D6 的边界状态和 D30 的披露。 - 关联记录:#215、BUG-1851、BUG-1848。 - 修复版本:`codex/purpose-stability-20261112`。 + +## BUG-1861 | 个人报告提示仍含旧置信度口径,功能吉凶资料混用 + +- 状态:resolved(分支定向回归通过,待独立验收) +- 首次发现 / 最近更新:2026-11-12 / 2026-11-12 +- 影响面:个人报告写作提示、功能吉凶规则溯源与「计算依据」附录。 +- 用户现象:旧准确率和 A/B/C 置信度口径仍进入个人报告写作提示。附录显示固定核验说明,读者无法辨认两项实际核验状态。 +- 触发条件:个人报告从事实包生成写作提示并渲染计算依据。 +- 根因:历史方法原文先于产品合同进入模型上下文。事实包使用 PVR,供模型参考的 BPHS 文档却用上游路径存放产品修订。普通审计表用固定文案替换后台核验状态。 +- 修复:先载入产品合同的废止公告,报告继续遵循 `report_evidence_grade_v1`。按 Git 原始字节恢复上游 BPHS 并另存产品修订。个人报告附录从已有审计读取两项核验状态,缺失或阻塞显示「未完成」。 +- 验证:检查提示拼接顺序、上游 SHA256、十二上升土星分类、两张公开盘的 PVR profile、已保存与缺失的核验状态,以及附录折叠和九节正文的渲染边界。详情见 `docs/tasks/PROGRESS-reading-runtime-sources-20261112.md`。 +- 防复发:`test_functional_profile_split_20261112.py` 锁定原始文件和运行时 profile。`report-reading-runtime-sources-20261112.test.ts` 锁定公告、提示顺序和个人报告附录边界。 +- 相关记录:BUG-1794(个人报告附录部分回撤)、BUG-1841、BUG-1570、BUG-1590。 +- 复发自:无。 +- 修复版本:`codex/reading-runtime-sources-20261112`,待发布。 diff --git a/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md b/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md new file mode 100644 index 00000000..1e6f097d --- /dev/null +++ b/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md @@ -0,0 +1,51 @@ +# 个人报告解读的运行时资料与核验记录 · 2026-11-12 + +Gitea #217,BUG-1861。计划评论 42256,认领评论 42374。任务书基线 `1ba0364a`,合入本分支的验证基线为 staging `c55338f35916587ec9007d0786f370e5c29d0aa9`。 + +## 旧原文盘点 + +范围为仓库 `SKILL.md` 与 `REPORT_READING_REFERENCES` 的八份文件。下列行号按本轮基线。 + +| 文件与标题 | 行 | 原文片段与用途 | +| --- | --- | --- | +| `SKILL.md`,v6.9.14 核心能力、Yoga 逻辑验证指标 | 29、57–61 | 「Yoga精度Benchmark 100%」、Precision 83.26% / 96.48%、Recall 91.52% / 93.99%、F1 87.19% / 95.22%、8/8。技术样本指标,报告不据此声明预测准确率。 | +| `SKILL.md`,Transit Actionable Output | 288 | 「[A]=已验证 / [B]=高概率 / [C]=推断」。旧三级分法。 | +| `SKILL.md`,Chara Dasha 能力升级 | 334–338 | 「95.83% ≥ 95%」,「Sign 100%, Dur 91.67%, Overall 95.83%」,「~4.2%差异」。引擎对拍,不是个案命中率。 | +| `SKILL.md`,核心分析规则 | 426 | 「若没有主承诺和推运激活,输出置信度不得超过 C」。旧固定上限。 | +| `SKILL.md`,精准解盘方法论与资料索引 | 392、604 | 「三级置信度」索引及「[A]已验证 / [B]强推断 / [C]假设」。 | +| `SKILL.md`,已验证名人案例 | 727、731–736、738 | 标题与总览「平均93%」,个案列 95%、94%、92%、93%、94%、93%。历史吻合度,报告不据此声明验证或命中。 | +| `strict-workflow-router.md`,full-reading-strict | 181 | `Confidence label: A/B/C/insufficient`。 | +| 同文件,event-verification-strict | 332–343 | `A: same theme + same timing`、`B: … approximate timing`、`C: symbolic match only`、`Fail`、表格 `A/B/C/fail`。回放质量的旧映射不作报告等级。 | +| 同文件,Confidence rules | 409–418 | 表格 A、B、C、Insufficient 与「Upgrade only when independent techniques converge」。报告不采用这组旧分级门槛。 | +| `precision-reading-methodology.md`,案例验证 | 42 | 「500个案例验证,达到99%成功率」。 | +| 同文件,九层复合方法 | 141 | 「做到第六层,平均85%的预测成功率」。 | +| 同文件,验证驱动 | 178 | 「倒推失败率 > 30%」。历史流程阈值,不是本报告结果。 | +| 同文件,置信度分级、输出规范及诚实边界 | 226–249 | 「A-已验证 / B-强推断 / C-假设」、「置信度:[A/B/C]」。第 249 行「物理学中90%」「医学中60%」是跨学科举例,不是预测成绩。 | +| 同文件,常见教条式失误及纠正 | 269 | 「多系统验证(L4-L9)才能达到85%准确率」。 | +| 同文件,实战五步法 | 315、323 | 「匹配度 <60% 则停止」是历史流程阈值。「三级置信度标注」是旧输出。 | +| `event_judgment_skeleton.md`,Confidence Mapping 与 Output Contract | 109–125、147 | 「建议映射」A–D 与 `"confidence": "A|B|C|D"`。不是旧 A/B/C 词表,但本报告不按其示例自评分。 | + +`SKILL.md` 第 148 行 A/B/C 是入口路由分类。第 713 行 97.8% 是文档覆盖率。三个专题 `event_judgment_career.md`、`event_judgment_wealth.md`、`event_judgment_marriage.md` 只提证据不足会影响置信度,未给旧等级词表或预测率。`functional-role-profile.md` 与 `interpretation_status_contract.md` 分别记方法和状态,不含此类旧声明。 + +## 实施与消费位置 + +- 产品合同 G 节新增专供个人报告的前置公告。 `reportReadingPrompt` 在引述原文之前加载公告,原文照常逐份保留和记录哈希。聊天不加载这个块。 +- 从占星师 `8aaf60991c32a84ac30d6d7b6a62c4f166507bce` Git 对象取原始字节。SHA256 为 `95f5445a197a5f49ebaa08431816f0f3583b0a3c13f7967d3c043cecfe63aa7e`。原产品表按原字节移入具名文件,另加逐行差异表。 `functional_benefics.py` 仅修改两处引用路径。 +- 从当前 BPHS 代码取十二上升的土星期望值。白羊、巨蟹、狮子、天蝎、射手、双鱼为凶。金牛、天秤、摩羯、水瓶为吉。双子、处女为混合,现有集合将混合列入中性组,歧义注记标为 mixed。 +- `pl9_full_data_export._append_audit_chapters` 是个人报告审计的统一接入点。 `audit_chapters` 在这里读取已保存的两个审计状态,不复制后台词和说明。空记录或阻塞记未完成,已记录的完成、部分完成或不适用照实写。中文行名为「网上资料核对」「真实案例校准」,英文版独立翻译。 `PersonalReportMarkdownView` 在原计算依据下折叠显示这张表,打印复用原折叠表机制,Markdown 导出保留两行。 +- 九节的 C 级说明仍表示缺少相符案例。文案为「有星盘依据,还没有对得上的案例」,使核验行名只出现在附录。原作者写作与聊天过滤合同继续生效。 + +## 既有断言变更 + +| 位置 | 原值 | 新值 | 原因 | +| --- | --- | --- | --- | +| `test_report_no_web_wording_20261109.py::_assert_clean` | 一条固定核验说明必须是普通审计表最后一行,其余内容禁词 | 独立核验表恰有两条状态行,其余内容沿用禁词断言 | #217 要求两条可读的实际状态。 | +| `test_report_audit_chapters_20261107.py` 中文审计 | 固定说明仅一次,正文全篇不出现案例词 | 两条未完成行分别检查,隔离后仍禁止其余内容出现案例词 | 保留词语隔离,按新附录结构验证。 | +| `test_report_wording_sanitizer_20261111.py` | 聊天与报告共用同一句固定说明 | 聊天固定文案保持原值,个人报告不显示旧固定句 | 本轮只更改个人报告附录。 | +| `report-reading-20261027.test.tsx` C 级 | 「有星盘依据,还没有用真实案例校准过」 | 「有星盘依据,还没有对得上的案例」 | 九节不重复附录中的核验行名,保留 C 级含义。 | + +## 验证 + +- 开工基线 `c55338f35916587ec9007d0786f370e5c29d0aa9`。Python 定向 64 项通过,覆盖 BPHS 拆分、两张公开盘的 PVR 事实包、报告审计、禁词范围和聊天提示。盘面、功能吉凶及校正另有 95 项与 3 个子测试通过。隐私守卫 62 项通过。 +- 前端指定测试 24 项通过,另有聊天核验说明、报告导出与相关消费链 16 项通过。原 6 个提示块逐块校验,去掉维护者注释后的文本与基线一致。 +- TypeScript 检查通过。Lint 为 0 错误、62 条既有警告。对照 `npm run build` 两边均成功,首页 `/` 保持 `○ Static`。从构建后的首页 HTML 提取 JS 和 CSS 资源,两边各 39 个文件,gzip 后 JS 515860 字节、CSS 90886 字节,均为 0% 变化。 diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index d3dd9b23..72c8ba41 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -1518,6 +1518,8 @@ Bhava Bala 保留完整十二宫力量表;Score / Weight 等领域表头不单 ## 报告核对层与独立附录(2026-09-23) +个人报告「计算依据」内的「核验记录」默认折叠。网上资料核对和真实案例校准各一行,按记录显示状态。导出保留两行,打印时按现有核对表规则展开,打印后恢复展开状态。解读区不显示这两行。 + 个人报告保留原 Markdown 阅读、目录隔离与 memo 边界;文后独立渲染服务端分盘和事实表。分盘复用 VedicChartSvg 与 chart-grid/chart-card,不使用 float 或负 margin。事实表默认折叠、可键盘展开,横向溢出仅在表格区域滚动,缺数据不补写。Markdown 表里,只有表头含速度、Speed、度数或黄经的数值表(`.personal-report-table-numeric`)单行并按内容撑宽,放不下时在表自己的框里横滑;作用说明、建议这类整句表在页内换行。打印时所有报告表都是页宽,单元格可以换行,纸上不横滑。Sade Sati 明确缺三轮日期。09-24 reader-actions D2 撤下操作区「下载原始附录」入口;相关组件、路由和 helper 因删除权限阻塞暂留源码,不当作完成清理。不接普通下载 fallback、不增加 spinner。旧缓存不升级、不重算;没有结构化层就不显示占位盘。文案遵守 VOICE:不把可计算写成已验证。 事实表用中文列名和领域行列呈现,不把引擎路径当行名。主运、分运与小运、SAV 与 BAV、年度位置与 Saham 分为同组子表;缺失的年度行星位置明确说明,不用本命盘替代。机器溯源路径保留在数据中、不渲染。打印或保存 PDF 前自动展开此核对层全部折叠组,完成或取消后恢复原状态;打印解除表格横向滚动裁剪、重复表头,宽 BAV 表仍保留十二星座列。不新增打印入口或等待动画。 diff --git a/frontend/src/components/personal-report/personal-report-markdown-view.tsx b/frontend/src/components/personal-report/personal-report-markdown-view.tsx index cc332e53..852e8507 100644 --- a/frontend/src/components/personal-report/personal-report-markdown-view.tsx +++ b/frontend/src/components/personal-report/personal-report-markdown-view.tsx @@ -18,6 +18,7 @@ import { import { reportAiNotice } from "@/lib/ai-generated-notice"; import { parseReportFocusBlock, reportTitleByline } from "@/lib/report-focus-block"; import { reportChartGrid } from "@/lib/report-chart-grid-rehype"; +import { bindFactTablePrint } from "@/lib/report-fact-table-print"; import { remarkCjkStrong } from "@/lib/remark-cjk-strong"; import { NorthIndianChartSvg } from "@/components/personal-report/vedic-chart-svg"; import { ReportEdgeJump } from "@/components/personal-report/report-edge-jump"; @@ -87,6 +88,21 @@ export function reportBirthLine(markdown: string): string | null { return value && value.length <= 40 ? value : null; } +function VerificationAppendix({ language, children }: { language: ReportLanguage; children: ReactNode }) { + const root = useRef(null); + useEffect(() => { + if (root.current) return bindFactTablePrint(root.current, window); + }, []); + return ( +
+
+ {language === "en" ? "Verification" : "核验记录"} +
{children}
+
+
+ ); +} + function markdownComponents( headings: readonly LongformHeading[], language: ReportLanguage, @@ -112,11 +128,14 @@ function markdownComponents( return {children}; }, img: () => null, - table: ({ children }) => ( -
- {children}
-
- ), + table: ({ children }) => { + const labels = tableHeaderLabels(children); + const table =
{children}
; + const verificationHeader = language === "en" ? "Verification item|Status" : "核验项目|状态"; + return labels.join("|") === verificationHeader + ? {table} + : table; + }, td: ({ children }) => {renderNakshatraLabel(children)}, h1: ({ children }) => { const title = flattenText(children).trim(); diff --git a/frontend/src/lib/personal-report-reading-contract.ts b/frontend/src/lib/personal-report-reading-contract.ts index 491d7703..d818a30c 100644 --- a/frontend/src/lib/personal-report-reading-contract.ts +++ b/frontend/src/lib/personal-report-reading-contract.ts @@ -143,7 +143,7 @@ export const EVIDENCE_GRADE_LABEL = "证据等级"; export const EVIDENCE_GRADE_MEANING: Readonly> = { A: "在明确的案例集里经过较强的独立验证", B: "有对得上的真实案例支持,几种独立方法方向一致", - C: "有星盘依据,还没有用真实案例校准过", + C: "有星盘依据,还没有对得上的案例", D: "关键依据缺失,暂不能判断", }; @@ -156,7 +156,7 @@ export function readingSectionView(section: ReportReading["sections"][number]): return { status: "ok", paragraphs: section.paragraphs.map(({ text, grade }) => (grade ? { text, grade } : { text })) }; } -/** 「证据等级 C:有星盘依据,还没有用真实案例校准过」 */ +/** 「证据等级 C:有星盘依据,还没有对得上的案例」 */ export function evidenceGradeTag(grade: EvidenceGrade): string { return `${EVIDENCE_GRADE_LABEL} ${grade}:${EVIDENCE_GRADE_MEANING[grade]}`; } diff --git a/frontend/src/lib/product-runtime-contract.ts b/frontend/src/lib/product-runtime-contract.ts index adeee09b..fbcbe4e6 100644 --- a/frontend/src/lib/product-runtime-contract.ts +++ b/frontend/src/lib/product-runtime-contract.ts @@ -28,6 +28,7 @@ export type ProductContractBlock = | "natal-instructions" | "mevg-blocked-policy" | "shared-reading" + | "report-reading-source-notices" | "report-reading"; let cached: string | null = null; diff --git a/frontend/src/mastra/report-reading-skill.ts b/frontend/src/mastra/report-reading-skill.ts index d6011ff2..9ae0f990 100644 --- a/frontend/src/mastra/report-reading-skill.ts +++ b/frontend/src/mastra/report-reading-skill.ts @@ -54,9 +54,11 @@ export function reportReadingPrompt(): ReportReadingPrompt { if (!body) throw new Error(`Skill ${jyotishSkillPackage.name} has no method body for the report reading`); const references = REPORT_READING_REFERENCES.map((path) => ({ path, ...read(path) })); const contract = read(PRODUCT_RUNTIME_CONTRACT_FILE); - const rules = productContractBlock("report-reading", { CLAIM_TYPES: REPORT_CLAIM_TYPES.join("、") }); + const sourceNotices = productContractBlock("report-reading-source-notices", {}, contract.text); + const rules = productContractBlock("report-reading", { CLAIM_TYPES: REPORT_CLAIM_TYPES.join("、") }, contract.text); const system = [ `The jyotish-vedic-astrology skill is loaded for a written report. Its full SKILL.md (the astrologer's upstream skill, verbatim) is quoted below, then the references this report routes to, verbatim. Follow its method, routing and truth boundaries. There are no tools in this call: everything you may use is in this message and the chart facts.`, + sourceNotices, REPORT_READING_SKILL_MARKER, body, ...references.map((file) => `\n${file.text.trim()}\n`), diff --git a/frontend/tests/report-reading-20261027.test.tsx b/frontend/tests/report-reading-20261027.test.tsx index 4e764a7d..9b11ead8 100644 --- a/frontend/tests/report-reading-20261027.test.tsx +++ b/frontend/tests/report-reading-20261027.test.tsx @@ -389,7 +389,7 @@ test("the page keeps a reading only in the stored shape and shows it before the assert.ok(readingAt > zh.indexOf("印度占星星盘报告") && readingAt < basisAt && basisAt < engineAt, zh.slice(0, 400)); for (const title of ["总评", "现在这几年", "几条建议", "依据与边界"]) assert.ok(zh.includes(`

${title}

`), title); // #192(产品 2026-11-12 原型方案 B):领域节每段下面一行灰字,写等级和含义;总评等不分级的节没有 - assert.ok(zh.includes("证据等级 C:有星盘依据,还没有用真实案例校准过"), "grade line"); + assert.ok(zh.includes("证据等级 C:有星盘依据,还没有对得上的案例"), "grade line"); assert.match(zh, /

证据等级 C:/, "a plain line, no tap to open"); const withheld = (accept(draft({ love: [`${PARAGRAPH}你注定晚婚。`] })) as { reading: unknown }).reading; const shown = renderToStaticMarkup(); diff --git a/frontend/tests/report-reading-runtime-sources-20261112.test.ts b/frontend/tests/report-reading-runtime-sources-20261112.test.ts new file mode 100644 index 00000000..d796b59d --- /dev/null +++ b/frontend/tests/report-reading-runtime-sources-20261112.test.ts @@ -0,0 +1,56 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; + +import { PersonalReportMarkdownView } from "../src/components/personal-report/personal-report-markdown-view.tsx"; +import { + EVIDENCE_GRADE_CONTRACT, + REPORT_READING_SECTIONS, + type ReportReading, +} from "../src/lib/personal-report-reading-contract.ts"; +import { projectOrdinaryReportMarkdown } from "../src/lib/report-public-projection.ts"; +import { reportReadingPrompt, REPORT_READING_SKILL_MARKER } from "../src/mastra/report-reading-skill.ts"; + +test("report writer retires the historic rules before the original references", () => { + const { system, skill } = reportReadingPrompt(); + const noticesAt = system.indexOf("### 运行时废止"); + const profileAt = system.indexOf("### 功能吉凶 profile"); + const sourceAt = system.indexOf(REPORT_READING_SKILL_MARKER); + assert.ok(noticesAt >= 0 && noticesAt < profileAt && profileAt < sourceAt); + const notices = system.slice(noticesAt, sourceAt); + assert.match(notices, /保留原文以便追溯,运行时无效/); + assert.match(notices, /report_evidence_grade_v1/); + assert.match(notices, /不得向用户宣称准确率、成功率或命中率/); + assert.match(notices, /functional\.functional_profile.*pvr_table30_v1/); + assert.match(notices, /product_functional_profile_bphs_v3_166q4\.md.*待占星师审核/); + assert.match(system.slice(sourceAt), /平均85%的预测成功率/); + assert.ok(skill.loaded.some(({ path }) => path === "references/functional-role-profile.md")); + assert.ok(!skill.loaded.some(({ path }) => path.includes("product_functional_profile_bphs"))); +}); + +test("personal report verification appears in the folded appendix outside all nine reading sections", () => { + const reading: ReportReading = { + version: 3, + language: "zh", + contract: EVIDENCE_GRADE_CONTRACT, + skill: { name: "fixture", version: "fixture", loaded: [{ path: "SKILL.md", sha256: "0".repeat(64) }] }, + sections: REPORT_READING_SECTIONS.map((section) => ({ + ...section, status: "ok", paragraphs: [{ text: "先核对盘面材料。", grade: "C" }], + })), + }; + const markdown = [ + "# 个人报告", "", "## 技法审计与证据边界", "", "| 核验项目 | 状态 |", "| ------ | ------ |", + "| 网上资料核对 | 未完成 |", "| 真实案例校准 | 未完成 |", + ].join("\n"); + const html = renderToStaticMarkup(createElement(PersonalReportMarkdownView, { + markdown: projectOrdinaryReportMarkdown(markdown), reading, drawnThrough: 0, + })); + const body = /]+class="personal-report-reading"[^>]*>([\s\S]*?)<\/section>/.exec(html)?.[1]; + assert.ok(body); + assert.equal(body.match(/class="personal-report-reading-part"/g)?.length, 9); + assert.doesNotMatch(body, /网上资料核对|真实案例校准/); + assert.match(body, /证据等级 C/); + assert.match(html, /

核验记录<\/summary>[\s\S]*网上资料核对<\/td>未完成[\s\S]*真实案例校准<\/td>未完成/); + assert.doesNotMatch(html, /MEVG/); +}); diff --git a/references/functional-role-profile.md b/references/functional-role-profile.md index 82fb2fb1..e2c74b32 100644 --- a/references/functional-role-profile.md +++ b/references/functional-role-profile.md @@ -1,8 +1,6 @@ -# Functional ownership profile v3 + #166 Q4 +# Functional ownership profile v3 -Profile: `bphs_ch34_general_with_sign_exceptions_v3_166q4` (upstream v3 table, i.e. Aries / Scorpio -Venus challenging (BUG-1570), plus the #166 Q4 Gemini / Virgo Saturn mixed rows -(BUG-1590)). Until 2026-11-07 this table was mislabelled `..._v2`. +Profile: `bphs_ch34_general_with_sign_exceptions_v3`. Source: BPHS chapter 34, general rules 2–17 and ascendant entries 19–44, public translation at https://jyotishvidya.com/ch34.htm (inspected 2026-10-02). This is a named implementation of a translation, not all-lineage agreement. @@ -19,11 +17,9 @@ not automatically malefic. Sun/Moon eighth lordship has the stated exception. Unspecified angular or second-house-only cases remain neutral/mixed. Explicit exceptions are recorded in `ROLE_OVERRIDES`: Aries Mars helpful in -association (mixed), Venus challenging (34.20); Taurus Venus challenging, Sun -supportive; Gemini Jupiter challenging, Saturn mixed (#166 Q4); Virgo Jupiter -challenging, Saturn mixed (#166 Q4); Libra Venus -mixed, Mars challenging; Scorpio Mars mixed, Sun yoga-supporting, Venus -challenging (34.35); Sagittarius Jupiter/Mercury mixed +association (mixed), Venus challenging; Taurus Venus challenging, Sun supportive; Gemini Jupiter +challenging; Virgo Jupiter challenging; Libra Venus mixed, Mars challenging; +Scorpio Mars mixed, Sun yoga-supporting and Venus challenging; Sagittarius Jupiter/Mercury mixed (Mercury's association with Sun is separate); Capricorn Moon challenging; Aquarius Mars challenging, Mercury mixed; Pisces Mercury challenging. The remaining general fallbacks are identified in each planet's `role_basis`; @@ -35,9 +31,8 @@ functional benefic does not guarantee a favorable event. No death or outcome prediction is inferred from this classification. The Yoga engine's natural predicates and active Yoga rule library are not replaced by ownership roles. -Chart page layout (issue #163): `scripts/chart_view_points/functional_roles.py` lays this -profile out one row per body for the 盘面数据 table. It adds no rule: the -functional class is the profile's; Rahu/Ketu are `pending` (association not -evaluated); Yogakaraka and Badhaka (lord of `yoga_engine.badhaka_house`) are -separate labels; a natural benefic owning 4/7/10 and none of 1/5/9 is marked -Kendradhipati with `conditions_not_evaluated`. +Revision v3 (2026-11-04) restores the explicit Venus entries in ch34.19–22 +and35–36. This corrects omissions independently of rectification fit. Existing +score weights remain unchanged; native event evidence records the functional +profile and its weighted/unweighted auxiliary contribution. Historical scores +must not be described as recomputed merely because this profile changed. diff --git a/references/product_functional_profile_bphs_v3_166q4.md b/references/product_functional_profile_bphs_v3_166q4.md new file mode 100644 index 00000000..454f585a --- /dev/null +++ b/references/product_functional_profile_bphs_v3_166q4.md @@ -0,0 +1,73 @@ +# 产品功能吉凶 profile · BPHS v3 + #166 Q4 + +- Profile ID:`bphs_ch34_general_with_sign_exceptions_v3_166q4` +- 来源:占星师 2026-11-05 #166 Q4,BUG-1570,BUG-1590。 +- 状态:产品修订,待占星师审核。个人报告以事实包选中的 profile 为准。 + +## 与占星师 `8aaf6099` 版本的逐行差异 + +行号分别按上游原文和下方产品原文计算。末组改动将上游 Revision v3 整段替换为产品 #163 的星盘页说明。 + +| 改动 | 上游原文 | 产品原文 | +| --- | --- | --- | +| 改写 | 1 # Functional ownership profile v3 | 1 # Functional ownership profile v3 + #166 Q4 | +| 改写 | 3 Profile: `bphs_ch34_general_with_sign_exceptions_v3`. | 3 Profile: `bphs_ch34_general_with_sign_exceptions_v3_166q4` (upstream v3 table, i.e. Aries / Scorpio | +| 新增 | — | 4 Venus challenging (BUG-1570), plus the #166 Q4 Gemini / Virgo Saturn mixed rows | +| 新增 | — | 5 (BUG-1590)). Until 2026-11-07 this table was mislabelled `..._v2`. | +| 改写 | 20 association (mixed), Venus challenging; Taurus Venus challenging, Sun supportive; Gemini Jupiter | 22 association (mixed), Venus challenging (34.20); Taurus Venus challenging, Sun | +| 改写 | 21 challenging; Virgo Jupiter challenging; Libra Venus mixed, Mars challenging; | 23 supportive; Gemini Jupiter challenging, Saturn mixed (#166 Q4); Virgo Jupiter | +| 改写 | 22 Scorpio Mars mixed, Sun yoga-supporting and Venus challenging; Sagittarius Jupiter/Mercury mixed | 24 challenging, Saturn mixed (#166 Q4); Libra Venus | +| 新增 | — | 25 mixed, Mars challenging; Scorpio Mars mixed, Sun yoga-supporting, Venus | +| 新增 | — | 26 challenging (34.35); Sagittarius Jupiter/Mercury mixed | +| 改写 | 34 Revision v3 (2026-11-04) restores the explicit Venus entries in ch34.19–22 | 38 Chart page layout (issue #163): `scripts/chart_view_points/functional_roles.py` lays this | +| 改写 | 35 and35–36. This corrects omissions independently of rectification fit. Existing | 39 profile out one row per body for the 盘面数据 table. It adds no rule: the | +| 改写 | 36 score weights remain unchanged; native event evidence records the functional | 40 functional class is the profile's; Rahu/Ketu are `pending` (association not | +| 改写 | 37 profile and its weighted/unweighted auxiliary contribution. Historical scores | 41 evaluated); Yogakaraka and Badhaka (lord of `yoga_engine.badhaka_house`) are | +| 改写 | 38 must not be described as recomputed merely because this profile changed. | 42 separate labels; a natural benefic owning 4/7/10 and none of 1/5/9 is marked | +| 新增 | — | 43 Kendradhipati with `conditions_not_evaluated`. | + +## 分拆前的产品原文 + +# Functional ownership profile v3 + #166 Q4 + +Profile: `bphs_ch34_general_with_sign_exceptions_v3_166q4` (upstream v3 table, i.e. Aries / Scorpio +Venus challenging (BUG-1570), plus the #166 Q4 Gemini / Virgo Saturn mixed rows +(BUG-1590)). Until 2026-11-07 this table was mislabelled `..._v2`. +Source: BPHS chapter 34, general rules 2–17 and ascendant entries 19–44, +public translation at https://jyotishvidya.com/ch34.htm (inspected 2026-10-02). +This is a named implementation of a translation, not all-lineage agreement. + +`owned_houses` is geometry. `lagna_lord` is identity. `yogakarakas` is the +strict distinct 4/7/10 plus 5/9 lordship definition. The first house remains +angular and trinal but cannot count twice. Broader textual yoga-producing +associations (including Scorpio Sun/Moon) are not restricted by that field. + +Functional roles use general ownership rules with explicit sign entries +taking precedence. Lagna/trinal lords are generally supportive; 3/6/11 and +qualified eighth lordship challenging. Sole twelfth lordship is conditional, +not automatically malefic. Sun/Moon eighth lordship has the stated exception. +Unspecified angular or second-house-only cases remain neutral/mixed. + +Explicit exceptions are recorded in `ROLE_OVERRIDES`: Aries Mars helpful in +association (mixed), Venus challenging (34.20); Taurus Venus challenging, Sun +supportive; Gemini Jupiter challenging, Saturn mixed (#166 Q4); Virgo Jupiter +challenging, Saturn mixed (#166 Q4); Libra Venus +mixed, Mars challenging; Scorpio Mars mixed, Sun yoga-supporting, Venus +challenging (34.35); Sagittarius Jupiter/Mercury mixed +(Mercury's association with Sun is separate); Capricorn Moon challenging; +Aquarius Mars challenging, Mercury mixed; Pisces Mercury challenging. +The remaining general fallbacks are identified in each planet's `role_basis`; +they are not presented as a verbatim complete classical table. + +Natural benefic/malefic status, strength, maraka roles, conjunctions, aspects +and period activation are independent layers. Neutral does not mean harmless; +functional benefic does not guarantee a favorable event. No death or outcome +prediction is inferred from this classification. The Yoga engine's natural +predicates and active Yoga rule library are not replaced by ownership roles. + +Chart page layout (issue #163): `scripts/chart_view_points/functional_roles.py` lays this +profile out one row per body for the 盘面数据 table. It adds no rule: the +functional class is the profile's; Rahu/Ketu are `pending` (association not +evaluated); Yogakaraka and Badhaka (lord of `yoga_engine.badhaka_house`) are +separate labels; a natural benefic owning 4/7/10 and none of 1/5/9 is marked +Kendradhipati with `conditions_not_evaluated`. diff --git a/references/product_runtime_contract.md b/references/product_runtime_contract.md index b8029ac2..93d283b4 100644 --- a/references/product_runtime_contract.md +++ b/references/product_runtime_contract.md @@ -11,7 +11,7 @@ SKILL.md 是占星师 skill 的原文(上游 732642856/yinduzhanxing),方 - 不给医疗、法律、投资、安全关键指令;不断言死亡、疾病诊断、离婚、妊娠、流产、不孕、孩子性别。 - 服务端标为 `blocked` 的计算原样保留为 blocked;外部 oracle 未闭环或体系分歧本身不阻塞有条件的传统解读,按 `references/interpretation_status_contract.md` 记在解读状态轴上。 - + - 回答里不写联网检索、外部资料、MEVG、全网核验或真实案例校准(简明解读、深度解读两种模式都不写,审计表也不列这几行);这几项只记在后台。也不假装做过:不把任何结论写成已验证、已校准或确定。 - Arudha(A1–A12、AL、UL)的写法:pada 所在星座、pada 所在宫、pada 星座的主星、该主星的本命落宫是四件不同的事,证据卡分别给出 `sign`、`pada_house_from_lagna`(从本命上升按整宫数到 pada 所在星座)、`lord`、`lord_natal_house`。写主星落宫时按占星师要求的句式:「A2 位于水瓶;其主星土星位于本命第 2 宫」。不得写成「A2 水瓶(主土星,落 2 宫)」这类分不清是 pada 落宫还是主星落宫的写法;要说 pada 所在宫时写明「A2 所在宫(从上升数)为第 6 宫」,并且只引卡上的 `pada_house_from_lagna`,不自己数。 @@ -125,7 +125,7 @@ Treat the tool result's top-level status and evidence_contract as the authoritat - When status is ready and evidence_contract.answer_policy.can_answer_direction is true, answer the user's actual question directly. Do not begin with infrastructure or confidence disclaimers. - An unavailable optional provider or external cross-check is not a calculation failure. Never call it an internal error. - + - Do not mention VedAstro, snapshot, fallback, gateway, archive or provider internals unless the user explicitly asks about methodology. In either mode, do not write about web search, external sources, MEVG or real-case calibration, and do not put rows for them in the 深度解读 Technique Audit Table; the backend keeps that record. Always: @@ -255,6 +255,24 @@ evidence_card.backstage records, for the backend only, that global web evidence **产品计算,待占星师审核(BUG-1853,2026-11-12):Badhaka。** 她的引擎(`8aaf6099`)没有本命 Badhaka 模块,健康领域清单却列了它。产品在 `scripts/report_render/badhaka_facts.py` 里按 `references/badhaka-obstacle-planet-guide.md` §二(与她仓库同名文件逐字相同)从已算好的 D1 位置给出 Badhaka 宫、星座、宫主及其落点、宫内行星,只给位置、不下结论,记录里带 `status: product_computation_pending_astrologer_review`。它不改她的 `jyotish_engine.py`、`yoga_engine.py`(只调用后者的 `badhaka_house`)。报告解读和聊天健康证据卡都读这条记录。她的路由 §7 本身没有列 Badhaka;是否保留为健康必查项、用哪条规则,等她审核。 + +### 运行时废止 + +以下位置保留原文以便追溯,运行时无效。它们不得成为个人报告的预测准确率、成功率或证据等级依据。 + +- `SKILL.md` 的「v6.9.14 核心能力」第 29 行和「Yoga 逻辑验证指标」第 57–61 行为旧技术评测。`Chara Dasha 能力升级`第 334–338 行为旧引擎对拍。第 727、731–736、738 行为既有案例吻合数字。这些数字均不得用于报告的准确率、成功率、命中率或校准声明。 +- `SKILL.md` 的「Transit Actionable Output」第 288 行、应期规则第 426 行及「精准解盘方法论」第 604 行的旧置信度口径和固定上限停止生效。第 392 行的索引只用于追溯。 +- `references/strict-workflow-router.md` 的「full-reading-strict」第 181 行、「event-verification-strict」第 332–343 行和「Confidence rules」第 409–418 行的旧 A/B/C/insufficient、A/B/C/fail 和分级门槛停止生效。 +- `references/precision-reading-methodology.md` 的「案例验证」第 42 行、「九层复合方法」第 141 行、「常见教条式失误及纠正」第 269 行的预测数字停止生效。「验证驱动」第 178 行和「实战」第 315 行的历史阈值与第 249 行的跨学科举例,不得当成本报告的验证结果或门槛。第 226–245 行与第 323 行的三级标签和示例停止生效。 +- `references/event_judgment_skeleton.md` 第 109–125 行的旧示例映射只保留方法史。第 147 行的 A–D 字段示例不能给报告自评分。 + +结论等级只按 `report_evidence_grade_v1` 提供的 A–D 上限逐条使用。报告不得向用户宣称准确率、成功率或命中率,也不得把旧样例或工程对拍写成本次验证。 + +### 功能吉凶 profile + +个人报告以事实包 `functional.functional_profile` 选中的版本为准,当前为 `pvr_table30_v1`。引用的 `references/functional-role-profile.md` 是占星师 `8aaf6099` 的 BPHS 原文,只供对照。产品修订的 `references/product_functional_profile_bphs_v3_166q4.md` 另有具名版本,待占星师审核,不进入报告结论。不要用对照表重判已选 PVR 结果。 + + 你在给一份个人星盘报告写开头的「解读」。用户消息里的盘面事实(report-reading-facts-v3)是引擎已经算好的全部材料,只用这些,不编数据,不另起算法,不凭印象重算尊贵度、宫位或日期。事实里没有的层就当没有。 diff --git a/scripts/functional_benefics.py b/scripts/functional_benefics.py index e5e4288c..1eddc1a8 100644 --- a/scripts/functional_benefics.py +++ b/scripts/functional_benefics.py @@ -377,7 +377,7 @@ def derive_functional_benefic_malefic( else "BPHS ch34 general ownership; associations not evaluated" for planet in PLANETS } - profile_source = "BPHS ch. 34 general ownership rules plus sign exceptions (references/functional-role-profile.md)" + profile_source = "BPHS ch. 34 general ownership rules plus sign exceptions (references/product_functional_profile_bphs_v3_166q4.md)" prior = [] for (sign, planet), (ruling, product_role, note) in PRIOR_RULINGS.items(): @@ -408,7 +408,7 @@ def derive_functional_benefic_malefic( "profile_source": profile_source, "lagna_lord": SIGN_LORDS[asc_sign], "yogakaraka_definition": "distinct lordships: one of 4/7/10 and one of 5/9", - "rule_reference": "references/functional-role-profile.md", + "rule_reference": "references/product_functional_profile_bphs_v3_166q4.md", "profile_is_not": PROFILE_IDS[other], "assertion_label": "parameter_sensitive", "dual_lordship_note": DUAL_LORDSHIP_NOTE, diff --git a/scripts/report_render/audit_chapters.py b/scripts/report_render/audit_chapters.py index b35cbaf4..2b3b38a3 100644 --- a/scripts/report_render/audit_chapters.py +++ b/scripts/report_render/audit_chapters.py @@ -6,9 +6,8 @@ for: the full Technique Audit Table (with the Functional Benefic/Malefic row), the parameter and method differences, the evidence boundaries, and the 60-division ledger (20 formal traditional divisions + 40 research D-N rows). -产品 2026-11-08(BUG-1810):用户可见文字不出现「联网 / 外部资料 / 外部核验 / -MEVG / 真实案例」这类说法。审计行与证据边界里的外部核验字样不再渲染;后台 -packet 的 ``technique_audit_table`` 原样保留,质量门改为检查后台记录仍在。 +核验状态只在个人报告计算依据的独立表中显示(BUG-1861)。普通审计行和 +证据边界继续过滤后台措辞,packet 的 ``technique_audit_table`` 原样保留。 Everything is read from the packet. Statuses are written as words, never as internal codes, so the ordinary projection keeps the chapter. @@ -37,13 +36,11 @@ LEDGER_HEADING = { REQUIRED_ROWS = ("Functional Benefic/Malefic",) # 原值:这三行都渲染,缺哪行就补哪行 # 新值:后两行不再渲染(后台 packet 保留);原因:产品负责人 2026-11-08:用户可见文字不出现联网/外部核验字样 -HIDDEN_TECHNIQUES = ("MEVG / Global Web Evidence", "Real Case Calibration") +VERIFICATION_LABELS = { + "MEVG / Global Web Evidence": ("网上资料核对", "Online sources check"), + "Real Case Calibration": ("真实案例校准", "Real-case calibration"), +} NO_WEB_WORDS = ("联网", "外部资料", "外部核验", "MEVG", "真实案例", "Real Case", "Global Web") -VERIFICATION_LIMIT_LINE = "本次未完成外部资料与案例核验,候选窗口尚未据此确认。" -VERIFICATION_LIMIT_LINE_EN = ( - "This reading did not complete external-source or real-case verification; " - "candidate windows have not been confirmed on that basis." -) WEB_WORDING = re.compile("|".join(re.escape(word) for word in NO_WEB_WORDS), re.IGNORECASE) AUDIT_CLAUSE = re.compile(r"[^。;;]+[。;;]?") BODIES = ("Ascendant", "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu") @@ -282,8 +279,8 @@ def _audit_rows(packet: dict, language: str) -> list[tuple[str, str, str, str]]: continue name = str(row["technique"]) seen.add(name) - if name in HIDDEN_TECHNIQUES: - # 产品负责人 2026-11-08:这两行只在后台记录里保留,不渲染给用户。 + if name in VERIFICATION_LABELS: + # The original audit names and notes stay in the packet. continue if name == "Functional Benefic/Malefic": note = _functional_note(functional, language) if functional else _clean(row.get("note"), language) @@ -325,6 +322,28 @@ def _table(header: tuple[str, ...], rows: list[tuple[str, ...]]) -> list[str]: return lines +def _verification_table(packet: dict, language: str) -> list[str]: + en = language == "en" + status_by_technique = {} + table = packet.get("technique_audit_table") + for row in table if isinstance(table, list) else []: + if isinstance(row, dict) and str(row.get("technique")) in VERIFICATION_LABELS: + status_by_technique[row["technique"]] = str(row.get("calculation_status") or row.get("status") or "").strip().lower() + lines = ["| Verification item | Status |" if en else "| 核验项目 | 状态 |", "| ------ | ------ |"] + for technique, labels in VERIFICATION_LABELS.items(): + state = status_by_technique.get(technique) + if state in ("used", "executed", "complete", "completed", "verified", "official_verified"): + status = "Completed" if en else "已完成" + elif state in ("partial", "partial_verified"): + status = "Partially completed" if en else "部分完成" + elif state == "not_applicable": + status = "Not applicable" if en else "不适用" + else: + status = "Not completed" if en else "未完成" + lines.append(f"| {labels[int(en)]} | {status} |") + return lines + + def _functional_table(packet: dict, language: str) -> list[str]: functional = _dict(_dict(_dict(packet.get("worksheets")).get("strengths_and_scores")).get("functional_benefic_malefic")) if not functional: @@ -551,7 +570,8 @@ def render_audit_chapters(packet: dict, language: str) -> str: "", *_table(("Technique", "Status", "Source", "Audit note") if en else ("技法", "状态", "依据来源", "审计说明"), _audit_rows(packet, language)), - f"| — | — | — | {VERIFICATION_LIMIT_LINE_EN if en else VERIFICATION_LIMIT_LINE} |", + "", + *_verification_table(packet, language), "", *_functional_table(packet, language), ] diff --git a/tests/test_functional_profile_split_20261112.py b/tests/test_functional_profile_split_20261112.py new file mode 100644 index 00000000..13066cc0 --- /dev/null +++ b/tests/test_functional_profile_split_20261112.py @@ -0,0 +1,60 @@ +"""Report and product BPHS provenance and the selected profile.""" + +from hashlib import sha256 +from pathlib import Path + +import pytest + +from scripts.functional_benefics import derive_functional_benefic_malefic +from scripts.report_render.audit_chapters import render_audit_chapters +from tests.test_reading_facts_v3_20261112 import _reading_facts, _reading_request, public_report + + +ROOT = Path(__file__).resolve().parents[1] +PRODUCT_PROFILE_PATH = "references/product_functional_profile_bphs_v3_166q4.md" + + +def test_upstream_profile_retains_exact_source_bytes(): + source = ROOT / "references/functional-role-profile.md" + # yinduzhanxing 8aaf60991c32a84ac30d6d7b6a62c4f166507bce. + assert sha256(source.read_bytes()).hexdigest() == "95f5445a197a5f49ebaa08431816f0f3583b0a3c13f7967d3c043cecfe63aa7e" + product = (ROOT / PRODUCT_PROFILE_PATH).read_text(encoding="utf-8") + assert "bphs_ch34_general_with_sign_exceptions_v3_166q4" in product + assert "Revision v3" in product and "Chart page layout (issue #163)" in product + + +@pytest.mark.parametrize(("ascendant", "role"), [ + ("Aries", "malefic"), ("Taurus", "benefic"), ("Gemini", "mixed"), + ("Cancer", "malefic"), ("Leo", "malefic"), ("Virgo", "mixed"), + ("Libra", "benefic"), ("Scorpio", "malefic"), ("Sagittarius", "malefic"), + ("Capricorn", "benefic"), ("Aquarius", "benefic"), ("Pisces", "malefic"), +]) +def test_product_bphs_saturn_table_is_unchanged(ascendant, role): + result = derive_functional_benefic_malefic(ascendant, functional_profile="bphs_exception_profile") + group = "neutral" if role == "mixed" else role + assert "Saturn" in result[f"functional_{group}s"] + if role == "mixed": + assert "mixed" in result["ambiguous_cell_notes"]["Saturn"]["summary_en"] + assert result["profile"] == "bphs_ch34_general_with_sign_exceptions_v3_166q4" + assert result["rule_reference"] == PRODUCT_PROFILE_PATH + assert PRODUCT_PROFILE_PATH in result["profile_source"] + + +def test_report_functional_profile_follows_packet(public_report): + _, body, reading, packet = public_report + assert _reading_facts(packet, reading, **_reading_request(body))["functional"]["functional_profile"] == "pvr_table30_v1" + + +def test_personal_appendix_reports_only_recorded_verification_status(): + packet = {"technique_audit_table": [ + {"technique": "MEVG / Global Web Evidence", "status": "blocked", "note": "internal"}, + {"technique": "Real Case Calibration", "calculation_status": "partial", "status": "executed"}, + ]} + zh = render_audit_chapters(packet, "zh") + assert "| 网上资料核对 | 未完成 |" in zh + assert "| 真实案例校准 | 部分完成 |" in zh + assert "MEVG" not in zh and "internal" not in zh + packet["technique_audit_table"][0]["status"] = "executed" + assert "| 网上资料核对 | 已完成 |" in render_audit_chapters(packet, "zh") + fallback = render_audit_chapters({}, "zh") + assert "| 网上资料核对 | 未完成 |" in fallback and "| 真实案例校准 | 未完成 |" in fallback diff --git a/tests/test_report_audit_chapters_20261107.py b/tests/test_report_audit_chapters_20261107.py index 7f59a69a..4639119c 100644 --- a/tests/test_report_audit_chapters_20261107.py +++ b/tests/test_report_audit_chapters_20261107.py @@ -72,12 +72,11 @@ def test_audit_chapter_keeps_required_rows_differences_boundaries_and_ledger() - assert "| Functional Benefic/Malefic |" in zh assert "MEVG" not in zh assert "Real Case" not in zh - # 原值:全文没有「外部资料」。新值:只放行表尾的固定说明行。 - # 原因:2026-11-11 固定核验说明(BUG-1837)。 - limit = "| — | — | — | 本次未完成外部资料与案例核验,候选窗口尚未据此确认。 |" - assert zh.count(limit) == 1 - assert "外部资料" not in zh.replace(limit, "", 1) - assert "真实案例" not in zh + assert "| 网上资料核对 | 未完成 |" in zh + case_row = "| 真实案例校准 | 未完成 |" + assert zh.count(case_row) == 1 + assert "外部资料" not in zh + assert "真实案例" not in zh.replace(case_row, "", 1) # Functional vs natural conflicts are stated, not only the role lists. assert "| 土星 | 自然凶 | Yogakaraka | 9, 10 | 冲突,降一级置信度 |" in zh # Parameter-sensitive rows and the Narayana method conflict. diff --git a/tests/test_report_no_web_wording_20261109.py b/tests/test_report_no_web_wording_20261109.py index 7c9ea95a..efdbcc9e 100644 --- a/tests/test_report_no_web_wording_20261109.py +++ b/tests/test_report_no_web_wording_20261109.py @@ -1,7 +1,4 @@ -"""产品负责人 2026-11-08(BUG-1810):报告渲染不出现联网/外部核验字样,后台记录保留。 - -只有技法审计表末行可显示固定核验说明。表中其他内容不显示联网措辞,后台记录保留。 -""" +"""Verification wording is confined to the personal-report appendix.""" from __future__ import annotations @@ -9,27 +6,23 @@ from itertools import takewhile from scripts.full_report_quality_gate import BACKSTAGE_TECHNIQUE_AUDIT_ROWS from scripts.report_render.audit_chapters import ( - AUDIT_TABLE_HEADING, NO_WEB_WORDS, - VERIFICATION_LIMIT_LINE, - VERIFICATION_LIMIT_LINE_EN, render_audit_chapters, ) from tests.test_report_audit_chapters_20261107 import _packet def _assert_clean(text: str, language: str, where: str) -> None: - # 原值:在全文检查禁词。 - # 新值:先核对固定说明只出现一次且位于技法审计表末行,再检查其余全文。 - # 原因:2026-11-11 的说明行及英文版补充(BUG-1837)。 - limit = VERIFICATION_LIMIT_LINE_EN if language == "en" else VERIFICATION_LIMIT_LINE - row = f"| — | — | — | {limit} |" - assert text.count(limit) == 1, where - _, heading, tail = text.partition(f"\n### {AUDIT_TABLE_HEADING[language]}\n") - assert heading, where - rows = list(takewhile(lambda line: line.startswith("|"), tail.lstrip("\n").splitlines())) - assert rows and rows[-1] == row, where - remainder = "\n".join(line for line in text.splitlines() if line != row).casefold() + header = "| Verification item | Status |" if language == "en" else "| 核验项目 | 状态 |" + first, second = (("Online sources check", "Real-case calibration") if language == "en" + else ("网上资料核对", "真实案例校准")) + lines = text.splitlines() + assert lines.count(header) == 1, where + start = lines.index(header) + table = list(takewhile(lambda line: line.startswith("|"), lines[start:])) + assert len(table) == 4, where + assert table[2].startswith(f"| {first} | ") and table[3].startswith(f"| {second} | "), where + remainder = "\n".join(lines[:start] + lines[start + len(table):]).casefold() for word in NO_WEB_WORDS: assert word.casefold() not in remainder, f"{where} 里出现了「{word}」" diff --git a/tests/test_report_wording_sanitizer_20261111.py b/tests/test_report_wording_sanitizer_20261111.py index 79236825..2f1d601a 100644 --- a/tests/test_report_wording_sanitizer_20261111.py +++ b/tests/test_report_wording_sanitizer_20261111.py @@ -7,7 +7,7 @@ import pytest from scripts.pl9_full_data_export import _sanitize_pl9_ai_density_markdown from scripts.pl9_reader_export import _sanitize_pl9_public_markdown -from scripts.report_render.audit_chapters import STATUS, VERIFICATION_LIMIT_LINE, render_audit_chapters +from scripts.report_render.audit_chapters import STATUS, render_audit_chapters from tests.public_chart_reports import PUBLIC_REPORT_CASES, public_chart_reports from tests.test_report_audit_chapters_20261107 import _packet from tests.test_report_no_web_wording_20261109 import _assert_clean @@ -41,7 +41,8 @@ def test_audit_filter_preserves_other_clauses_and_uses_empty_cell_marker() -> No def test_chinese_limit_line_matches_consult_literal() -> None: frontend = Path(__file__).resolve().parents[1] / "frontend/src/lib/consult-answer-basis.ts" match = re.search(r'CONSULT_VERIFICATION_LIMIT_LINE\s*=\s*"([^"]+)"', frontend.read_text(encoding="utf-8")) - assert match and VERIFICATION_LIMIT_LINE == match[1] + assert match and match[1] == "本次未完成外部资料与案例核验,候选窗口尚未据此确认。" + assert match[1] not in render_audit_chapters(_packet(), "zh") def test_both_reader_paths_translate_status_words_without_changing_field_keys_or_code() -> None: From cbd1b476a72aa9695f8dfc9b2e0fd122070d8fba Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Thu, 12 Nov 2026 23:14:30 +0800 Subject: [PATCH 3/3] docs(report): record #217 validation against staging --- docs/tasks/PROGRESS-reading-runtime-sources-20261112.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md b/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md index 1e6f097d..8035e56e 100644 --- a/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md +++ b/docs/tasks/PROGRESS-reading-runtime-sources-20261112.md @@ -49,3 +49,7 @@ Gitea #217,BUG-1861。计划评论 42256,认领评论 42374。任务书基 - 开工基线 `c55338f35916587ec9007d0786f370e5c29d0aa9`。Python 定向 64 项通过,覆盖 BPHS 拆分、两张公开盘的 PVR 事实包、报告审计、禁词范围和聊天提示。盘面、功能吉凶及校正另有 95 项与 3 个子测试通过。隐私守卫 62 项通过。 - 前端指定测试 24 项通过,另有聊天核验说明、报告导出与相关消费链 16 项通过。原 6 个提示块逐块校验,去掉维护者注释后的文本与基线一致。 - TypeScript 检查通过。Lint 为 0 错误、62 条既有警告。对照 `npm run build` 两边均成功,首页 `/` 保持 `○ Static`。从构建后的首页 HTML 提取 JS 和 CSS 资源,两边各 39 个文件,gzip 后 JS 515860 字节、CSS 90886 字节,均为 0% 变化。 +- Python 快速门 `--profile quick --skip-frontend-runtime` 退出 1,1463 项通过、2 项跳过、29 个子测试通过。3 项失败与开工基线对照一致,均在 `tests/test_upstream_technique_layers.py`,分别为公开盘固定值、大运注册表与 Kaala 的 PyJHora 对照。失败表现相同,分别为 `KeyError: 'seed'`、Windows `OSError: [Errno 22]`、`KeyError: 'seed'`。 +- 合入 staging `718bc991368cd3eb33de60e93c22600e80a139f1`(#216)后,验证实际合并树。功能吉凶拆分、两张公开盘、参与状态和报告事实包定向共 41 项通过。合入期间只需解决 Bug 历史的追加冲突,两单记录均保留。前端源文件和测试与上面的验证版本逐字节一致。 +- 前端全量按 `npm test` 同一 TSX 文件清单运行,每组并发 4。开工基线 3663 项,3636 通过、27 失败。分支 3665 项,3638 通过、27 失败。两组取消与跳过均为 0,退出码均为 1。27 项失败名称完全一致,无缺失断言。新增的 2 项提示与附录测试均通过。 +- 已验证提示实际拼接及个人报告服务端渲染。真实模型输出与浏览器交互留待独立验收。