Skip to content

fix(creation): prevent duplicate workspaces and agents on retries - #4442

Open
boudra wants to merge 5 commits into
mainfrom
investigate-severe-bug
Open

fix(creation): prevent duplicate workspaces and agents on retries#4442
boudra wants to merge 5 commits into
mainfrom
investigate-severe-bug

Conversation

@boudra

@boudra boudra commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Linked issue

Closes #4327. Closes #4058. Closes #3217. Closes #4279. Closes #2673.

Refs #4039, which concerns duplicate sends in an already active session and remains a separate investigation.

Type of change

  • Bug fix

Reasoning

One submit could start several real agents doing the same work. Rapid clicks raced React rendering, remounted drafts lost their pending state, and retrying after a timeout could create another agent even though the first was already running.

The app now gives each draft a stable creation key and first-message ID. Agent creation and initial-prompt delivery use separate durable receipts. Workspace creation accepts an optional idempotencyKey too, extending the existing daemon journal across socket sessions and restarts. Replaying a completed key returns the original resource; different arguments conflict. Interrupted workspace provisioning remains an explicit unknown outcome instead of treating a partial registry record as success. Completed workspace replays reject a missing checkout. A provider delivery with an unknown outcome is not blindly repeated.

The app also consumes pending submissions correctly in Expo's emitted production code and restores an in-flight draft independently of the consumed handoff. Failed drafts can be submitted again. Remounted views rebuild their pending preview after model settings hydrate and unlock when the original request fails. Sending the first prompt still supplies the agent's initial title. Workspace creation hooks execute inside the receipt operation, so a replay does not rerun hooks.

Goals

  • Repeated taps and transport retries create one workspace and one agent per draft.
  • A lost first-prompt acknowledgement can be retried with the same agent and message identity.
  • Separate drafts can create separate agents concurrently in one workspace.
  • Preserve existing receipt files and accept older clients' keyless requests.

Non-goals

  • Deduplicating unrelated active-session messages or intentionally separate drafts.
  • Automatically resending an ambiguously accepted provider request.
  • Adding automatic archive-on-startup-failure behavior.

Supersedes

These five PRs have been closed in favor of this PR.

QA

Before the fix, real browser/isolated daemon tests reported:

Repeated workspace Create clicks: expected 1 workspace, received 3
Replayed app create-agent request: expected 1 unique agent ID, received 3
Production pending-submission consume: expected null on second consume, received the original submission
Remounted draft while model settings reload: expected pending prompt, received "Select a model"
Failed draft retry: expected accepted, received rejected
Workspace replay after checkout removal: expected error, received a workspace

The browser regression file covers local and worktree creation, rapid agent submits, repeated new-workspace prompts, transport replays, a dropped first-prompt acknowledgement, initial naming, actual workspace eviction/remount, and concurrent independent drafts. Browser mechanics and resource cleanup live in helpers and fixtures; draft lifecycle assertions use the store directly.

Windows CI also exposed missed file-deletion notifications under churn. The native observer now classifies previously unknown paths announced only by a change event, so subsequent reconciliation can recover coalesced deletions. A deterministic real-filesystem regression failed before this fix; all 16 observer tests passed in ten consecutive local runs afterward. The Windows server CI suite now passes on dc3c7d00c.

Validation:

npm run build:server                         passed
npm run typecheck                            passed
npm run lint                                 0 warnings, 0 errors
npm run format                               passed
Request receipt tests                        9 passed
Workspace RPC error/source tests             8 passed
Daemon wire compatibility tests              7 passed
Protocol wire compatibility tests           13 passed
Draft flow and production submission tests  11 passed
Draft lifecycle store tests                   6 passed
Workspace tab/setup tests                   20 passed
Plugin lifecycle tests                        4 passed
File observer tests                          16 passed × 10 runs

Final browser run (videos recorded):

E2E_RECORD_VIDEO=1 npm run test:e2e --workspace=@getpaseo/app -- e2e/browser/creation-idempotency.spec.ts
9 passed (1.2m)

Tests use real sockets, registries and Git worktrees with the test provider adapter; no live provider billing. Tested on Chromium/web and the Linux daemon. Native iOS/Android and packaged Electron were not exercised. No visual layout changes.

The new app requires the host's receipt capabilities for these creation flows and asks for a host update when unavailable. The wire fields remain optional for older clients.

