mirror of
https://github.com/thedotmack/claude-mem.git
synced 2026-09-20 04:23:02 +08:00
c5d52e5c40
A generation job whose payload points at a non-existent job id is dropped
silently: `ProviderObservationGenerator` resolves the row through
`payload.generation_job_id`, so `lockOutbox` finds nothing, logs at info level
and returns `{ status: "completed" }` to BullMQ without ever touching Postgres.
The queue reports success, the row stays `queued` forever, and nothing is
recorded as failed.
That pointer goes stale on the upsert path. Every re-create mints a fresh id
for `$1` and puts the same id in the payload it hands over. On
`ON CONFLICT (idempotency_key)` the existing row wins, so the minted id is
discarded for the `id` column -- but `payload || excluded.payload` still lets
it overwrite `generation_job_id`, leaving the row pointing at an id that was
never inserted.
This only bites `session_summary`. Its idempotency key is derived from
`sourceId`, which for summaries is the session, so every re-run of a session
summary collides. Event jobs key off the individual event id and never conflict.
Re-pin `generation_job_id` to the surviving row inside the same merge.
Notes for reviewers:
- An operator re-queue flow that "reuses the persisted payload" (#2459 /
discussion #2460) does not recover these rows: replaying the stored payload
replays the stale pointer, and the job is dropped again just as silently.
- Observed on a production deployment running server-beta since May: 190 summary
jobs stranded in `queued` across four months, 190/190 with
`payload->>generation_job_id` absent from the table. Event jobs on the same
instance: 0 divergences in ~221k rows. After re-pointing the payload the same
rows started draining immediately.
Co-authored-by: Alessandro <alessandropcostabr@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>