#!/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]) def test_profile_supports_two_to_fifteen_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, 16]) def test_profile_rejects_candidate_counts_outside_two_to_fifteen(count: int) -> None: with pytest.raises(FlexibleBirthTimeProfileError, match="candidate_count_must_be_two_to_fifteen"): 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"}, )