coastwise / tests /test_rules.py
Stephen Lee
Implement advisory and context overlays
de1d671
Raw
History Blame Contribute Delete
3.32 kB
"""Rule composition tests."""
from datetime import date
from coastwise.data import get_rule_card
from coastwise.rules import default_context, compose_safety_result
from coastwise.schemas import CoastalRegion, HarvestStatus, RuleCard, UserIntent
def test_rule_card_result_includes_status_sources_freshness_and_next_action():
result = compose_safety_result(
get_rule_card("lingcod"),
default_context(today=date(2026, 6, 13)),
)
assert result.status is HarvestStatus.RULES_APPLY
assert result.display_name == "Lingcod"
assert result.source_links
assert result.cache_dates
assert "verify" in result.next_safe_action.lower()
def test_unknown_result_is_observe_only_without_source_requirement():
result = compose_safety_result(
get_rule_card("unknown"),
default_context(today=date(2026, 6, 13)),
)
assert result.status is HarvestStatus.OBSERVE_ONLY
assert result.source_links == ()
assert "observe" in result.next_safe_action.lower()
def test_stricter_exception_cards_do_not_fall_through_to_rules_apply():
for key in ("yelloweye_rockfish", "green_sturgeon", "ocean_salmon", "red_abalone"):
result = compose_safety_result(
get_rule_card(key),
default_context(
intent=UserIntent.THINKING_OF_HARVEST,
region=CoastalRegion.POINT_ARENA_TO_PIGEON_POINT,
today=date(2026, 6, 13),
),
)
assert result.status is HarvestStatus.DO_NOT_HARVEST
def test_mussel_harvest_during_quarantine_returns_do_not_harvest_warning():
result = compose_safety_result(
get_rule_card("mussels"),
default_context(
intent=UserIntent.THINKING_OF_HARVEST,
region=CoastalRegion.POINT_ARENA_TO_PIGEON_POINT,
today=date(2026, 6, 13),
),
)
assert result.status is HarvestStatus.DO_NOT_HARVEST
assert any("cooking" in warning.lower() for warning in result.advisory_warnings)
def test_stale_rules_apply_card_is_capped_at_verify_before_harvest():
card = RuleCard(
key="demo_fish",
display_name="Demo fish",
category="fish",
aliases=("demo fish",),
covered_species=(),
region_keys=("sf_coast_point_arena_to_pigeon_point",),
photo_supported=False,
default_status=HarvestStatus.RULES_APPLY,
short_answer="Rules apply.",
rule_notes=("Demo note.",),
safety_warnings=(),
source_names=("CDFW",),
source_urls=("https://wildlife.ca.gov/Fishing/Ocean/Regulations",),
cache_date=date(2026, 1, 1),
)
result = compose_safety_result(
card,
default_context(today=date(2026, 6, 13)),
)
assert result.stale
assert result.status is HarvestStatus.VERIFY_BEFORE_HARVEST
def test_san_francisco_bay_context_for_sf_coast_card_requires_verification():
result = compose_safety_result(
get_rule_card("lingcod"),
default_context(
intent=UserIntent.THINKING_OF_HARVEST,
region=CoastalRegion.SAN_FRANCISCO_BAY,
today=date(2026, 6, 13),
),
)
assert result.status is HarvestStatus.VERIFY_BEFORE_HARVEST
assert any("bay" in warning.lower() for warning in result.advisory_warnings)