feat: add release docs and replay schemas
This commit is contained in:
@@ -61,6 +61,7 @@ For large architecture or release work, also read:
|
||||
| ERR-028 | Active birth-time rectification can stop at question generation and never narrow candidate clusters from user answers. | mitigated 2026-07-09 | `active_rectification_questions.score_answers()` must turn A/B/C/D answers into cluster rankings, next-round questions, and an explicit boundary that final rectification still needs candidate chart differences. |
|
||||
| ERR-029 | Basic git and premium cloud-drive skill packages can blur contents, privacy exclusions, and external-engine promises. | mitigated 2026-07-09 | `scripts/skill_release_manifest.py` must define edition contents, excluded private material, acceptance commands, and external-engine runtime boundaries before packaging. |
|
||||
| ERR-030 | Release packaging can misread non-ASCII tracked filenames when parsing quoted `git ls-files` output. | mitigated 2026-07-09 | Package builders must use `git ls-files -z` and decode NUL-separated paths before writing zip archives. |
|
||||
| ERR-031 | Premium skill zip can ship without user install prompts or replay schemas, leaving users and future oracle imports without a contract. | mitigated 2026-07-09 | `skill_release_package.py` must inject `INSTALL.md` and `USER_PROMPTS.md`; replay contracts must live in `references/real_case_calibration/` and `references/oracle/`. |
|
||||
|
||||
## Fragment Sweep Command Set
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Three Engine Same-Chart Parity Replay",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"case_id",
|
||||
"birth_data_policy",
|
||||
"engines",
|
||||
"comparison_rows",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"case_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"birth_data_policy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"public_case_only",
|
||||
"anonymized_private_case",
|
||||
"operator_local_only"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"VedAstro": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"official_raw_response_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"artifact_hash": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PyJHora_JHora": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"raw_output_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jyotishganit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"raw_output_path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"comparison_rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"section",
|
||||
"field",
|
||||
"local_value",
|
||||
"oracle_values",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"section": {
|
||||
"type": "string"
|
||||
},
|
||||
"field": {
|
||||
"type": "string"
|
||||
},
|
||||
"local_value": {},
|
||||
"oracle_values": {
|
||||
"type": "object"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"match",
|
||||
"mismatch",
|
||||
"blocked",
|
||||
"not_comparable"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"not_started",
|
||||
"blocked",
|
||||
"partial",
|
||||
"complete"
|
||||
]
|
||||
},
|
||||
"blocked_reason": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Real Case Calibration Catalog",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"case_id",
|
||||
"source",
|
||||
"chart_signature",
|
||||
"event_outcomes",
|
||||
"similarity",
|
||||
"replay"
|
||||
],
|
||||
"properties": {
|
||||
"case_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url",
|
||||
"source_grade",
|
||||
"license_or_quote_boundary"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"source_grade": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"primary",
|
||||
"verified_secondary",
|
||||
"forum_claim",
|
||||
"unverified"
|
||||
]
|
||||
},
|
||||
"license_or_quote_boundary": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chart_signature": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lagna": {
|
||||
"type": "string"
|
||||
},
|
||||
"moon_sign": {
|
||||
"type": "string"
|
||||
},
|
||||
"d9_lagna": {
|
||||
"type": "string"
|
||||
},
|
||||
"ul": {
|
||||
"type": "string"
|
||||
},
|
||||
"a7": {
|
||||
"type": "string"
|
||||
},
|
||||
"a10": {
|
||||
"type": "string"
|
||||
},
|
||||
"notable_yogas": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"event_outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"event_type",
|
||||
"event_date",
|
||||
"outcome"
|
||||
],
|
||||
"properties": {
|
||||
"event_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string"
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string"
|
||||
},
|
||||
"source_excerpt_note": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"similarity": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"score": {
|
||||
"type": "number"
|
||||
},
|
||||
"matching_factors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"dissimilar_factors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"outcome_replay_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"not_started",
|
||||
"blocked",
|
||||
"partial",
|
||||
"complete"
|
||||
]
|
||||
},
|
||||
"conflict_notes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"do_not_use_for_prediction": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,34 @@ except ModuleNotFoundError: # pragma: no cover - direct script execution
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SKIP_PREFIXES = ("scratch/", "references/open_source_sources/", ".git/", "__pycache__/")
|
||||
SKIP_NAMES = {".env", ".env.local"}
|
||||
GENERATED_DOCS = {
|
||||
"INSTALL.md": """# Jyotish Skill Install
|
||||
|
||||
1. Unzip this package into a local folder.
|
||||
2. Run `python3 scripts/public_release_privacy_scan.py`.
|
||||
3. Run `python3 scripts/user_invocation_acceptance_check.py`.
|
||||
4. If the check passes, load this folder as a Codex skill/plugin or call `mcp_server.py`.
|
||||
5. VedAstro cloud evidence is optional. Without `official_raw_response`, reports must say `official_blocked` or `local_fallback`.
|
||||
|
||||
Do not add private birth data, API keys, or desktop oracle screenshots to this package.
|
||||
""",
|
||||
"USER_PROMPTS.md": """# User Prompts
|
||||
|
||||
## User Has No Question
|
||||
|
||||
请根据我的出生信息先运行统一主链,生成 evidence_packet、guided_topics 和 Technique Audit Table。
|
||||
不要反问我想看什么;请先给出 3-5 个最值得继续看的方向,并附可直接复制的问题。
|
||||
|
||||
## High-Rigor Reading
|
||||
|
||||
请使用 strict_workflow,并在输出中标明 VedAstro / PyJHora-JHora / jyotishganit / Real Case Calibration 的状态。
|
||||
如果没有 VedAstro official_raw_response,请标记 official_blocked 或 local_fallback。
|
||||
|
||||
## Birth-Time Rectification
|
||||
|
||||
请使用主动问询式校时:先生成候选时间扫描和选择题,我只回答 A/B/C/D。
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
def _git_files() -> list[str]:
|
||||
@@ -59,6 +87,7 @@ def build_package_plan(edition: str = "premium_cloud_drive") -> dict[str, Any]:
|
||||
"privacy_scan_status": privacy["status"],
|
||||
"file_count": len(files),
|
||||
"files": files,
|
||||
"generated_files": sorted(GENERATED_DOCS),
|
||||
"boundary": "Dry-run plan only; use --write-zip to create a local zip, then upload manually if desired.",
|
||||
}
|
||||
|
||||
@@ -71,6 +100,8 @@ def write_zip(edition: str, output: Path) -> dict[str, Any]:
|
||||
with zipfile.ZipFile(output, "w", compression=zipfile.ZIP_DEFLATED) as archive:
|
||||
for rel in plan["files"]:
|
||||
archive.write(ROOT / rel, rel)
|
||||
for rel, text in GENERATED_DOCS.items():
|
||||
archive.writestr(rel, text)
|
||||
return {**plan, "mode": "write_zip", "zip_path": str(output)}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _load(path: str) -> dict:
|
||||
return json.loads((ROOT / path).read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_real_case_calibration_schema_defines_replay_contract() -> None:
|
||||
schema = _load("references/real_case_calibration/catalog.schema.json")
|
||||
props = schema["properties"]
|
||||
|
||||
assert schema["title"] == "Real Case Calibration Catalog"
|
||||
assert {"case_id", "source", "chart_signature", "event_outcomes", "similarity", "replay"} <= set(props)
|
||||
assert props["source"]["properties"]["source_grade"]["enum"] == ["primary", "verified_secondary", "forum_claim", "unverified"]
|
||||
assert "outcome_replay_status" in props["replay"]["properties"]
|
||||
assert "do_not_use_for_prediction" in props["replay"]["properties"]
|
||||
|
||||
|
||||
def test_three_engine_parity_replay_schema_defines_raw_oracle_slots() -> None:
|
||||
schema = _load("references/oracle/three_engine_parity_replay.schema.json")
|
||||
engines = schema["properties"]["engines"]["properties"]
|
||||
|
||||
assert schema["title"] == "Three Engine Same-Chart Parity Replay"
|
||||
assert {"VedAstro", "PyJHora_JHora", "jyotishganit"} <= set(engines)
|
||||
assert "official_raw_response_path" in engines["VedAstro"]["properties"]
|
||||
assert "raw_output_path" in engines["PyJHora_JHora"]["properties"]
|
||||
assert "comparison_rows" in schema["properties"]
|
||||
assert "blocked_reason" in schema["properties"]
|
||||
@@ -29,4 +29,12 @@ def test_skill_release_package_can_write_zip(tmp_path) -> None:
|
||||
names = set(archive.namelist())
|
||||
assert "SKILL.md" in names
|
||||
assert "scripts/skill_release_manifest.py" in names
|
||||
assert "INSTALL.md" in names
|
||||
assert "USER_PROMPTS.md" in names
|
||||
assert ".env.local" not in names
|
||||
with zipfile.ZipFile(target) as archive:
|
||||
install = archive.read("INSTALL.md").decode("utf-8")
|
||||
prompts = archive.read("USER_PROMPTS.md").decode("utf-8")
|
||||
assert "python3 scripts/user_invocation_acceptance_check.py" in install
|
||||
assert "guided_topics" in prompts
|
||||
assert "official_blocked" in prompts
|
||||
|
||||
Reference in New Issue
Block a user