814c924e4a
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Focused contracts for unresolved birth-time candidate profiles."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
SCRIPTS = os.path.join(os.path.dirname(__file__), "..", "scripts")
|
|
if SCRIPTS not in sys.path:
|
|
sys.path.insert(0, SCRIPTS)
|
|
|
|
from flexible_birth_time_profile import ( # noqa: E402
|
|
FlexibleBirthTimeProfileError,
|
|
build_flexible_birth_time_profile,
|
|
)
|
|
|
|
|
|
def _candidate(index: int, count: int) -> dict:
|
|
candidate_time = f"08:{index:02d}"
|
|
return {
|
|
"candidate_id": f"fictional-{index}",
|
|
"candidate_time": candidate_time,
|
|
"evidence": {
|
|
"D1.ascendant": "Aries",
|
|
"D10.ascendant": "Capricorn" if index < count - 1 else "Aquarius",
|
|
},
|
|
"trace": [{"kind": "fictional_candidate", "reference": f"fixture://{candidate_time}"}],
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize("count", [2, 15, 31])
|
|
def test_profile_supports_two_to_thirty_one_candidates_with_real_minute_variation(count: int) -> None:
|
|
candidates = [_candidate(index, count) for index in range(count)]
|
|
|
|
profile = build_flexible_birth_time_profile(
|
|
candidates,
|
|
source_reference={"review_id": "fictional-review"},
|
|
)
|
|
reversed_profile = build_flexible_birth_time_profile(
|
|
list(reversed(candidates)),
|
|
source_reference={"review_id": "fictional-review"},
|
|
)
|
|
|
|
assert profile == reversed_profile
|
|
assert profile["birth_time_window"]["candidate_count"] == count
|
|
assert profile["stable_evidence"] == {"D1.ascendant": "Aries"}
|
|
assert set(profile["sensitive_evidence"]) == {"D10.ascendant"}
|
|
for minute_values in profile["sensitive_evidence"].values():
|
|
assert len({json.dumps(value, sort_keys=True) for value in minute_values.values()}) > 1
|
|
|
|
|
|
@pytest.mark.parametrize("count", [1, 32])
|
|
def test_profile_rejects_candidate_counts_outside_two_to_thirty_one(count: int) -> None:
|
|
with pytest.raises(FlexibleBirthTimeProfileError, match="candidate_count_must_be_two_to_thirty_one"):
|
|
build_flexible_birth_time_profile(
|
|
[_candidate(index, max(count, 2)) for index in range(count)],
|
|
source_reference={"review_id": "fictional-review"},
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("status", ["approved", "confirmed"])
|
|
def test_profile_rejects_approved_or_confirmed_source_reference(status: str) -> None:
|
|
with pytest.raises(FlexibleBirthTimeProfileError, match="approved_or_confirmed_source_reference_forbidden"):
|
|
build_flexible_birth_time_profile(
|
|
[_candidate(0, 2), _candidate(1, 2)],
|
|
source_reference={"review_id": "fictional-review", "status": status},
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"field",
|
|
["approved_birth_time", "final_birth_time", "winner", "approval", "approval_authority"],
|
|
)
|
|
def test_profile_rejects_birth_minute_authority_fields(field: str) -> None:
|
|
candidates = [_candidate(0, 2), _candidate(1, 2)]
|
|
candidates[0]["evidence"][field] = "08:00"
|
|
|
|
with pytest.raises(FlexibleBirthTimeProfileError, match="candidate_window_authority_forbidden"):
|
|
build_flexible_birth_time_profile(
|
|
candidates,
|
|
source_reference={"review_id": "fictional-review"},
|
|
)
|