from __future__ import annotations from datetime import date from scripts import active_rectification_events_v4 as v4 from scripts.rectification.contracts import normalize_rectification_request from scripts.rectification.scoring_service import calculation_spec, sha256 def _row(candidate_time: str, event_id: str, points: float): return { "time": candidate_time, "score": points, "evidence": [{ "event_id": event_id, "domain": "education", "candidate_time": candidate_time, "rule_ids": ["test"], "points": points, }], "missing_layers": [], } def test_v4_wrapper_uses_raman_spec_and_never_confirms_a_minute(monkeypatch) -> None: calls = [] def fake_compute(request, static_contexts=None): calls.append(request) event_id = request["events"][0]["id"] return [ _row("05:13", event_id, 10), _row("05:14", event_id, 9), _row("05:15", event_id, 8), ] monkeypatch.setattr("scripts.rectification.scoring_service.compute_event_candidate_rows", fake_compute) monkeypatch.setattr("scripts.rectification.scoring_service.compute_candidate_static_contexts", lambda request: []) result = v4.score_life_events_v4({ "birth_date": "1997-08-08", "start_time": "04:30", "end_time": "05:30", "lat": 36.419, "lon": 114.213, "tz": 8.0, "events": [{ "id": "00000000-0000-4000-8000-000000000001", "domain": "education", "event_kind": "education_milestone", "date_start": "2016-09-01", "date_end": "2016-09-30", "precision": "month", "summary": "大学入学", }], }) assert [call["events"][0]["date"] for call in calls] == ["2016-09-01", "2016-09-15", "2016-09-30"] assert result["can_confirm_exact_minute"] is False assert result["calculation_spec"]["ayanamsa"] == "raman" normalized = normalize_rectification_request({ "birth_date": "1997-08-08", "start_time": "04:30", "end_time": "05:30", "lat": 36.419, "lon": 114.213, "tz": 8.0, "events": [{ "id": "00000000-0000-4000-8000-000000000001", "domain": "education", "event_kind": "education_milestone", "date_start": "2016-09-01", "date_end": "2016-09-30", "precision": "month", "summary": "大学入学", }], }, today=date(2026, 7, 28)) assert result["calculation_spec_hash"] == sha256(calculation_spec(normalized)) def test_v4_api_validates_event_kind_and_date_boundaries(monkeypatch) -> None: from scripts.jyotish_api_server import BadRequest, JyotishAPIHandler captured = {} monkeypatch.setattr( "scripts.rectification.api_service.score_candidates", lambda request: captured.setdefault("request", request) or {}, ) handler = JyotishAPIHandler.__new__(JyotishAPIHandler) body = { "birth_date": "1997-08-08", "start_time": "05:00", "end_time": "05:30", "lat": 36.419, "lon": 114.213, "tz": 8, "events": [{ "id": "00000000-0000-4000-8000-000000000001", "domain": "relationship", "event_kind": "relationship_end", "date_start": "2020-10-01", "date_end": "2020-10-31", "precision": "month", "summary": "关系结束", }], } result = handler._compute_active_rectification_events_v4(body) assert result["endpoint"] == "active_rectification_events_v4" assert captured["request"]["events"][0]["date_end"] == "2020-10-31" import pytest with pytest.raises(BadRequest, match="event_kind does not match"): handler._compute_active_rectification_events_v4({ **body, "events": [{**body["events"][0], "event_kind": "relationship_start", "domain": "career"}], }) with pytest.raises(BadRequest, match="date_start must not exceed"): handler._compute_active_rectification_events_v4({ **body, "events": [{**body["events"][0], "date_start": "2020-11-01"}], })