Checklist

  • One focused change
  • npm run typecheck passes
  • npm run lint passes
  • npm run format passes
  • QA evidence
  • Tests added or updated where it made sense

@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes workspace, agent, and initial-message creation retry-safe by assigning stable operation identities and persisting separate daemon receipts.

  • Adds daemon-wide receipt handling for workspace creation alongside agent creation and message delivery.
  • Preserves draft creation keys and first-message IDs across retries and remounts.
  • Prevents repeated submissions while allowing failed drafts to retry with the original identity.
  • Validates completed workspace replays and treats interrupted provisioning as an unknown outcome.
  • Adds browser, store, protocol, session, lifecycle, and receipt regression coverage.

Confidence Score: 5/5

The PR appears safe to merge; the previously reported issues are resolved or withdrawn, and no actionable new regression remains.

The creation paths now use operation-specific durable receipt identities, failed drafts can retry, completed workspace replays validate their checkout, and remounted drafts retain observable lifecycle state. Every previous Greptile root thread is resolved, including the two concerns Greptile explicitly withdrew after the implementation boundary or runtime module-resolution behavior was clarified.

Important Files Changed

Filename Overview
packages/server/src/server/request-receipts/index.ts Generalizes durable receipts across agent creation, workspace creation, and message delivery with operation-specific identities and replay validation.
packages/server/src/server/session.ts Integrates workspace creation with durable receipts while preserving explicit handling for ambiguous interrupted provisioning.
packages/app/src/composer/draft/create-flow.ts Restores active and failed creation state across remounts and blocks only genuinely active duplicate submissions.
packages/app/src/stores/create-flow-store.ts Adds atomic duplicate suppression and retained failure details while allowing abandoned attempts to retry.
packages/app/src/screens/new-workspace-screen.tsx Gives each workspace draft a stable workspace, agent, and initial-message creation identity.
packages/app/src/agent-creation/index.ts Centralizes the two-receipt agent creation and initial-message delivery sequence.
packages/app/e2e/browser/creation-idempotency.spec.ts Covers rapid submissions, transport replays, remount recovery, prompt acknowledgement loss, and independent concurrent drafts through user-level scenarios.
packages/server/src/server/file-observer/internal/native-recursive.ts Records files first announced through native change notifications so later coalesced removals can be reconciled.
packages/app/src/screens/workspace/explorer-sidebar-tab-rail.tsx Uses complete tab-target identity when toggling workspace-scoped plugin panels in Explorer.

Sequence Diagram

sequenceDiagram
  participant UI as Draft UI
  participant Client as Daemon Client
  participant Receipts as Request Receipts
  participant Workspace as Workspace Provisioning
  participant Agent as Agent Runtime
  UI->>Client: create workspace(draft key)
  Client->>Receipts: execute(create-workspace, key)
  Receipts->>Workspace: provision once
  Workspace-->>Receipts: workspace ID
  Receipts-->>Client: durable result
  UI->>Client: create agent(draft key)
  Client->>Receipts: execute(create, key)
  Receipts->>Agent: create once
  Agent-->>Receipts: agent ID
  Receipts-->>Client: durable result
  UI->>Client: send initial prompt(message ID)
  Client->>Receipts: execute(send, agent ID, message ID)
  Receipts->>Agent: deliver once
  Agent-->>Receipts: completed
  Receipts-->>Client: acknowledgement
Loading

Reviews (6): Last reviewed commit: "fix(file-observer): track files announce..." | Re-trigger Greptile

Comment thread packages/server/src/server/session.ts
Comment thread packages/app/src/screens/new-workspace-screen.tsx Outdated
Comment thread packages/server/src/server/request-receipts/index.ts
Comment thread packages/server/src/server/session.ts Outdated
Comment thread packages/app/e2e/browser/creation-idempotency.spec.ts Outdated
Comment thread packages/app/src/composer/draft/create-flow.test.ts Outdated
@boudra
boudra force-pushed the investigate-severe-bug branch from 709c0ad to 8f81ddc Compare September 7, 2026 18:06
Comment thread packages/server/src/server/request-receipts/index.ts
@boudra
boudra force-pushed the investigate-severe-bug branch from ba95a79 to ebab0b8 Compare September 7, 2026 19:31
Comment thread packages/protocol/src/messages.ts
Comment thread packages/server/src/server/request-receipts/index.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment