Quest windows via quest_definition_windows (D-008)
Per IMPLEMENTATION-ORDER.md 1.4: a quest_definition_windows table (definition_id, window, due_time) declares which day windows a definition spans, one row per definition+window via the composite primary key; window is CHECK-constrained to morning/afternoon/evening. - const.py: WINDOW_MORNING/AFTERNOON/EVENING, QUEST_WINDOWS canonical order, WINDOW_CLOCK_RANGES with the documented boundaries and the boundary-to-later-window rule documented for Feature 07. - schema.py: windows DDL joins SCHEMA_V1_STATEMENTS; due_time is caller-validated strict HH:MM (DAO layer), matching the date policy. - migrations.py: migration 4 is a plain CREATE IF NOT EXISTS statement list (no rebuild needed for a new table). - dao_rules.py: QuestDefinitionsDao gains upsert_window (idempotent per window, due_time refresh in place), list_windows (const order), remove_window; _validate_time/_validate_window helpers. - tests: windows DDL shape/constraints (CHECK matrix, duplicate, unknown definition), DAO round-trips, const range shapes; leak guards extended to the new table.
This commit is contained in:
@@ -73,6 +73,36 @@ def test_panel_idle_timeout_config() -> None:
|
||||
assert const.DEFAULT_PANEL_IDLE_TIMEOUT > 0
|
||||
|
||||
|
||||
def test_quest_windows_canonical_order() -> None:
|
||||
"""QUEST_WINDOWS is exactly the three spellings in canonical order."""
|
||||
assert const.QUEST_WINDOWS == ("morning", "afternoon", "evening")
|
||||
assert const.WINDOW_MORNING == "morning"
|
||||
assert const.WINDOW_AFTERNOON == "afternoon"
|
||||
assert const.WINDOW_EVENING == "evening"
|
||||
# No duplicates, every name covered by its individual constant.
|
||||
assert len(set(const.QUEST_WINDOWS)) == 3
|
||||
|
||||
|
||||
def test_window_clock_ranges_cover_every_window() -> None:
|
||||
"""Each window has a strict HH:MM (start, end) range.
|
||||
|
||||
The ranges follow the documented boundaries (D-008): morning ends
|
||||
11:59, afternoon spans 12:00-17:00, evening 17:00-21:00, and each
|
||||
window's end equals the next window's start (the boundary belongs
|
||||
to the later window at classification time).
|
||||
"""
|
||||
assert const.WINDOW_CLOCK_RANGES == {
|
||||
"morning": ("00:00", "11:59"),
|
||||
"afternoon": ("12:00", "17:00"),
|
||||
"evening": ("17:00", "21:00"),
|
||||
}
|
||||
for window in const.QUEST_WINDOWS:
|
||||
start, end = const.WINDOW_CLOCK_RANGES[window]
|
||||
for value in (start, end):
|
||||
parsed = datetime.strptime(value, "%H:%M").time()
|
||||
assert parsed.strftime("%H:%M") == value
|
||||
|
||||
|
||||
def test_no_hardcoded_domain_or_db_filename_in_modules() -> None:
|
||||
"""Ensure no module other than const.py hardcodes DOMAIN string or SQLITE_DB_FILENAME."""
|
||||
pkg_dir = Path(const.__file__).parent
|
||||
|
||||
Reference in New Issue
Block a user