Skip to content

Bug: multi-step DB writes lack transactions (autoReschedule cascade, reorderSubtasks, createMilestone, two-step deletes) #1809

Description

@steilerDev

Severity: Medium — found during a deep project review (2026-07-06). Crash-window bugs: better-sqlite3 is synchronous so there is no in-process interleaving, but a crash/OOM/docker stop mid-sequence persists partial state with no rollback.

Non-transactional multi-step writes

  1. autoReschedule mass date cascade (highest impact)server/src/services/schedulingEngine.ts:698-1050: per-row db.update(workItems) (:885) and db.update(householdItems) (:1031) loops; each statement autocommits. Triggered from routes/workItems.ts:139 on work-item create/update and from the daily reschedule. A crash mid-run persists a half-applied schedule (some items cascaded, dependents not), undetectable afterwards.
  2. reorderSubtasksserver/src/services/subtaskService.ts:252-262: per-subtask sortOrder updates autocommit individually; kill mid-loop persists mixed old/new orders (duplicate sortOrder values).
  3. createMilestone parent + linksserver/src/services/milestoneService.ts:253-278: milestone insert then milestoneWorkItems link loop; crash in between persists the milestone with partial/no links while the client gets an error and retries → duplicate milestone.
  4. Two-step deletesserver/src/services/workItemService.ts:597-609 and server/src/services/milestoneService.ts:373-382: householdItemDeps rows deleted first, then the parent entity; crash in between silently destroys dependency rows while the parent survives.

Suggested fix

Wrap each sequence in a Drizzle/better-sqlite3 transaction (db.transaction(...)). The scheduling engine cascade is the priority — it does the largest multi-table write in the app on a routine trigger.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions