feat: integrate minute rectification safeguards
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""Stable, privacy-safe identities for birth-time rectification evidence."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any
|
||||
|
||||
INPUT_CONTRACT_VERSION = "rectification-input-v1"
|
||||
REQUIRED_FIELDS = ("year", "month", "day", "hour", "minute", "lat", "lon", "tz")
|
||||
STABILITY_OFFSETS = (-5, -2, -1, 1, 2, 5)
|
||||
|
||||
|
||||
def _canonical_json(value: Any) -> str:
|
||||
return json.dumps(value, ensure_ascii=True, sort_keys=True, separators=(",", ":"))
|
||||
|
||||
|
||||
def canonical_birth_input(case: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Normalize only calculation-bearing fields using deployed defaults."""
|
||||
missing = [field for field in REQUIRED_FIELDS if case.get(field) is None]
|
||||
if missing:
|
||||
raise ValueError(f"missing rectification input fields: {', '.join(missing)}")
|
||||
|
||||
year, month, day = int(case["year"]), int(case["month"]), int(case["day"])
|
||||
hour, minute, second = int(case["hour"]), int(case["minute"]), int(case.get("second", 0))
|
||||
datetime(year, month, day, hour, minute, second)
|
||||
node_mode = str(case.get("node_mode", case.get("nodeMode", "mean"))).strip().lower()
|
||||
if node_mode not in {"mean", "true"}:
|
||||
raise ValueError("node_mode must be mean or true")
|
||||
|
||||
return {
|
||||
"year": year,
|
||||
"month": month,
|
||||
"day": day,
|
||||
"hour": hour,
|
||||
"minute": minute,
|
||||
"second": second,
|
||||
"lat": float(case["lat"]),
|
||||
"lon": float(case["lon"]),
|
||||
"tz": float(case["tz"]),
|
||||
"ayanamsa": str(case.get("ayanamsa", "lahiri")).strip().lower(),
|
||||
"node_mode": node_mode,
|
||||
}
|
||||
|
||||
|
||||
def candidate_input_fingerprint(case: dict[str, Any]) -> str:
|
||||
payload = {
|
||||
"schema_version": INPUT_CONTRACT_VERSION,
|
||||
"calculation_input": canonical_birth_input(case),
|
||||
}
|
||||
return hashlib.sha256(_canonical_json(payload).encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def stability_probe_contract(case: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Materialize adjacent-minute identities without claiming that they passed."""
|
||||
baseline = canonical_birth_input(case)
|
||||
center = datetime(
|
||||
baseline["year"],
|
||||
baseline["month"],
|
||||
baseline["day"],
|
||||
baseline["hour"],
|
||||
baseline["minute"],
|
||||
baseline["second"],
|
||||
)
|
||||
probes = []
|
||||
for offset in STABILITY_OFFSETS:
|
||||
moment = center + timedelta(minutes=offset)
|
||||
probe = {
|
||||
**baseline,
|
||||
"year": moment.year,
|
||||
"month": moment.month,
|
||||
"day": moment.day,
|
||||
"hour": moment.hour,
|
||||
"minute": moment.minute,
|
||||
"second": moment.second,
|
||||
}
|
||||
probes.append({
|
||||
"offset_minutes": offset,
|
||||
"input_fingerprint": candidate_input_fingerprint(probe),
|
||||
})
|
||||
return {
|
||||
"scope": "candidate_minute_stability_contract",
|
||||
"status": "pending_score_comparison",
|
||||
"baseline_input_fingerprint": candidate_input_fingerprint(baseline),
|
||||
"probes": probes,
|
||||
"minute_confirmation_allowed": False,
|
||||
"blocker": "public_blind_minute_holdout_not_closed",
|
||||
"boundary": (
|
||||
"Probe identities are reproducible inputs, not evidence that a minute passed "
|
||||
"stability or outcome validation."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _semantic_normalize(value: Any, *, parent_key: str | None = None) -> Any:
|
||||
if isinstance(value, dict):
|
||||
return {
|
||||
key: _semantic_normalize(item, parent_key=key)
|
||||
for key, item in sorted(value.items())
|
||||
}
|
||||
if isinstance(value, list):
|
||||
normalized = [_semantic_normalize(item, parent_key=parent_key) for item in value]
|
||||
if parent_key in {"gives", "receives"}:
|
||||
return sorted(normalized, key=_canonical_json)
|
||||
return normalized
|
||||
return value
|
||||
|
||||
|
||||
def semantic_evidence_hash(value: Any) -> str:
|
||||
"""Hash known order-insensitive evidence while raw artifact hashes remain intact."""
|
||||
normalized = _semantic_normalize(value)
|
||||
return hashlib.sha256(_canonical_json(normalized).encode("utf-8")).hexdigest()
|
||||
Reference in New Issue
Block a user