Skip to content

Agent mutations 409 PROJECTION_STALE; stale-epoch browser sessions silently drop edits #1

Description

@vishalsachdev

Observed (live deployment, 2026-07-26, doc slug rclchxs4)

Three related failures around the access-epoch / live-authority machinery, observed while an AI agent posted marks via the stateless HTTP mutation path (MCP bridge) with a human editor session open in the browser:

1. Parallel agent mutations trip the write gate

Three concurrent suggest mutations raced the epoch bookkeeping. After the burst, every subsequent mutation returned 409 PROJECTION_STALE even though the projection row was verifiably healthy (document_projections.health = 'healthy', revision matching documents). Sequential writes eventually succeed, but only ~one per background repair cycle (60-90s) — a throughput cliff for any agent workflow that posts several marks.

2. Misleading error code

The 409 is produced by projectionStaleMutationResult() (server/document-engine.ts), but the actual denial comes from the live-authority gate in getCanonicalReadableDocumentSync (server/collab.ts): active collab presence + getLocalLiveAuthorityDecision(...).allowed === falsemutation_ready: false. Debugging chased the projection (which was fine) because the code said PROJECTION_STALE. The live-authority denial deserves its own error code (e.g. LIVE_AUTHORITY_UNAVAILABLE) and log line.

3. Stale-epoch browser sessions silently drop human edits (data loss)

After the epoch bump (access_epoch 0 → 3), the open browser session kept editing with no UI indication, while the server logged for every change:

[collab] stale-epoch write dropped { slug: 'rclchxs4', source: 'onChange', sessionAccessEpoch: 0, currentAccessEpoch: 3 }

From the user's perspective the editor was working; in reality nothing persisted until a manual hard refresh re-attached the session at the current epoch. This is the highest-severity piece: silent human data loss.

Suggested fixes (in priority order)

  1. On stale-epoch write drop, close that collab connection so the client auto-reconnects at the current epoch (or push a force-resync). One dropped write is a race; a session that keeps dropping writes should never linger silently.
  2. Distinct error code + client banner for live-authority denial vs genuine projection staleness.
  3. Serialize or lease agent mutations per doc (or make the epoch bump not invalidate live-authority for in-flight sessions) so a burst of agent marks doesn't wedge the write path for minutes.

Environment

Fork vps branch at 759aabf (flag-rendering fix), deployed via proof-vps Docker; single replica; SQLite store.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ro6KiE6zCSSzsqeyVoAu8M

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions