Skip to content

TOCTOU: plan-task, plan-slice, reassess-roadmap, replan-slice guards outside transaction #11

@igouss

Description

@igouss

Summary

Four tool handlers run state machine guards outside the transaction() callback, then perform writes inside a separate transaction. This creates a time-of-check-to-time-of-use (TOCTOU) race where two agents can both pass the guard simultaneously and both write successfully.

Impact

Critical — In multi-agent deployments (the exact threat model the Single-Writer Engine v3 addresses), concurrent agents can:

  • Both re-plan the same completed slice/task
  • Both reassess the same milestone simultaneously
  • Both replan the same blocked slice

SQLite's single-writer lock prevents corruption but does not prevent both operations from succeeding — the second write wins silently.

Affected Files

plan-task.ts

  • Line 80: getSlice() guard — outside txn
  • Line 88: getTask() guard — outside txn
  • Line 94: transaction(() => { insertTask/upsertTaskPlanning }) — separate txn

plan-slice.ts

  • Line 149: getMilestone() guard — outside txn
  • Line 157: getSlice() guard — outside txn
  • Line 166: transaction(() => { ... }) — separate txn

reassess-roadmap.ts

  • Line 108: getMilestone() check — outside txn
  • Line 117: getSlice() for completedSliceId — outside txn
  • Lines 126-146: getMilestoneSlices() + enforcement — outside txn
  • Line 158: transaction() — separate txn

replan-slice.ts

  • Line 94: getSlice() slice-status check — outside txn
  • Line 103: getTask() blocker check — outside txn
  • Lines 112-132: completed-task enforcement — outside txn
  • Line 138: transaction() — separate txn

Correct Pattern (for reference)

complete-task.ts:155-208, complete-slice.ts:223-257, reopen-task.ts:60-92, and reopen-slice.ts:59-88 all correctly colocate guards and writes inside a single transaction() callback.

Fix

Move guard checks into the transaction() callback in all four files, following the same pattern as complete-task.ts. Use a guardError variable set inside the transaction, checked after it returns.

Confidence

85% — structural pattern verified across all tool handlers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions