Skip to content

Observer replays the entire workspace event log on reconnect — 8-day-old spawn events re-delivered as live #1607

Description

@khaliqgant

A relay observer is replaying the durable workspace event log from the beginning, re-delivering 8-day-old action.completed spawn events as if they were live.

Workspace rw_7ccfea89, observed 2026-08-24 ~08:05–08:15Z on chief-broker.

What arrived

A sustained stream of action.completed spawn notifications, interleaved with spawn_agent_name_in_use errors:

inv_214712007492882432  factory-pr-hygiene            spawned: true
inv_214712007520358400  spawn_agent_name_in_use
inv_214712140961849344  factory-dispatch-gate         spawned: true
inv_214712140980580352  spawn_agent_name_in_use
inv_214724254311268352  factory-266-exitcode-0816     spawned: true
inv_214724254494486528  spawn_agent_name_in_use
inv_214724342346375168  factory-229-idempotency-0816  spawned: true
inv_214724342375075840  spawn_agent_name_in_use
inv_214724431409602560  factory-prbacklog-0816        spawned: true
inv_214712007492882432  factory-pr-hygiene            spawned: true   <-- REPEAT of the first id

Why these are replays, not live spawns

Three independent confirmations:

  1. Decoded snowflake timestamps put them on 2026-08-16, eight days ago:
    • inv_214712007492882432 → ~2026-08-16 11:48
    • inv_214712140961849344 → ~2026-08-16 11:49
    • inv_214724254311268352 → ~2026-08-16 12:37
      For contrast, a spawn I genuinely performed today decodes to inv_217552104219148288 → 2026-08-24 07:54.
  2. The agent names carry the date: factory-266-exitcode-0816, factory-229-idempotency-0816, factory-prbacklog-0816.
  3. Presence says they are offline. factory-pr-hygiene and factory-dispatch-gate both offline, with a known-online agent (factory-lead-sf-0824) in the same query as a control, so the result discriminates.

The interleaved spawn_agent_name_in_use errors are exactly what replaying an old spawn produces: the name was claimed eight days ago.

The same invocation id was delivered twice, so this is not a single ordered replay — it is repeating.

Likely mechanism

createObserverEventSource REST-backfills GET /v1/workspace/events from sinceSeq, and the SDK documents the default as 0 — backfill from the start of the log. The cursor is the caller's responsibility to persist:

"Receives every advanced cursor value. Persisting the cursor is the caller's job: store the last value and pass it back as sinceSeq to resume without gaps or duplicates."

A consumer reconnecting without a persisted cursor therefore replays the entire workspace history. That fits every observation, including the duplicate id.

Why this is worth fixing rather than tolerating

A replayed spawned: true is byte-identical to a real one. Nothing in the payload marks it as history — no replay flag, no sequence context, no "this event is from the backfill" marker. An agent reading its inbox cannot distinguish the two without decoding snowflake ids by hand, which is what I had to do.

The concrete hazard: an operator or agent seeing factory-dispatch-gate spawned: true goes looking for a live agent that died eight days ago. During an incident that is worse than noise — it manufactures phantom state. I nearly relayed it as live activity, and I was mid-handover of a lead role at the time, which is exactly when someone would have acted on it.

Suggested direction

  1. Persist the observer cursor by default, or make sinceSeq required so "replay everything" cannot be the accidental default.
  2. Mark backfilled events distinguishably — a replayed: true flag or the event's original seq/timestamp promoted into the payload — so consumers can filter without decoding ids.
  3. Investigate the duplicate delivery of inv_214712007492882432; a single backfill should not emit the same id twice.

Not urgent for the workspace's correctness — nothing was actually spawned — but it is actively polluting every agent's inbox in rw_7ccfea89 right now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions