Compare commits

..
5 Commits
Author SHA1 Message Date
jesse-ux f8e0fc3659 docs(report): record #215 verification after decision
Independent Staging Quality Gate / validate-python (pull_request) Successful in 7m1s
Independent Staging Quality Gate / validate-frontend (pull_request) Successful in 7m12s
Independent Staging Quality Gate / publish (pull_request) Skipped
2026-11-12 21:44:08 +08:00
jesse-ux 24152df0b4 Merge remote-tracking branch 'origin/staging' into codex/purpose-stability-20261112
# Conflicts:
#	docs/BUG_HISTORY.md
2026-11-12 21:29:07 +08:00
jesse-ux 292f248125 fix(report): separate purpose stability from minute boundaries (#215) 2026-11-12 21:28:55 +08:00
jesse-ux 16641c5159 docs(report): record #215 test contract decision 2026-11-12 21:20:23 +08:00
ClaudeandClaude Opus 5.5 d65ccce04e docs(tasks): brief for #215 purpose-stability
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXozsiu43ob7B8UZCmDM
2026-11-12 21:01:07 +08:00
7 changed files with 374 additions and 16 deletions
+13
View File
@@ -25085,3 +25085,16 @@
- 防复发:后端验证单来源不成窗、条件事件不能桥接窗口,前端验证同向不抬级和候选说明。
- 关联记录:#209、#190、BUG-1601、BUG-1650、BUG-1732、BUG-1830、BUG-1842。
- 修复版本:`codex/annual-narayana-conditional-20261112`。
## BUG-1858 | 报告用途稳定性由一分钟分盘边界检查推定
- 状态:fixed-pending-verify(待独立验收)。
- 首次发现 / 最近更新:2026-11-12 / 2026-11-12。
- 影响面:个人报告 `report_evidence_grade_v1` 每类结论的用途稳定性账本。
- 现象和触发:事实包报用途未评估,但一分钟内无分盘边界时账本填稳定。应期窗口无分盘依赖也被填稳定。
- 根因:`claim_grade` 从分盘边界检查推导用途稳定性。BUG-1851 的既有回归核对分级上限和分盘边界,还把边界值当作用途稳定性,未覆盖两者不一致。
- 修复:分别记录用途评估和一分钟边界检查,增加未评估披露,保留必需分盘贴边时的 D 上限。
- 验证:合成事实包复现原实现八项误报稳定。Claude 确认同步两条旧断言后,任务书三文件合跑 20 项通过。快速门有 3 项失败,均在 staging 定向复现。见 `docs/tasks/PROGRESS-purpose-stability-20261112.md`。
- 防复发:新增回归覆盖未评估、应期窗口、必需分盘贴边及缺失边界。保留旧测试的 D6/D30 上限检查,分别核对 D6 的边界状态和 D30 的披露。
- 关联记录:#215、BUG-1851、BUG-1848。
- 修复版本:`codex/purpose-stability-20261112`。
@@ -0,0 +1,27 @@
# 报告用途稳定性 · 2026-11-12
Gitea #215,BUG-1858。首次按评论 42245 认领。评论 42285 确认两条断言可同步更新,认领评论 42293。任务书基线为 `1ba0364a7a8c0f964c3e21c21cb304aaa1899375`。
## 已核实
- 用完整合成事实复现。所有分盘最近边界大于 60 分钟、事实包用途稳定性为 `not_evaluated` 时,旧账本将八类结论全标为 `stable`。八类上限仍为 C。
- 账本从事实包读取用途稳定性,默认 `not_evaluated`。事实包给出 `stable` 时,应期窗口仍记为 `not_evaluated`。分盘边界独立列在 `ledger.boundary_check`,包含规则、状态和原数值。必需 D6 距边界 0.25 分钟时上限仍为 D。
- 已检索 `frontend/src` 及后端消费者。前端等级判断读取 `evidence_grades.claims` 的 `cap`。未找到消费本单 `v:` 行的 `stable` 字面值的模块。
- 四项新增回归在本地候选上通过。第一项在原实现失败,实际为八项 `stable`。
- 拍板前合跑任务书指定的三个文件,19 项通过、1 项失败。原 staging 上两个既有文件 16 项均通过。候选失败是下表第一条。运行在第一条断言中止,第二条已用同一夹具独立核对。
## 既有断言变更
两条断言在 `tests/test_report_evidence_grade_20261112.py` 的同一个测试中。Claude 2026-11-12 答复确认可同步更新。
| 位置 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `test_missing_required_layer_or_boundary_varga_gives_d` 的必需 D6 | `ledger.purpose_stability == "boundary_sensitive"` | `ledger.purpose_stability == "not_evaluated"`,在 `boundary_check.rows` 验证 D6 为 `boundary_sensitive`,保留上限 D 断言 | 任务书 #215 第 1、5 条;Claude 2026-11-12 答复。 |
| 同测试的仅核对 D30 | `must_disclose == ["v:D30"]` | `must_disclose` 同时包含 `v:D30` 与 `purpose_stability_not_evaluated`,保留上限 C 断言 | 任务书 #215 第 1、5 条;Claude 2026-11-12 答复。 |
## 最终验证
- 合入本分支的验证基线为 staging `2f374fff281622f342151a97fa6f6d758de74cc8`,保留了该分支上的 Bug 记录。
- 更新既有断言后,任务书指定三文件合跑 20 项通过,四项新增回归均通过。
- Python 快速门退出码 1,1,463 项通过、3 项失败、2 项跳过、29 项子测试通过。失败均在 `test_upstream_technique_layers.py`,在同一 staging 提交定向复跑重现。
- 仓库隐私检查 62 项通过。
@@ -0,0 +1,71 @@
# TASK:上限账本的用途稳定性不再由一分钟规则冒充(2026-11-12)
- Gitea:#215
- 分支:`codex/purpose-stability-20261112`,基于 staging `1ba0364a7a8c0f964c3e21c21cb304aaa1899375`
- Bug 编号:BUG-1858
- 验收: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」都指这份文件。
## 背景(她 §2 P0-1)
`scripts/report_render/evidence_grade.py` 为报告解读的每类结论算上限,账本里有一项 `purpose_stability`。问题在于两处结果对不上:
- 事实包里 `birth_precision.purpose_stability` 是 `not_evaluated`,因为按用途区间的合同还没接入。
- 账本里却写 `stable`。
原因是 `claim_grade` 用 `_varga_stability` 的结果推出 `purpose_stability`:分盘上升最近的换宫距离大于 `CONFIRMED_TOLERANCE_MINUTES = 1.0`,就算 `stable`。Jobs 样例的 8 项全是 `stable`;Obama 样例 7 项 `stable`,1 项 `boundary_sensitive`。
她的裁定:这个一分钟比较只是在 `birth_record_minute_v1` 规则下检查附近有没有边界,不能证明结论在真实出生区间内稳定。`timing_window` 更不能在没有精度依赖的情况下标成稳定。
## 要改的文件
- `scripts/report_render/evidence_grade.py`
- 新建 `tests/test_evidence_grade_purpose_stability_20261112.py`
- `tests/test_report_evidence_grade_20261112.py`:只在断言写的是旧的 `stable` 时改,并在 PROGRESS 逐条列出
- `docs/BUG_HISTORY.md`:只在末尾追加一条
- `docs/tasks/PROGRESS-purpose-stability-20261112.md`
## 要做的
1. 账本里的 `purpose_stability` 改成直接取事实包的 `birth_precision.purpose_stability`,取不到就填 `not_evaluated`。不能再由分盘边界推出来。
2. 分盘边界检查的结果单独记在账本新字段 `boundary_check` 里,形如 `{"policy": "birth_record_minute_v1", "rows": [...]}`。`rows` 保留现有的 `nearest_change_minutes`、`tolerance_minutes` 和状态(`clear` 表示一分钟内没有换宫,另有 `boundary_sensitive`、`not_evaluated`、`missing`)。
- `required` / `checked` 里 `v:` 依赖行的 `state`:`stable` 改名为 `clear_at_tolerance`。
- 其余状态不变。
- 前端读不读这个字符串,你要用 grep 核对 `frontend/src`。如果有读取,只能在 PROGRESS 报告,不许改前端,选需拍板。
3. 上限规则不变:
- 必需分盘落在边界内(`boundary_sensitive`),照旧给 D;
- `not_evaluated` 不会因此把结论降到 D(她:未评估不意味着整份报告一律 D)。
4. `timing_window` 的账本里,`purpose_stability` 在任何情况下都不能是 `stable`。
5. 新增一个 `must_disclose` 项 `purpose_stability_not_evaluated`:只要 `purpose_stability` 不是 `stable`,每类结论都带上这一项。
## 不要碰
- `frontend/**`、`references/**`、`scripts/report_render/reading_facts.py`、`scripts/report_render/birth_precision_margins.py`
- 冻结文件
## 验收标准(写进新测试)
1. 用合成 facts 测:`minute_confirmed=True`,所有分盘边界都大于 60 分钟,`birth_precision.purpose_stability="not_evaluated"`。此时 8 类结论的账本 `purpose_stability` 全是 `not_evaluated`,上限仍是 C。
2. 事实包里给出 `birth_precision.purpose_stability="stable"` 时,`timing_window` 仍不是 `stable`,其他类照抄 `stable`。
3. `v:D8` 落在 0.25 分钟内、并且是必需依赖时(自己造一个把 D8 设为必需的场景;做不到就用 D6),该类上限是 D。`boundary_check.rows` 里能看到 0.25。
4. 旧代码上,第 1 条必须失败。在 PROGRESS 里记下旧代码的结果。
5. `tests/test_report_evidence_grade_20261112.py` 和 `tests/test_reading_facts_v3_20261112.py` 全部通过。
## 自测命令(仓库根目录)
```
python3 -m pytest -q tests/test_evidence_grade_purpose_stability_20261112.py tests/test_report_evidence_grade_20261112.py tests/test_reading_facts_v3_20261112.py
python3 scripts/run_quality_gate.py --profile quick --skip-frontend-runtime
```
## 何时停下来选「需拍板」
- 前端或别的模块依赖 `stable` 这个字面值。
- 只有改事实包结构才能完成。
@@ -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. 每份样例提供完整快照哈希、测试命令/结果、分段修复记录与可读审计附录。区分“本地测试通过”“暂存部署成功”“占星语义已审”三个结论。
本轮资料源预检通过,包含外部适配器诊断、远端可见性与既有治理测试。该结果只说明本仓预检,不是网站算法或新拦截器测试通过。本轮不修改冻结导出器、不改网站服务器、不重新输出个人命盘。
+20 -14
View File
@@ -33,7 +33,7 @@ GRADE_CONTRACT = "report_evidence_grade_v1"
GRADE_ORDER = ("A", "B", "C", "D")
# Product policy, versioned: how far the true birth instant may sit from the
# recorded one. A minute-confirmed record is taken as +/- 1 minute; an
# unconfirmed one has no stated tolerance, so varga stability is not evaluated.
# unconfirmed one has no stated tolerance, so the local boundary is not checked.
PRECISION_POLICY = "birth_record_minute_v1"
CONFIRMED_TOLERANCE_MINUTES = 1.0
@@ -42,7 +42,7 @@ MISSING_STATES = {"blocked", "withheld", "missing", "calculation_failed", "missi
# Dependency kinds:
# ("p", domain, id) domain participation row
# ("s", id) shared technique row
# ("v", code) varga ascendant stable within the birth-time tolerance
# ("v", code) varga ascendant boundary relative to the birth-time tolerance
# ("t", key) timing / transit / annual block present
# Each claim type: route (her router section), section ids it may appear in,
# required deps (missing -> D) and checked deps (missing -> disclosed only).
@@ -124,7 +124,7 @@ def _shared(facts: dict, item_id: str) -> str:
return "missing"
def _varga_stability(facts: dict, code: str) -> tuple[str, dict[str, Any]]:
def _varga_boundary(facts: dict, code: str) -> tuple[str, dict[str, Any]]:
precision = facts.get("birth_precision") or {}
margin = (precision.get("ascendant_margins") or {}).get(code)
if not facts.get("minute_confirmed"):
@@ -134,7 +134,7 @@ def _varga_stability(facts: dict, code: str) -> tuple[str, dict[str, Any]]:
nearest = min(float(margin.get("before_minutes", 0)), float(margin.get("after_minutes", 0)))
detail = {"policy": PRECISION_POLICY, "nearest_change_minutes": nearest,
"tolerance_minutes": CONFIRMED_TOLERANCE_MINUTES}
return ("stable" if nearest > CONFIRMED_TOLERANCE_MINUTES else "boundary_sensitive"), detail
return ("clear_at_tolerance" if nearest > CONFIRMED_TOLERANCE_MINUTES else "boundary_sensitive"), detail
def _block_state(facts: dict, key: str) -> str:
@@ -168,7 +168,7 @@ def _evaluate(facts: dict, dep: tuple, sensitive: set[str]) -> dict[str, Any]:
if dep[1] in sensitive and state == "executed":
state = "parameter_sensitive"
elif kind == "v":
state, detail = _varga_stability(facts, dep[1])
state, detail = _varga_boundary(facts, dep[1])
else:
state = _block_state(facts, dep[1])
return {"id": _dep_id(dep), "state": state, **({"detail": detail} if detail else {})}
@@ -189,15 +189,20 @@ def claim_grade(facts: dict, claim_type: str) -> dict[str, Any]:
required = [_evaluate(facts, dep, sensitive) for dep in spec["required"]]
checked = [_evaluate(facts, dep, sensitive) for dep in spec["checked"]]
missing_required = [row["id"] for row in required if _is_missing(row)]
missing_checked = [row["id"] for row in checked if _is_missing(row)]
must_disclose = [row["id"] for row in checked if _is_missing(row)]
sensitive_rows = [row["id"] for row in required + checked if row["state"] == "parameter_sensitive"]
stability = [row for row in required + checked if row["id"].startswith("v:")]
if any(row["state"] == "boundary_sensitive" for row in stability):
purpose = "boundary_sensitive"
elif any(row["state"] == "not_evaluated" for row in stability):
boundary_rows = []
for row in required + checked:
if row["id"].startswith("v:"):
details = {key: value for key, value in row["detail"].items() if key != "policy"}
state = "clear" if row["state"] == "clear_at_tolerance" else row["state"]
boundary_rows.append({"id": row["id"], "state": state, **details})
precision = facts.get("birth_precision") or {}
purpose = precision.get("purpose_stability") or "not_evaluated"
if claim_type == "timing_window" and purpose == "stable":
purpose = "not_evaluated"
else:
purpose = "stable"
if purpose != "stable":
must_disclose.append("purpose_stability_not_evaluated")
cap = "D" if missing_required else "C"
reasons = (
[f"required dependency unavailable: {item}" for item in missing_required]
@@ -210,14 +215,15 @@ def claim_grade(facts: dict, claim_type: str) -> dict[str, Any]:
"reasons": reasons,
"required": required,
"checked": checked,
"must_disclose": missing_checked,
"must_disclose": must_disclose,
"parameter_sensitive": sensitive_rows,
# Six axes (§5.2), raw enums; a missing value never defaults to good.
# Six axes (§5.2) plus the local boundary check.
"ledger": {
"case_fit": "none",
"method_maturity": "source_bounded" if not missing_required else "dependency_missing",
"independent_agreement": "not_assessed",
"purpose_stability": purpose,
"boundary_check": {"policy": PRECISION_POLICY, "rows": boundary_rows},
"external_calculation_check": "not_done",
"contradiction": [f"{row.get('planet')}: natural {row.get('natural')} / functional {row.get('functional')}"
for row in _contradictions(facts)],
@@ -0,0 +1,70 @@
"""Keep the product's minute boundary check separate from purpose stability."""
from scripts.report_render.evidence_grade import CLAIM_TYPES, claim_grade, evidence_grades
from tests.test_report_evidence_grade_20261112 import _facts
def _complete_facts(purpose_stability):
facts = _facts()
for row in facts["domains"]["health"]["participation"]:
if row["id"] == "Badhaka":
row["state"] = "executed"
precision = facts["birth_precision"]
precision["purpose_stability"] = purpose_stability
for margin in precision["ascendant_margins"].values():
margin.update(before_minutes=90.0, after_minutes=120.0)
return facts
def test_clear_minute_boundary_does_not_establish_purpose_stability():
claims = evidence_grades(_complete_facts("not_evaluated"))["claims"]
assert len(claims) == 8
assert {name: claim["ledger"]["purpose_stability"] for name, claim in claims.items()} == {
name: "not_evaluated" for name in CLAIM_TYPES
}
for claim in claims.values():
assert claim["cap"] == "C"
assert "purpose_stability_not_evaluated" in claim["must_disclose"]
character = claims["character_structure"]
assert character["required"][0]["state"] == "clear_at_tolerance"
assert next(row for row in character["checked"] if row["id"] == "v:D9")["state"] == "clear_at_tolerance"
assert character["ledger"]["boundary_check"]["policy"] == "birth_record_minute_v1"
assert character["ledger"]["boundary_check"]["rows"][0] == {
"id": "v:D1", "state": "clear", "nearest_change_minutes": 90.0, "tolerance_minutes": 1.0,
}
def test_explicit_stability_does_not_make_timing_stable():
claims = evidence_grades(_complete_facts("stable"))["claims"]
for name, claim in claims.items():
purpose = "not_evaluated" if name == "timing_window" else "stable"
assert claim["ledger"]["purpose_stability"] == purpose
assert ("purpose_stability_not_evaluated" in claim["must_disclose"]) == (purpose != "stable")
assert claims["timing_window"]["ledger"]["boundary_check"]["rows"] == []
def test_required_boundary_still_caps_the_claim_at_d():
facts = _complete_facts("not_evaluated")
facts["birth_precision"]["ascendant_margins"]["D6"]["before_minutes"] = 0.25
claim = claim_grade(facts, "health_pressure")
assert claim["cap"] == "D"
assert claim["ledger"]["purpose_stability"] == "not_evaluated"
row = next(row for row in claim["ledger"]["boundary_check"]["rows"] if row["id"] == "v:D6")
assert row == {
"id": "v:D6", "state": "boundary_sensitive", "nearest_change_minutes": 0.25, "tolerance_minutes": 1.0,
}
def test_missing_purpose_defaults_to_unassessed_independently_of_boundary_status():
facts = _complete_facts(None)
del facts["birth_precision"]["ascendant_margins"]["D9"]
claim = claim_grade(facts, "character_structure")
assert claim["cap"] == "C"
assert claim["ledger"]["purpose_stability"] == "not_evaluated"
assert claim["must_disclose"] == ["v:D9", "purpose_stability_not_evaluated"]
assert claim["ledger"]["boundary_check"]["rows"][-1]["state"] == "missing"
facts["minute_confirmed"] = False
claim = claim_grade(facts, "character_structure")
assert claim["cap"] == "C"
assert {row["state"] for row in claim["ledger"]["boundary_check"]["rows"]} == {"not_evaluated"}
+4 -2
View File
@@ -69,12 +69,14 @@ def test_missing_required_layer_or_boundary_varga_gives_d():
boundary["birth_precision"]["ascendant_margins"]["D6"] = {"before_minutes": 0.4, "after_minutes": 9.0}
health = claim_grade(boundary, "health_pressure")
assert health["cap"] == "D"
assert health["ledger"]["purpose_stability"] == "boundary_sensitive"
assert health["ledger"]["purpose_stability"] == "not_evaluated"
d6 = next(row for row in health["ledger"]["boundary_check"]["rows"] if row["id"] == "v:D6")
assert d6["state"] == "boundary_sensitive"
checked_only = _facts()
checked_only["birth_precision"]["ascendant_margins"]["D30"] = {"before_minutes": 0.4, "after_minutes": 9.0}
disclosed = claim_grade(checked_only, "health_pressure")
assert disclosed["cap"] == "C"
assert disclosed["must_disclose"] == ["v:D30"]
assert {"v:D30", "purpose_stability_not_evaluated"} <= set(disclosed["must_disclose"])
def test_unconfirmed_birth_time_is_not_evaluated_not_assumed_stable():