fix(storage): deleting a chore or child drops its pending swap requests (#785) - #786
Merged
Conversation
…ts (#785) `async_remove_chore` cascaded to completions, last-completed, task groups, scheduled changes and children's chore_order; `async_remove_child` cascaded to completions, reward claims, transactions, pool allocations, career history, quest and challenge progress. Neither touched swap_requests, so a pending request outlived whatever it referred to. The panel falls back to "?" for a name it cannot resolve (taskmate-panel.js:3187), leaving the parent a permanent "? wants to swap ?" row in the approval queue that only rejecting can clear. Both ends of a request matter for the child cascade: `requester_id` is who the handover goes to, and `from_child_id` is who it comes from and is rendered in the queue. Either being gone makes the request undeliverable. Child removal also clears a chore's approved swap override when it pointed at the deleted child, so the chore is not left assigned to someone who no longer exists. The load-time sweep from #784 is extended to drop dangling pending requests too, so installs that already deleted a chore or child get cleaned up rather than carrying the stuck row forever. A request now survives only when it is pending *and* every id it names resolves — `from_child_id` is exempt when blank, which is the normal shape for a chore with no cached assignee yet. Verified on a live instance: two orphans created the way a user would (delete the chore, then delete the requesting child) sat visibly in the approval queue on unpatched code, were gone after restarting on this branch, and both delete paths then dropped their request immediately with no restart involved.
This was referenced Aug 13, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #785
Problem
Deleting a chore or a child left its pending swap requests behind.
async_remove_chorecascaded to completions, last-completed, task groups, scheduled changes and children'schore_order.async_remove_childcascaded to completions, reward claims, transactions, pool allocations, career history, quest and challenge progress, and stripped the child fromassigned_to. Neither touchedswap_requests.The panel falls back to
"?"for a name it cannot resolve (taskmate-panel.js:3187):so the parent was left with a permanent
"? wants to swap ?"row in the approval queue that only rejecting could clear.Fix
Cascade on delete, matching every other cleanup in the codebase.
Both ends matter for the child cascade.
requester_idis who the handover goes to;from_child_idis who it comes from and is rendered in the queue. Either being gone makes the request undeliverable, soremove_swap_requests_for_childfilters on both.Child removal also clears a chore's approved swap override when it pointed at the deleted child, so the chore is not left assigned to someone who no longer exists.
Migration. The load-time sweep added in #784 is extended to drop dangling pending requests, so installs that already deleted a chore or child get cleaned up instead of carrying the stuck row forever. A request now survives only when it is pending and every id it names resolves.
from_child_idis exempt when blank — that is the normal shape for a request against a chore with no cached assignee yet, not a dead reference, and there is a test pinning it.Verification
Unit — 7 new tests (5 cascade, 2 sweep). Full suite 1558 passed.
Two existing tests from #784 needed their fixtures updated: they asserted pending requests survive, but used empty
children/choreslists, so under the new orphan rule every one of their records is dangling. They now seed the referenced entities, which is what they always meant — they were testing the settled/pending filter, not the orphan filter.Live instance. Created two orphans the way a user would — delete the chore out from under a pending request, then delete the requesting child:
The two cascade assertions run with no restart involved. A full swap-request-approve-complete cycle still passes afterwards.
Noted, not fixed
assignment_current_child_idis not cleared when the child it names is deleted, so a rotation chore can point at a ghost until the midnight assignment pass, during which the sensor filter (assignment_current_child_id != child.id) matches nobody and the chore is invisible to the whole pool. That predates the swap feature and is a separate defect — happy to open an issue.