Skip to content

Double-summarization: no lock on maybeSummarize + boundary off-by-one #21

Description

@serge-ivo

Severity: LOW. Found in the 2026-07-16 storage/AI sweep (deferred).

agent-do.ts fires maybeSummarize() fire-and-forget with no lock. The DO input gate lets two turns (e.g. concurrent WS + HTTP) interleave at await points, so both can cross the 20-message threshold and read the same lastSummary before either writes → two sum: rows for overlapping ranges + duplicate mem:fact:* writes.

Also a boundary off-by-one: maybeSummarize uses startAfter: msg:${lastTimestamp} where lastTimestamp is the prior summary's to. Since msg keys are msg:{ts}:{id}, the boundary message (msg:{ts}:{id} > msg:{ts}) is re-included → one message double-counted each window.

Files: workers/api/src/agent-do.ts (fire point), workers/api/src/agent-storage.ts (maybeSummarize, boundary).

Fix sketch: a lightweight in-DO lock/guard around summarization; store the boundary as the full msg key (or advance past {ts}:{id}) to exclude the already-summarized message.

Impact: duplicate summary rows + facts, one double-counted message. Not corruption. Deferred because the fix risks wedging summarization if the lock isn't released cleanly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions