Correct retirement docs: deactivation clears future open instances

Retirement preserves the definition row, schedule rule, assignees,
windows and all durable completion history, but like any deactivation
it regenerates, so future uncompleted instances are cleared and none
are recreated while inactive. Fixes the "deletes nothing / all
instances preserved" wording in the core docstrings, the admin DELETE
route description, ADMIN-SPEC and the retire test's docstring
(review finding NQ-262-1). No behavioural change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 12:40:44 -04:00
co-authored by Claude Opus 5.5
parent ed230961e0
commit ba0b2032cc
4 changed files with 37 additions and 15 deletions
+8 -2
View File
@@ -208,8 +208,14 @@ retire/deactivate if there is"):
:func:`nestquest_core.quest_definitions.delete_quest_definition`. A
definition with NO completion event on any instance is hard-deleted
(instances, assignees, windows, the row and its unreferenced rule, in
one core transaction); one WITH history is retired by deactivation
and everything is preserved. The response reports which happened
one core transaction); one WITH history is retired by deactivation.
Retirement preserves the definition row, schedule rule, assignees,
windows and ALL durable completion history; like any deactivation it
regenerates, so future UNCOMPLETED instances are cleared (rolling,
regenerable rows) and none are recreated while the definition is
inactive — the retired task stops generating and shows no open work.
Durable instance history lives only in the append-only
``completion_events``. The response reports which happened
(``deleted`` / ``retired``) and carries the retired definition, or
``null`` when deleted. An unknown id is 404.
@@ -525,10 +525,15 @@ async def set_quest_definition_active(
completion history (Feature 06 guardrail; a history-free definition
may instead be hard-deleted by :func:`delete_quest_definition`):
a deactivated definition stops future instance generation but its
row, schedule rule, assignees and windows all survive, and existing
instances plus completion history are never touched. Reactivation
re-enables future generation; generating or removing instances is
Feature 07 and does not happen here.
row, schedule rule, assignees and windows all survive, and its
durable completion history (the append-only ``completion_events``)
is never touched. Like every Feature 06 config change, the flip is
followed by :func:`~.materialize.regenerate_for_definition`: the
definition's future (today onward) UNCOMPLETED instances are cleared
— they are rolling, regenerable rows — and, while the definition is
inactive, none are re-materialized. Completed and past instances
are kept. Reactivation re-enables generation, and the same
regeneration re-materializes the rolling horizon.
``definition_id`` must be a plain int (bools and floats rejected,
since SQLite would bind ``True`` onto definition 1) and
@@ -598,9 +603,14 @@ async def delete_quest_definition(
:meth:`~.dao_rules.QuestDefinitionsDao.delete_if_no_history` — the
history check is inside that transaction, so a completion recorded
concurrently can never be deleted (D-005). When history exists,
nothing is deleted: the definition is retired through
:func:`set_quest_definition_active` (``False``), preserving the row,
rule, assignees, windows, instances and completion history.
the definition is retired through :func:`set_quest_definition_active`
(``False``). Retirement preserves the definition row, schedule
rule, assignees, windows and ALL durable completion history. Like
any deactivation it regenerates, so future UNCOMPLETED instances are
cleared (they are rolling, regenerable rows) and none are recreated
while the definition is inactive — the retired task stops generating
and no longer shows open work. Durable instance history lives only
in the append-only ``completion_events``.
``definition_id`` must be a plain int (bools and floats rejected).
Raises ValueError naming the field when the id is malformed or the
+8 -3
View File
@@ -91,9 +91,14 @@ otherwise it is retired (deactivated) and its history is kept." — with `Go bac
danger-filled `Delete task`. Confirming calls `DELETE /api/v1/admin/quest-definitions/{id}`
(admin plane only; the kids' panel has no equivalent control). Hybrid outcome (D-017): no
completion event on any instance → the definition, its instances, assignees, windows and
unreferenced rule are hard-deleted and the row leaves the list; otherwise nothing is
deleted, the definition is deactivated and the row stays, shown inactive. An error keeps
the sheet open with the API's detail.
unreferenced rule are hard-deleted and the row leaves the list; otherwise the definition
is retired (deactivated) and the row stays, shown inactive. Retirement preserves the
definition row, schedule rule, assignees, windows and all durable completion history. Like
any deactivation it regenerates, so future uncompleted instances are cleared (they are
rolling, regenerable rows) and none are recreated while the definition is inactive — the
retired task stops generating and no longer shows open work. Durable instance history lives
only in the append-only `completion_events`. An error keeps the sheet open with the API's
detail.
### 3.3 Icon picker
Each definition carries one optional icon, shown on both surfaces. The picker offers three
+4 -3
View File
@@ -2212,9 +2212,10 @@ def test_delete_without_history_keeps_a_shared_rule(tmp_path) -> None:
def test_delete_with_history_retires_and_preserves_everything(
tmp_path,
) -> None:
"""A completion event on ANY instance: nothing is deleted; the
definition is deactivated and its row, rule, assignees, windows,
instance and completion history all remain."""
"""A completion event on ANY instance: the definition is retired
(deactivated) and its row, rule, assignees, windows and completion
history all remain. The completed instance survives; only future
UNCOMPLETED instances are cleared by the deactivation's regeneration."""
async def _body(database, children, rules, definitions, child):
created = await create_quest_definition(
database, "Brush teeth", _daily_rule(), [child.id], ["morning"]