fix(storage): drop settled swap requests instead of keeping them forever (#783) - #784
Merged
Conversation
…ver (#783) `async_approve_swap` only flipped the request's status to "approved" and left the record in storage. Nothing reads a request once it leaves "pending" — `_build_state_snapshot` and `async_approve_swap` both filter on it, and the panel's only swap UI is the pending-approval queue — so approved records were write-only data that accumulated indefinitely. Approval now consumes the request, exactly as rejection already did. The asymmetry was the giveaway: `async_reject_swap` deleted the record while approve merely annotated it. Nothing is lost — the approval is still observable through the `taskmate_swap_approved` event (which carries chore_id, requester_id, from_child_id and timestamp) and, since #781, through the chore's own dated `assignment_swap_*` override. A retention/prune job would have been the wrong shape here. `async_prune_history` keeps completions for 90 days because they are real history someone might want; these records are read by nothing, so a retention policy would only mean holding dead data for 90 days rather than forever. Existing installs are swept at load. That runs on every load rather than behind a one-shot flag: it is a cheap list filter, and it also cleans up after a downgrade to a version that still wrote the records. Verified on a live instance — the load-time sweep dropped 8 genuinely accumulated records from the dev store, and a restart after a fresh approval found nothing left to drop.
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 #783
Problem
async_approve_swapflipped the request's status to"approved"and left the record in storage forever. Nothing ever reads it — both readers filter to pending:websocket.py:367—[r for r in get_swap_requests() if r.get("status") == "pending"]coord_chores.py:177— matches onidandstatus == "pending"The panel's only swap UI is the pending-approval queue (
taskmate-panel.js:3185); there is no approved-swap history view.fairness_reportis built from completions, which after a swap are already recorded against the swapped-to child, so it reflects the outcome without the request record.The lifecycle asymmetry gave away the original intent:
async_reject_swapdeleted the record outright, while approve merely annotated it.Fix
Approval consumes the request, matching rejection. Nothing is lost — the approval remains observable through the
taskmate_swap_approvedevent (carryingchore_id,requester_id,from_child_id,timestamp) and, since #782, through the chore's own datedassignment_swap_child_id/assignment_swap_dateoverride.Why not a prune job.
async_prune_historykeeps completions for 90 days because they are real history someone might want. These records are read by nothing, so a retention policy would just mean holding dead data for 90 days instead of forever.Migration. Existing installs are swept at load, otherwise the fix would only stop new records accumulating. It runs on every load rather than behind a one-shot flag — it is a cheap list filter over a small list, and it also cleans up after a downgrade to a version that still wrote the records. Pending requests are preserved, including legacy records with no
statuskey (dropped, since only an explicit"pending"is actionable).Verification
Unit — 5 new tests: approval removes the request, double-approve still raises, and three covering the load-time sweep (settled dropped / pending preserved / absent list harmless). The two behavioural ones fail on
main. Full suite 1551 passed.Live instance. Ran three swap-and-approve cycles on unpatched
mainto accumulate records, then restarted on this branch with debug logging enabled:Eight — the three I had just made plus five genuinely accumulated from earlier testing, which is the bug in miniature. Then a fresh swap-approve-complete cycle passed end to end, and the next restart reported nothing left to drop, confirming new approvals leave no residue.
Noted, not fixed
Removing a chore does not cascade to its pending swap requests, so a deleted chore can leave an orphan in the approval queue. Separate from this change; happy to open an issue if you want it chased.