diff --git a/references/cross_project_contract/fixture_manifest.v1.json b/references/cross_project_contract/fixture_manifest.v1.json index ba93b53f..dd399d9d 100644 --- a/references/cross_project_contract/fixture_manifest.v1.json +++ b/references/cross_project_contract/fixture_manifest.v1.json @@ -4,8 +4,23 @@ "fixtures": [ { "id": "public_synthetic_delhi_1990_noon_mean_lahiri", - "birth": {"synthetic": true, "year": 1990, "month": 1, "day": 1, "hour": 12, "minute": 0, "second": 0, "lat": 28.6139, "lon": 77.209, "tz": 5.5}, - "effective": {"ayanamsa": "lahiri", "node_mode": "mean", "timezone_offset": 5.5}, + "birth": { + "synthetic": true, + "year": 1990, + "month": 1, + "day": 1, + "hour": 12, + "minute": 0, + "second": 0, + "lat": 28.6139, + "lon": 77.209, + "tz": 5.5 + }, + "effective": { + "ayanamsa": "lahiri", + "node_mode": "mean", + "timezone_offset": 5.5 + }, "compatibility_hash": "257042461fe303aa3bff5a8333f65090832ce8a2be395f038523838d724b474b" } ] diff --git a/references/cross_project_contract/sync_ledger.json b/references/cross_project_contract/sync_ledger.json index df0e369a..a9b67279 100644 --- a/references/cross_project_contract/sync_ledger.json +++ b/references/cross_project_contract/sync_ledger.json @@ -1,4 +1,27 @@ { "schema_version": 1, - "entries": [] + "entries": [ + { + "source_repository": "732642856/yinduzhanxing", + "source_commit": "f4d8148fc031cfa581bce7f30410fcd63fc89202", + "target_repository": "jesse-ux/Jyotisha", + "target_commit": "fd06bdc2eefa5547ed09968a218a8590df484bf3", + "change_class": "calculation_contract", + "copied_files": [ + "references/cross_project_contract/fixture_manifest.v1.json", + "references/cross_project_contract/sync_ledger.json", + "scripts/cross_project_contract.py", + "tests/test_cross_project_contract.py" + ], + "dependency_delta": "none", + "privacy_review": "pass: public synthetic fixture only; no production configuration or user data", + "focused_tests": [ + "python3 -m pytest -q tests/test_cross_project_contract.py", + "python3 scripts/cross_project_contract.py --require-match --format json", + "python3 scripts/public_release_privacy_scan.py --json" + ], + "hash_contract_result": "pass: 257042461fe303aa3bff5a8333f65090832ce8a2be395f038523838d724b474b", + "rollback": "git revert f4d8148 / git revert fd06bdc" + } + ] } diff --git a/scripts/cross_project_contract.py b/scripts/cross_project_contract.py index 6e29302b..96cf3585 100644 --- a/scripts/cross_project_contract.py +++ b/scripts/cross_project_contract.py @@ -19,9 +19,17 @@ from jyotish_engine import compute_chart_data PLANETS = ("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu") REQUIRED_LEDGER_FIELDS = { - "source_repository", "source_commit", "target_repository", "target_commit", - "change_class", "copied_files", "dependency_delta", "privacy_review", - "focused_tests", "hash_contract_result", "rollback", + "source_repository", + "source_commit", + "target_repository", + "target_commit", + "change_class", + "copied_files", + "dependency_delta", + "privacy_review", + "focused_tests", + "hash_contract_result", + "rollback", } @@ -69,8 +77,15 @@ def compatibility_payload(chart: dict[str, Any], fixture: dict[str, Any]) -> dic return { "fixture_id": fixture["id"], "birth": {key: value for key, value in fixture["birth"].items() if key != "synthetic"}, - "effective": fixture["effective"], - "ascendant": {"sign": chart["ascendant"]["sign"], "lon": _longitude(chart["ascendant"])}, + "effective": { + "ayanamsa": fixture["effective"]["ayanamsa"], + "node_mode": fixture["effective"]["node_mode"], + "timezone_offset": fixture["effective"]["timezone_offset"], + }, + "ascendant": { + "sign": chart["ascendant"]["sign"], + "lon": _longitude(chart["ascendant"]), + }, "planets": { planet: {"sign": chart["planets"][planet]["sign"], "lon": _longitude(chart["planets"][planet])} for planet in PLANETS @@ -79,7 +94,9 @@ def compatibility_payload(chart: dict[str, Any], fixture: dict[str, Any]) -> dic def compatibility_hash(chart: dict[str, Any], fixture: dict[str, Any]) -> str: - encoded = json.dumps(compatibility_payload(chart, fixture), ensure_ascii=True, sort_keys=True, separators=(",", ":")).encode("utf-8") + encoded = json.dumps( + compatibility_payload(chart, fixture), ensure_ascii=True, sort_keys=True, separators=(",", ":") + ).encode("utf-8") return hashlib.sha256(encoded).hexdigest() @@ -90,13 +107,24 @@ def evaluate_manifest(path: Path) -> dict[str, Any]: chart = _calculate_fixture_chart(fixture) actual = compatibility_hash(chart, fixture) expected = fixture["compatibility_hash"] - fixtures.append({"id": fixture["id"], "expected_compatibility_hash": expected, "actual_compatibility_hash": actual, "matches": actual == expected}) + fixtures.append( + { + "id": fixture["id"], + "expected_compatibility_hash": expected, + "actual_compatibility_hash": actual, + "matches": actual == expected, + } + ) return {"schema_version": 1, "manifest": str(path), "fixtures": fixtures, "matches": all(row["matches"] for row in fixtures)} def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--manifest", type=Path, default=ROOT / "references" / "cross_project_contract" / "fixture_manifest.v1.json") + parser.add_argument( + "--manifest", + type=Path, + default=ROOT / "references" / "cross_project_contract" / "fixture_manifest.v1.json", + ) parser.add_argument("--format", choices=("text", "json"), default="text") parser.add_argument("--require-match", action="store_true") args = parser.parse_args(argv) diff --git a/tests/test_cross_project_contract.py b/tests/test_cross_project_contract.py index 44044150..024420ce 100644 --- a/tests/test_cross_project_contract.py +++ b/tests/test_cross_project_contract.py @@ -1,4 +1,4 @@ -"""Public synthetic-fixture contract shared with the backup repository.""" +"""Public synthetic-fixture contract shared with the commercial repository.""" from __future__ import annotations @@ -20,15 +20,17 @@ LEDGER = ROOT / "references" / "cross_project_contract" / "sync_ledger.json" def test_public_fixture_manifest_has_complete_effective_settings() -> None: manifest = contract.load_manifest(MANIFEST) - fixture = manifest["fixtures"][0] + assert manifest["schema_version"] == 1 assert manifest["privacy_scope"] == "public_synthetic_only" + fixture = manifest["fixtures"][0] assert fixture["birth"]["synthetic"] is True assert fixture["effective"] == {"ayanamsa": "lahiri", "node_mode": "mean", "timezone_offset": 5.5} def test_local_calculation_matches_public_compatibility_hash() -> None: report = contract.evaluate_manifest(MANIFEST) + assert report["matches"] is True assert report["fixtures"][0]["matches"] is True @@ -38,7 +40,9 @@ def test_comparator_reports_tampered_expected_hash(tmp_path: Path) -> None: manifest["fixtures"][0]["compatibility_hash"] = "0" * 64 changed = tmp_path / "fixture_manifest.v1.json" changed.write_text(json.dumps(manifest), encoding="utf-8") + report = contract.evaluate_manifest(changed) + assert report["matches"] is False assert report["fixtures"][0]["matches"] is False @@ -47,16 +51,25 @@ def test_compatibility_payload_normalizes_engine_degree_field() -> None: fixture = contract.load_manifest(MANIFEST)["fixtures"][0] chart = { "ascendant": {"sign": "Aries", "degree": 1.25}, - "planets": {planet: {"sign": "Aries", "degree": float(index)} for index, planet in enumerate(contract.PLANETS)}, + "planets": { + planet: {"sign": "Aries", "degree": float(index)} + for index, planet in enumerate(contract.PLANETS) + }, } + payload = contract.compatibility_payload(chart, fixture) + assert payload["ascendant"]["lon"] == 1.25 assert payload["planets"]["Sun"]["lon"] == 0.0 def test_sync_ledger_requires_provenance_privacy_tests_hash_and_rollback() -> None: ledger = contract.load_ledger(LEDGER) - assert ledger == {"schema_version": 1, "entries": []} + + assert ledger["schema_version"] == 1 + assert len(ledger["entries"]) == 1 + assert contract.validate_ledger_entry(ledger["entries"][0]) == [] + assert ledger["entries"][0]["privacy_review"].startswith("pass:") missing = contract.validate_ledger_entry({"source_repository": "x"}) assert "target_commit" in missing assert "privacy_review" in missing