feat: complete verifiable birth-time rectification flow
This commit is contained in:
@@ -1,8 +1,126 @@
|
||||
from scripts.minute_rectification_holdout_validator import validate
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
|
||||
from scripts.minute_rectification_blind_eval import _candidate_moments, implementation_sha256, summarize_trials
|
||||
from scripts.minute_rectification_holdout_validator import DEFAULT_MANIFEST, validate
|
||||
|
||||
|
||||
def test_empty_public_minute_protocol_blocks_verified_claims() -> None:
|
||||
def _manifest() -> dict:
|
||||
return json.loads(DEFAULT_MANIFEST.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_seeded_public_minute_protocol_remains_blocked_below_twenty_cases() -> None:
|
||||
report = validate()
|
||||
assert report["status"] == "blocked_awaiting_public_aa_cases"
|
||||
assert report["verified_minute_claim_allowed"] is False
|
||||
assert report["valid_public_aa_cases"] == 1
|
||||
assert report["invalid_cases"] == []
|
||||
|
||||
|
||||
def test_frozen_implementation_hash_matches_manifest() -> None:
|
||||
manifest = _manifest()
|
||||
frozen = manifest["frozen_scoring"]
|
||||
assert implementation_sha256(frozen["files"]) == frozen["implementation_sha256"]
|
||||
|
||||
|
||||
def test_validator_accepts_the_new_sealed_schema_version(tmp_path: Path) -> None:
|
||||
manifest = _manifest()
|
||||
manifest["schema_version"] = "minute-rectification-holdout-v3"
|
||||
manifest["source_audit_status"] = "passed_before_freeze"
|
||||
path = tmp_path / "v3.json"
|
||||
path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||
|
||||
report = validate(path)
|
||||
|
||||
assert "unsupported_schema_version" not in report["manifest_errors"]
|
||||
|
||||
|
||||
def test_v3_validator_requires_content_source_audit_before_freeze(tmp_path: Path) -> None:
|
||||
manifest = _manifest()
|
||||
manifest["schema_version"] = "minute-rectification-holdout-v3"
|
||||
manifest["source_audit_status"] = "invalidated_after_replay"
|
||||
path = tmp_path / "invalid-source-audit.json"
|
||||
path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||
|
||||
report = validate(path)
|
||||
|
||||
assert "source_content_audit_not_passed_before_freeze" in report["manifest_errors"]
|
||||
assert report["status"] == "blocked_awaiting_public_aa_cases"
|
||||
|
||||
|
||||
def test_validator_rejects_tuning_case_and_non_independent_event_source(tmp_path: Path) -> None:
|
||||
manifest = deepcopy(_manifest())
|
||||
case = manifest["cases"][0]
|
||||
case["excluded_from_tuning"] = False
|
||||
case["events"][0]["source"]["url"] = case["birth"]["source"]["url"]
|
||||
path = tmp_path / "invalid.json"
|
||||
path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||
|
||||
report = validate(path)
|
||||
errors = report["invalid_case_details"][0]["errors"]
|
||||
assert "case_not_excluded_from_tuning" in errors
|
||||
assert "event_1_source_not_independent_of_birth" in errors
|
||||
assert report["valid_public_aa_cases"] == 0
|
||||
|
||||
|
||||
def test_validator_requires_adjacent_false_minutes_on_both_sides(tmp_path: Path) -> None:
|
||||
manifest = deepcopy(_manifest())
|
||||
manifest["cases"][0]["false_minute_offsets"] = [1, 2, 5, 10]
|
||||
path = tmp_path / "one-sided.json"
|
||||
path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||
|
||||
errors = validate(path)["invalid_case_details"][0]["errors"]
|
||||
assert "false_minutes_do_not_cover_both_sides" in errors
|
||||
assert "false_minutes_missing_adjacent_controls" in errors
|
||||
|
||||
|
||||
def test_metric_summary_reports_accuracy_error_and_rejection() -> None:
|
||||
trials = [
|
||||
{
|
||||
"true_rank": 1,
|
||||
"minute_error": 0,
|
||||
"false_confirmation": False,
|
||||
"insufficient_evidence_rejected": True,
|
||||
"would_confirm": True,
|
||||
},
|
||||
{
|
||||
"true_rank": 4,
|
||||
"minute_error": 4,
|
||||
"false_confirmation": True,
|
||||
"insufficient_evidence_rejected": False,
|
||||
"would_confirm": True,
|
||||
},
|
||||
]
|
||||
gates = {
|
||||
"top_1_rate_minimum": 0.5,
|
||||
"top_3_rate_minimum": 0.5,
|
||||
"mean_absolute_minute_error_maximum": 2.0,
|
||||
"false_confirmation_rate_maximum": 0.5,
|
||||
"correct_insufficient_evidence_rejection_rate_minimum": 0.5,
|
||||
}
|
||||
|
||||
report = summarize_trials(trials, gates)
|
||||
|
||||
assert report["metrics"] == {
|
||||
"top_1_rate": 0.5,
|
||||
"top_3_rate": 0.5,
|
||||
"mean_absolute_minute_error": 2.0,
|
||||
"false_confirmation_rate": 0.5,
|
||||
"correct_insufficient_evidence_rejection_rate": 0.5,
|
||||
"confirmation_coverage_rate": 1.0,
|
||||
}
|
||||
assert report["metric_gates_passed"] is True
|
||||
|
||||
|
||||
def test_blind_candidate_moments_preserve_real_dates_across_midnight() -> None:
|
||||
case = {
|
||||
"candidate_radius_minutes": 5,
|
||||
"birth": {"date": "2000-01-02", "time": "00:03"},
|
||||
}
|
||||
|
||||
moments = _candidate_moments(case)
|
||||
|
||||
assert moments[0].isoformat() == "2000-01-01T23:58:00"
|
||||
assert moments[5].isoformat() == "2000-01-02T00:03:00"
|
||||
assert moments[-1].isoformat() == "2000-01-02T00:08:00"
|
||||
|
||||
Reference in New Issue
Block a user