feat: add persistent personal report document v2

This commit is contained in:
Jesse_Chen
2026-08-15 05:10:37 +08:00
parent 9d2d79801d
commit 5012ff7212
48 changed files with 9301 additions and 932 deletions
+485
View File
@@ -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": "本命盘 D1Lahiri 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/A10Lahiri"
},
{
"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