1.4 Quest windows via quest_definition_windows (D-008) #47

Member

Implements IMPLEMENTATION-ORDER.md §1.4 (decision D-008). Stacks on PR #46 (1.3 multi-assignee) — earlier commits included until those PRs merge.

Changes

  • const.py: WINDOW_MORNING/AFTERNOON/EVENING, QUEST_WINDOWS canonical order, WINDOW_CLOCK_RANGES (morning 00:00–11:59, afternoon 12:00–17:00, evening 17:00–21:00) with the boundary-to-later-window rule documented for Feature 07 materialisation.
  • schema.py: quest_definition_windows (definition_id, window, due_time), window CHECK-constrained to the three spellings, composite primary key = one window per definition; due_time caller-validated strict HH:MM at the DAO.
  • migrations.py: migration 4 = plain CREATE IF NOT EXISTS (new table, no rebuild).
  • dao_rules.py: QuestDefinitionsDao.upsert_window (idempotent per window, due_time refreshed in place), list_windows (const order), remove_window; _validate_time/_validate_window helpers.
  • tests: DDL shape/FK/CHECK matrix, duplicate + unknown-definition constraints, DAO round-trips, const range shapes; leak guards extended to the new table.

Verification

uv run pytest: 806 passed.

Closes task c2a8597a (feature 14, task 1.4).

Implements IMPLEMENTATION-ORDER.md §1.4 (decision D-008). Stacks on PR #46 (1.3 multi-assignee) — earlier commits included until those PRs merge. ## Changes - **const.py**: WINDOW_MORNING/AFTERNOON/EVENING, QUEST_WINDOWS canonical order, WINDOW_CLOCK_RANGES (morning 00:00–11:59, afternoon 12:00–17:00, evening 17:00–21:00) with the boundary-to-later-window rule documented for Feature 07 materialisation. - **schema.py**: quest_definition_windows (definition_id, window, due_time), window CHECK-constrained to the three spellings, composite primary key = one window per definition; due_time caller-validated strict HH:MM at the DAO. - **migrations.py**: migration 4 = plain CREATE IF NOT EXISTS (new table, no rebuild). - **dao_rules.py**: QuestDefinitionsDao.upsert_window (idempotent per window, due_time refreshed in place), list_windows (const order), remove_window; _validate_time/_validate_window helpers. - **tests**: DDL shape/FK/CHECK matrix, duplicate + unknown-definition constraints, DAO round-trips, const range shapes; leak guards extended to the new table. ## Verification uv run pytest: 806 passed. Closes task c2a8597a (feature 14, task 1.4).
dev_agent added 3 commits 2026-09-15 10:05:56 -04:00
Per design/IMPLEMENTATION-ORDER.md 1.1 and decision D-007: the domain
model takes the quest vocabulary pre-release. SCHEMA_V1 now creates
quest_definitions/quest_instances directly; DAO classes, records and
error messages follow (QuestDefinitionsDao, QuestInstancesDao). The
migration runner gains migration 2, an async-callable step that detects
surviving task_* tables on dev machines and ALTER TABLE RENAMES them
inside the migration transaction, with FK clauses rewritten by SQLite.
Migration 1's content rewrite is legal because nothing was ever
shipped; dev databases stamped version 1 ride migration 2 up to 2.
Per IMPLEMENTATION-ORDER.md 1.3: a quest_definition_assignees table
(definition_id, child_id) with a composite primary key and FKs to
quest_definitions and children replaces the single child_id column on
quest_definitions.

- schema.py: definitions DDL loses child_id; new assignees table joins
  SCHEMA_V1_STATEMENTS; the definitions table body is extracted to
  QUEST_DEFINITIONS_TABLE_SQL so the rebuild migration cannot drift
  from the canonical shape.
- migrations.py: callable migrations now own their transaction and
  stamp via stamp_schema_version(database, version), because the
  rebuild must bracket itself with PRAGMA foreign_keys OFF/ON. New
  migration 3 creates the assignees table and, when a pre-D-008
  quest_definitions still carries child_id, rebuilds the table via
  SQLite's canonical procedure (create, copy, move assignees, drop,
  rename), verifies PRAGMA foreign_key_check inside the transaction,
  and stamps. Migration 2 converted to the new callable contract.
- dao_rules.py: QuestDefinitionsDao.create drops the child_id argument
  and applies assignee_child_ids atomically; set_assignee is replaced
  by add_assignee (idempotent, active-child validated under the
  connection lock), remove_assignee and list_assignees; list_by_child
  reads through the assignees table.
- dao_instances.py: upsert validates the child against
  quest_definition_assignees instead of the definitions column.
- tests: schema shape tests for the assignees table (columns, PK, FKs,
  duplicate/unknown constraints); DAO tests rewritten for the new
  assignment API; migration tests for the v2 -> v3 rebuild (rows and
  instances survive, child_id gone, foreign_key_check clean).
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.
dev_agent merged commit 522875642d into feature/c16267ae-75be-4a4e-b14f-e41c06c8ab11-design-model-changes 2026-09-15 10:35:40 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/NestQuest#47