Decide what cancelling a child task does to its parent #85

Open
opened 2026-09-11 21:47:46 +01:00 by liamjd · 0 comments
Owner

Part of milestone #5. Follows on from #68.

#68 gives a parent two rules: it cannot start until every child is COMPLETE, and cancelling it cancels its children. Neither rule says what happens when a child alone is cancelled.

With the rules as implemented, nothing does. CANCELLED is not COMPLETE, so the gate never reopens and the parent sits BLOCKED for the rest of the run — still queued, never offered, invisible as a problem because BLOCKED is a normal status. next_for() re-evaluates it forever and always gets false.

This is deliberately left open rather than guessed at: it depends on what real tasks and subtasks turn out to be, and which of them a player or the simulation can cancel independently of their parent. That is not yet known — construction spawning one haul per resource is the only concrete tree so far.

What has to be decided

Whether a child can be cancelled on its own at all, and if so, what it does to its parent. The candidates:

  1. Cancelling a child cancels the parent too (cascade upward as well as down). Right if a child is always a hard requirement of its parent — a build with a haul missing cannot be finished.
  2. Cancelled children drop out of the gate (the parent waits only on children that are not COMPLETE and not CANCELLED). Right if a child can be genuinely optional, and the parent's own _can_start() is expected to notice the missing delivery.
  3. Forbid it: cancel() on a task with a parent is rejected with a push_error, and only the root of a subtree can be cancelled. The most restrictive, and the easiest to relax later once a case for it appears.

Worth answering alongside it: does a cancelled child leave the parent recoverable at all, or does the parent need re-planning (a fresh child spawned to replace the cancelled one)? That question is what distinguishes option 2 from option 1 in practice.

Existing coverage

test/unit/test_task_tree.gd already holds two tests for this:

  • test_a_cancelled_child_leaves_its_parent_unworkable — documents the current behaviour without endorsing it. It will need rewriting or deleting whichever option is chosen.
  • test_what_a_cancelled_child_should_do_to_its_parent_is_undecided — a GUT pending() carrying a short version of this issue. Delete it when this lands.

AC

  • A decision recorded here (and in docs/ if it turns out to shape more than the queue)
  • The chosen rule implemented in TaskManager.cancel() and/or Task.can_start()
  • test_a_cancelled_child_leaves_its_parent_unworkable updated to assert the chosen behaviour
  • The pending() placeholder removed
Part of milestone #5. Follows on from #68. #68 gives a parent two rules: it cannot start until every child is COMPLETE, and cancelling it cancels its children. Neither rule says what happens when a **child alone** is cancelled. With the rules as implemented, nothing does. CANCELLED is not COMPLETE, so the gate never reopens and the parent sits BLOCKED for the rest of the run — still queued, never offered, invisible as a problem because BLOCKED is a normal status. `next_for()` re-evaluates it forever and always gets false. This is deliberately left open rather than guessed at: it depends on what real tasks and subtasks turn out to be, and which of them a player or the simulation can cancel independently of their parent. That is not yet known — construction spawning one haul per resource is the only concrete tree so far. ### What has to be decided Whether a child can be cancelled on its own at all, and if so, what it does to its parent. The candidates: 1. **Cancelling a child cancels the parent too** (cascade upward as well as down). Right if a child is always a hard requirement of its parent — a build with a haul missing cannot be finished. 2. **Cancelled children drop out of the gate** (the parent waits only on children that are not COMPLETE *and* not CANCELLED). Right if a child can be genuinely optional, and the parent's own `_can_start()` is expected to notice the missing delivery. 3. **Forbid it**: `cancel()` on a task with a parent is rejected with a `push_error`, and only the root of a subtree can be cancelled. The most restrictive, and the easiest to relax later once a case for it appears. Worth answering alongside it: does a cancelled child leave the parent recoverable at all, or does the parent need re-planning (a fresh child spawned to replace the cancelled one)? That question is what distinguishes option 2 from option 1 in practice. ### Existing coverage `test/unit/test_task_tree.gd` already holds two tests for this: - `test_a_cancelled_child_leaves_its_parent_unworkable` — documents the current behaviour without endorsing it. It will need rewriting or deleting whichever option is chosen. - `test_what_a_cancelled_child_should_do_to_its_parent_is_undecided` — a GUT `pending()` carrying a short version of this issue. Delete it when this lands. ### AC - A decision recorded here (and in `docs/` if it turns out to shape more than the queue) - The chosen rule implemented in `TaskManager.cancel()` and/or `Task.can_start()` - `test_a_cancelled_child_leaves_its_parent_unworkable` updated to assert the chosen behaviour - The `pending()` placeholder removed
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder#85
No description provided.