feat: add persistent personal report document v2
This commit is contained in:
+485
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"schemaVersion": "report_document.v2",
|
||||
"reportId": "3f2b1c4a-8d6e-4f0a-9c2b-5a7e1d3f8b40",
|
||||
"reportType": "personal_full",
|
||||
"presentationMode": "default",
|
||||
"generatedAt": "2026-08-06T08:00:00Z",
|
||||
"subject": {
|
||||
"displayName": "测试用户(合成资料)",
|
||||
"birthTimeStatus": "confirmed",
|
||||
"birthPlaceLabel": "北京(合成测试地点)"
|
||||
},
|
||||
"provenance": {
|
||||
"skillSourceCommit": "9034e1967032d09c0a1b2c3d4e5f60718293a4b5",
|
||||
"skillSnapshotSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"calculationHash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"evidenceHash": "b4f6d95916b5253054a9c64958eb3deec6ee5b54b0286465e7a986ba701132cf",
|
||||
"reportContractVersion": "2",
|
||||
"skillName": "jyotish-personal-report",
|
||||
"skillVersion": "1.0.0"
|
||||
},
|
||||
"executiveSummary": {
|
||||
"headline": "事业与财富主题的多系统证据较一致",
|
||||
"summary": "本报告基于服务端计算的本命盘与分盘证据。事业主题在 D10 与 A10 双层呈现一致信号,财富主题在 D2 与 D11 呈现中等强度信号;婚恋主题需用户历史事件核验;时机主题因外部参照未闭环而降级为 blocked,不给出确定性应期。",
|
||||
"priorities": [
|
||||
"先核验事业主题的三条历史事件证据",
|
||||
"婚恋主题等待用户提供可核验的过往关系时间点",
|
||||
"时机主题在外部参照闭环前不做确定性预测"
|
||||
],
|
||||
"overallClaimStatus": "multi_system_consensus",
|
||||
"evidenceRefs": [
|
||||
"ev-d1-foundation",
|
||||
"ev-fbm",
|
||||
"ev-vimshottari"
|
||||
]
|
||||
},
|
||||
"charts": [
|
||||
{
|
||||
"id": "D1",
|
||||
"title": "本命盘 D1(Lahiri Ayanamsa)",
|
||||
"claimStatus": "multi_system_consensus",
|
||||
"houses": [
|
||||
{
|
||||
"houseNumber": 1,
|
||||
"sign": "狮子座",
|
||||
"occupants": [
|
||||
"上升点"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 2,
|
||||
"sign": "处女座",
|
||||
"occupants": []
|
||||
},
|
||||
{
|
||||
"houseNumber": 3,
|
||||
"sign": "天秤座",
|
||||
"occupants": [
|
||||
"水星"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 4,
|
||||
"sign": "天蝎座",
|
||||
"occupants": [
|
||||
"金星"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 5,
|
||||
"sign": "射手座",
|
||||
"occupants": [
|
||||
"太阳"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 6,
|
||||
"sign": "摩羯座",
|
||||
"occupants": [
|
||||
"火星"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 7,
|
||||
"sign": "水瓶座",
|
||||
"occupants": []
|
||||
},
|
||||
{
|
||||
"houseNumber": 8,
|
||||
"sign": "双鱼座",
|
||||
"occupants": [
|
||||
"木星"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 9,
|
||||
"sign": "白羊座",
|
||||
"occupants": [
|
||||
"土星"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 10,
|
||||
"sign": "金牛座",
|
||||
"occupants": [
|
||||
"月亮"
|
||||
]
|
||||
},
|
||||
{
|
||||
"houseNumber": 11,
|
||||
"sign": "双子座",
|
||||
"occupants": []
|
||||
},
|
||||
{
|
||||
"houseNumber": 12,
|
||||
"sign": "巨蟹座",
|
||||
"occupants": [
|
||||
"罗睺"
|
||||
]
|
||||
}
|
||||
],
|
||||
"planets": [
|
||||
{
|
||||
"name": "太阳",
|
||||
"sign": "射手座",
|
||||
"longitudeDegrees": 248.5,
|
||||
"houseNumber": 5,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "月亮",
|
||||
"sign": "金牛座",
|
||||
"longitudeDegrees": 42.1,
|
||||
"houseNumber": 10,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "火星",
|
||||
"sign": "摩羯座",
|
||||
"longitudeDegrees": 288.3,
|
||||
"houseNumber": 6,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "水星",
|
||||
"sign": "天秤座",
|
||||
"longitudeDegrees": 190.7,
|
||||
"houseNumber": 3,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "木星",
|
||||
"sign": "双鱼座",
|
||||
"longitudeDegrees": 341.9,
|
||||
"houseNumber": 8,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "金星",
|
||||
"sign": "天蝎座",
|
||||
"longitudeDegrees": 222.4,
|
||||
"houseNumber": 4,
|
||||
"retrograde": false
|
||||
},
|
||||
{
|
||||
"name": "土星",
|
||||
"sign": "白羊座",
|
||||
"longitudeDegrees": 11.8,
|
||||
"houseNumber": 9,
|
||||
"retrograde": true
|
||||
},
|
||||
{
|
||||
"name": "罗睺",
|
||||
"sign": "巨蟹座",
|
||||
"longitudeDegrees": 102.6,
|
||||
"houseNumber": 12,
|
||||
"retrograde": true
|
||||
},
|
||||
{
|
||||
"name": "计都",
|
||||
"sign": "摩羯座",
|
||||
"longitudeDegrees": 282.6,
|
||||
"houseNumber": 6,
|
||||
"retrograde": true
|
||||
}
|
||||
],
|
||||
"evidenceRefs": [
|
||||
"ev-d1-foundation",
|
||||
"ev-fbm"
|
||||
]
|
||||
}
|
||||
],
|
||||
"thematicNarrative": [
|
||||
{
|
||||
"id": "theme-general",
|
||||
"theme": "general",
|
||||
"title": "综合主题",
|
||||
"narrative": "综合主题以 D1、本命功能性吉凶星与已闭合的强度证据为基础。可以用于整理长期倾向和观察重点,但不延伸到缺少正式分盘数据的具体领域结论。",
|
||||
"actions": [
|
||||
"把报告中的倾向与已发生事件逐项核对"
|
||||
],
|
||||
"caveats": [
|
||||
"未请求或未闭合的主题不从综合结论外推"
|
||||
],
|
||||
"claimStatus": "multi_system_consensus",
|
||||
"evidenceRefs": [
|
||||
"ev-d1-foundation",
|
||||
"ev-fbm",
|
||||
"ev-shadbala-total"
|
||||
]
|
||||
}
|
||||
],
|
||||
"evidenceAppendix": {
|
||||
"expandedByDefault": false,
|
||||
"techniqueAudit": [
|
||||
{
|
||||
"id": "ev-mevg-web",
|
||||
"techniqueId": "mevg_global_web_evidence",
|
||||
"techniqueName": "MEVG / Global Web Evidence",
|
||||
"status": "partial",
|
||||
"used": true,
|
||||
"notes": "外部资料采集完成度 60%,来源分级已记录,冲突已进入 conflicts 列表"
|
||||
},
|
||||
{
|
||||
"id": "ev-real-case",
|
||||
"techniqueId": "real_case_calibration",
|
||||
"techniqueName": "Real Case Calibration",
|
||||
"status": "partial",
|
||||
"used": true,
|
||||
"notes": "10 个公开案例可回放:事业 5、婚恋 5;财富案例缺失"
|
||||
},
|
||||
{
|
||||
"id": "ev-fbm",
|
||||
"techniqueId": "functional_benefic_malefic",
|
||||
"techniqueName": "Functional Benefic/Malefic",
|
||||
"status": "verified",
|
||||
"used": true
|
||||
},
|
||||
{
|
||||
"id": "ev-vimshottari",
|
||||
"techniqueId": "vimshottari_dasha",
|
||||
"techniqueName": "Vimshottari Dasha",
|
||||
"status": "verified",
|
||||
"used": true
|
||||
},
|
||||
{
|
||||
"id": "ev-narayana",
|
||||
"techniqueId": "narayana_dasha",
|
||||
"techniqueName": "Narayana Dasha",
|
||||
"status": "verified",
|
||||
"used": true,
|
||||
"notes": "与 Vimshottari 双轨交叉"
|
||||
},
|
||||
{
|
||||
"id": "ev-d10-a10",
|
||||
"techniqueId": "d10_a10",
|
||||
"techniqueName": "D10 + A10(事业分盘)",
|
||||
"status": "verified",
|
||||
"used": true
|
||||
},
|
||||
{
|
||||
"id": "ev-d2-d11",
|
||||
"techniqueId": "d2_d11",
|
||||
"techniqueName": "D2 / D11(财富分盘)",
|
||||
"status": "verified",
|
||||
"used": true
|
||||
},
|
||||
{
|
||||
"id": "ev-d9-ul",
|
||||
"techniqueId": "d9_ul",
|
||||
"techniqueName": "D9 + UL(婚恋分盘)",
|
||||
"status": "verified",
|
||||
"used": true
|
||||
},
|
||||
{
|
||||
"id": "ev-shadbala",
|
||||
"techniqueId": "shadbala",
|
||||
"techniqueName": "Shadbala",
|
||||
"status": "partial",
|
||||
"used": true,
|
||||
"notes": "内部总量一致;外部绝对数值对照未闭环"
|
||||
},
|
||||
{
|
||||
"id": "ev-ashtakavarga",
|
||||
"techniqueId": "ashtakavarga",
|
||||
"techniqueName": "Ashtakavarga",
|
||||
"status": "partial",
|
||||
"used": true
|
||||
}
|
||||
],
|
||||
"conflicts": [
|
||||
{
|
||||
"id": "ev-conflict-1",
|
||||
"description": "Vimshottari 与 Narayana Dasha 在 2031 年前后的应期窗口存在分歧",
|
||||
"impact": "时机主题降级为 blocked,不输出确定性应期",
|
||||
"status": "unresolved"
|
||||
},
|
||||
{
|
||||
"id": "ev-conflict-2",
|
||||
"description": "Shadbala 内部总量与外部参照数值尚未对齐",
|
||||
"impact": "Shadbala 行标记为 partial,不参与绝对强度结论",
|
||||
"status": "partial"
|
||||
}
|
||||
],
|
||||
"calculationEvidence": [
|
||||
{
|
||||
"id": "ev-d1-foundation",
|
||||
"label": "D1 本命基础盘",
|
||||
"value": "十二宫 houseNumber 1..12 完整,行星经度由服务端计算结果提供",
|
||||
"source": "服务端 D1 结构化排盘数据(Lahiri)"
|
||||
},
|
||||
{
|
||||
"id": "ev-career-d10-a10",
|
||||
"label": "D10 与 A10 事业证据",
|
||||
"value": "D10 月亮入第十宫,A10 同宫主星呼应;双盘一致",
|
||||
"source": "服务端排盘 varga D10/A10(Lahiri)"
|
||||
},
|
||||
{
|
||||
"id": "ev-career-dasha-boundary",
|
||||
"label": "Vimshottari 大运边界",
|
||||
"value": "当前大运:木星-土星;起始边界已记录",
|
||||
"source": "服务端 Dasha 计算"
|
||||
},
|
||||
{
|
||||
"id": "ev-wealth-d2-d11",
|
||||
"label": "D2 与 D11 财富证据",
|
||||
"value": "D2 第二宫与 D11 第十一宫证据链相互印证",
|
||||
"source": "服务端排盘 varga D2/D11"
|
||||
},
|
||||
{
|
||||
"id": "ev-ashtakavarga-wealth",
|
||||
"label": "Ashtakavarga 财富相关宫位",
|
||||
"value": "第二宫与第十一宫 Bhinna Ashtakavarga 点数高于均值",
|
||||
"source": "服务端 Ashtakavarga 计算"
|
||||
},
|
||||
{
|
||||
"id": "ev-marriage-d9-ul",
|
||||
"label": "D9 与 UL 婚恋证据",
|
||||
"value": "D9 第七宫状态与 UL 指示存在呼应,需用户核验",
|
||||
"source": "服务端排盘 varga D9 + UL"
|
||||
},
|
||||
{
|
||||
"id": "ev-timing-vd-md-ad",
|
||||
"label": "Vimshottari 小运边界",
|
||||
"value": "木星-土星-月亮 小运边界已计算,仅作校准素材",
|
||||
"source": "服务端 Dasha 计算"
|
||||
},
|
||||
{
|
||||
"id": "ev-timing-narayana",
|
||||
"label": "Narayana Dasha 边界",
|
||||
"value": "Narayana 大运边界已计算,与 Vimshottari 存在分歧",
|
||||
"source": "服务端 Narayana Dasha 计算"
|
||||
},
|
||||
{
|
||||
"id": "ev-shadbala-total",
|
||||
"label": "Shadbala 总量",
|
||||
"value": "各星 Shadbala 总量内部一致,外部对照 partial",
|
||||
"source": "服务端 Shadbala 计算"
|
||||
}
|
||||
],
|
||||
"blockedTechniques": [
|
||||
"Sphuta 判定层(外部数值参照缺失)",
|
||||
"Tajika 命名组合事件判定(无金标案例)"
|
||||
]
|
||||
},
|
||||
"disclaimer": "本报告由计算引擎与模型共同生成,仅用于传统文化研究与个人参考,不构成医疗、法律或投资建议。任何涉及健康、法律、财务的决策请咨询对应领域的专业人士。报告中的时间预测均受证据完整度限制,blocked 内容不代表确定性结论。",
|
||||
"depth": "standard",
|
||||
"requestedThemes": [
|
||||
"general",
|
||||
"career",
|
||||
"wealth",
|
||||
"timing"
|
||||
],
|
||||
"natalFoundation": {
|
||||
"title": "本命基础",
|
||||
"narrative": "本命基础只整理服务端已经提供的 D1、功能性吉凶星与强度证据,不自行补算缺失分盘。当前证据适合描述稳定倾向,不支持脱离主题证据作确定性事件预测。",
|
||||
"keyFactors": [
|
||||
"D1 十二宫结构完整,可作为报告的基础盘展示",
|
||||
"功能性吉凶星判定已执行,并参与结论置信度控制",
|
||||
"Shadbala 内部结果可用,但外部绝对数值对照仍为 partial"
|
||||
],
|
||||
"caveats": [
|
||||
"出生时间状态为 confirmed,但外部引擎并未全部闭环"
|
||||
],
|
||||
"claimStatus": "multi_system_consensus",
|
||||
"evidenceRefs": [
|
||||
"ev-d1-foundation",
|
||||
"ev-fbm",
|
||||
"ev-shadbala-total"
|
||||
]
|
||||
},
|
||||
"currentPhase": {
|
||||
"title": "当前阶段",
|
||||
"phaseLabel": "木星—土星阶段(仅作证据化阶段描述)",
|
||||
"narrative": "Vimshottari 与 Narayana Dasha 的边界都已进入证据附录,但两套系统对更细应期仍有分歧。因此这里只描述当前阶段的长期建设取向,不给出未经闭合的具体日期承诺。",
|
||||
"timingNotes": [
|
||||
"优先记录真实事件时间点,供后续双轨校准"
|
||||
],
|
||||
"caveats": [
|
||||
"具体应期仍受外部参照闭环与历史事件核验限制"
|
||||
],
|
||||
"claimStatus": "parameter_sensitive",
|
||||
"evidenceRefs": [
|
||||
"ev-career-dasha-boundary",
|
||||
"ev-timing-vd-md-ad",
|
||||
"ev-timing-narayana",
|
||||
"ev-conflict-1"
|
||||
]
|
||||
},
|
||||
"actionNotes": [
|
||||
{
|
||||
"id": "record-events",
|
||||
"title": "记录可核验事件",
|
||||
"note": "持续记录职业、财务和重要关系事件的实际发生时间,用于后续校准,而不是把当前报告当作确定性预言。",
|
||||
"priority": "now",
|
||||
"evidenceRefs": [
|
||||
"ev-real-case",
|
||||
"ev-timing-vd-md-ad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "close-external-comparison",
|
||||
"title": "完成外部对照",
|
||||
"note": "在扩展事业与财富正文前,先补齐正式分盘结构和外部数值对照。",
|
||||
"priority": "next",
|
||||
"evidenceRefs": [
|
||||
"ev-mevg-web",
|
||||
"ev-conflict-2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"blockedConflictDisclosure": [
|
||||
{
|
||||
"theme": "career",
|
||||
"title": "事业主题暂缓展开",
|
||||
"reason": "证据附录保留了 D10/A10 摘要,但当前 ReportDocument 没有可供结构化渲染的 D10 chart data;为避免把摘要扩写成未经支持的完整章节,本主题保持 blocked。",
|
||||
"missingEvidence": [
|
||||
"结构化 D10 chart data",
|
||||
"完整外部参照闭环"
|
||||
],
|
||||
"conflictNotes": [
|
||||
"Shadbala 外部绝对数值仍未对齐"
|
||||
],
|
||||
"evidenceRefs": [
|
||||
"ev-career-d10-a10",
|
||||
"ev-conflict-2"
|
||||
],
|
||||
"claimStatus": "blocked"
|
||||
},
|
||||
{
|
||||
"theme": "wealth",
|
||||
"title": "财富主题暂缓展开",
|
||||
"reason": "证据附录只有 D2/D11 摘要,没有可渲染的 D2 与 D11 结构化 chart data,也缺少足够的历史财务事件校准,因此不输出财富正文。",
|
||||
"missingEvidence": [
|
||||
"结构化 D2 chart data",
|
||||
"结构化 D11 chart data",
|
||||
"历史财务事件校准"
|
||||
],
|
||||
"conflictNotes": [],
|
||||
"evidenceRefs": [
|
||||
"ev-wealth-d2-d11",
|
||||
"ev-ashtakavarga-wealth",
|
||||
"ev-real-case"
|
||||
],
|
||||
"claimStatus": "blocked"
|
||||
},
|
||||
{
|
||||
"theme": "timing",
|
||||
"title": "具体应期存在冲突",
|
||||
"reason": "Vimshottari 与 Narayana Dasha 对 2031 年前后的窗口存在未解决分歧;现有引用足以披露冲突,不足以支持具体日期结论。",
|
||||
"missingEvidence": [
|
||||
"双轨应期冲突的外部闭环",
|
||||
"更多用户历史事件锚点"
|
||||
],
|
||||
"conflictNotes": [
|
||||
"两套 Dasha 的边界方向不完全一致"
|
||||
],
|
||||
"evidenceRefs": [
|
||||
"ev-timing-vd-md-ad",
|
||||
"ev-timing-narayana",
|
||||
"ev-conflict-1"
|
||||
],
|
||||
"claimStatus": "blocked"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
"""Immutable package and policy contract for jyotish-personal-report."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PACKAGE_ROOT = ROOT / "skills/jyotish-personal-report"
|
||||
VERSION_ROOT = PACKAGE_ROOT / "versions/1.0.0"
|
||||
REGISTRY = ROOT / "skills/skill-package-registry.json"
|
||||
HASH_DOMAIN = b"jyotisha-skill-package-v1\0"
|
||||
|
||||
|
||||
def _update_length_prefixed(digest, label: str, value: bytes) -> None:
|
||||
digest.update(f"{label}:{len(value)}\0".encode())
|
||||
digest.update(value)
|
||||
digest.update(b"\0")
|
||||
|
||||
|
||||
def _package_sha256(package_directory: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
digest.update(HASH_DOMAIN)
|
||||
files = sorted(
|
||||
(path for path in package_directory.rglob("*") if path.is_file()),
|
||||
key=lambda path: path.relative_to(package_directory).as_posix(),
|
||||
)
|
||||
assert files
|
||||
for path in files:
|
||||
assert not path.is_symlink()
|
||||
relative = path.relative_to(package_directory).as_posix().encode("utf-8")
|
||||
executable = b"1" if path.stat().st_mode & 0o111 else b"0"
|
||||
_update_length_prefixed(digest, "path", relative)
|
||||
_update_length_prefixed(digest, "executable", executable)
|
||||
_update_length_prefixed(digest, "bytes", path.read_bytes())
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def test_personal_report_skill_is_versioned_and_registry_hash_matches_package_bytes() -> None:
|
||||
registry = json.loads(REGISTRY.read_text(encoding="utf-8"))
|
||||
matches = [
|
||||
package
|
||||
for package in registry["packages"]
|
||||
if package["name"] == "jyotish-personal-report" and package["status"] == "active"
|
||||
]
|
||||
assert matches == [{
|
||||
"name": "jyotish-personal-report",
|
||||
"version": "1.0.0",
|
||||
"sha256": _package_sha256(VERSION_ROOT),
|
||||
"sourceCommit": None,
|
||||
"packagePath": "skills/jyotish-personal-report/versions/1.0.0",
|
||||
"status": "active",
|
||||
}]
|
||||
assert (PACKAGE_ROOT / "SKILL.md").read_bytes() == (VERSION_ROOT / "SKILL.md").read_bytes()
|
||||
assert (PACKAGE_ROOT / "references/report-contract.md").read_bytes() == (
|
||||
VERSION_ROOT / "references/report-contract.md"
|
||||
).read_bytes()
|
||||
assert not (VERSION_ROOT / "scripts").exists()
|
||||
|
||||
|
||||
def test_personal_report_skill_encodes_evidence_only_two_stage_and_safety_boundaries() -> None:
|
||||
skill = (VERSION_ROOT / "SKILL.md").read_text(encoding="utf-8")
|
||||
contract = (VERSION_ROOT / "references/report-contract.md").read_text(encoding="utf-8")
|
||||
combined = f"{skill}\n{contract}"
|
||||
|
||||
for required in (
|
||||
"ReportEvidenceBundleV2",
|
||||
"claimCards",
|
||||
"blockedSections",
|
||||
"planner → writer",
|
||||
"concise",
|
||||
"standard",
|
||||
"deep",
|
||||
"research",
|
||||
"requestedThemes",
|
||||
"聊天历史",
|
||||
"工具轨迹",
|
||||
"内部文件路径",
|
||||
"禁止 HTML",
|
||||
"不得计算、外推、缩窄、扩展或编造日期",
|
||||
"禁止医疗诊断",
|
||||
"禁止确定性财务承诺",
|
||||
):
|
||||
assert required in combined
|
||||
|
||||
assert "每个 requested theme" in skill
|
||||
assert "恰好" in skill
|
||||
assert "不得从宫位、星座、度数、分盘或 Dasha 自行推导含义" in skill
|
||||
assert "research` 不代表可以联网或补证" in skill
|
||||
Reference in New Issue
Block a user