Skip to content

Roll surfaced task out of the UI when creation fails after onTaskReady - #4018

Closed
adboio wants to merge 2 commits into
mainfrom
posthog-code/rollback-surfaced-task-on-failed-create
Closed

Roll surfaced task out of the UI when creation fails after onTaskReady#4018
adboio wants to merge 2 commits into
mainfrom
posthog-code/rollback-surfaced-task-on-failed-create

Conversation

@adboio

@adboio adboio commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Problem

When task creation fails partway through, the prompt correctly returns to the channel composer — but the message can stay in the feed looking like a normal kickoff, and clicking its card lands on a task page that just says "Select a repository folder".

The creation saga fires onTaskReady before its final steps (agent session connect), so the UI splices the real task card into the channel feed, seeds the task lists, and caches the task detail before creation has actually settled. A late failure then produces one of two states:

  1. Rolled back — the saga deletes the task server-side, but none of the UI cache seeds are undone, so a ghost card lingers and its cached detail entry makes the task route treat the server's 404 as non-authoritative (that guard exists for cloud-pending tasks), rendering a dead task instead of redirecting.
  2. Survived — the rollback delete is swallowed on failure (and a create-request timeout commits server-side with nothing to roll back), so a run-less task row legitimately stays in the feed — it survives app restarts. Opening it dead-ended on the repo picker, which makes no sense for a repo-less channel task.

Why

Raised by Adam in the code channel: a failed create left a normal-looking message in the feed whose card led to a confusing "select a repo folder" page, even though the prompt had correctly bounced back to the input box — and the card survived an app restart.

Changes

  • TaskService.createTask tracks the task surfaced via onTaskReady and fires a new TaskCreationEffects.onCreateRolledBack(task) when the saga then fails. The shared effects impl cancels in-flight list/feed refetches, removes the task from task-list and channel-feed caches, drops the detail cache entry (so the route's existing 404 handling redirects), and invalidates both roots — so server truth settles either way: a deleted task disappears, a surviving one comes back as a real row.
  • Repo-less tasks that resolve no cwd now provision their scratch dir on open — the same thing creation does — in both TaskLogsPanel (feed-card navigation) and navigationTaskBinder (imperative openTask). The folder picker remains only as the fallback if scratch provisioning errors, and is untouched for repo-linked tasks. A surviving orphan now opens into a working session instead of the picker.
  • useTaskCreation gains an onTaskCreationFailed(task, promptText) callback (forwarded through TaskInput); WebsiteNewTask uses it to return a user parked on the dead task's page to the composer with their prompt.

How did you test this?

  • New unit tests: TaskService fires/skips onCreateRolledBack (fails-after-surface, success, fails-before-surface); effects impl removes the task from list/feed/detail caches and marks them stale; WebsiteNewTask returns the user to the composer only when still parked on the dead task; useEnsureScratchWorkspace provisions once, invalidates workspaces, and doesn't loop on failure; navigationTaskBinder provisions scratch only for repo-less tasks with no workspace.
  • Full suites: @posthog/core (242 files) and @posthog/ui (284 files) pass; pnpm typecheck clean across the workspace; biome lint packages/core reports zero noRestrictedImports.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

The creation saga fires onTaskReady before its final steps (agent session
connect, cloud run), so a late failure rolls back a task the UI already
spliced into the channel feed, task lists, and the detail cache. The prompt
returned to the composer, but the feed kept a card pointing at a deleted
task whose detail page fell through to the "Select a repository folder"
prompt.

TaskService now tracks the surfaced task and fires a new
TaskCreationEffects.onCreateRolledBack on failure; the shared impl cancels
in-flight refetches, removes the task from list/feed caches, and drops the
detail entry so the route's 404 handling redirects instead of rendering the
dead task. useTaskCreation exposes onTaskCreationFailed so WebsiteNewTask
can return a user parked on the dead task's page to the composer with
their prompt.

Generated-By: PostHog Code
Task-Id: d7169be9-8012-4434-a325-c578adac0458
@trunk-io

trunk-io Bot commented Jul 30, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

React Doctor found 1 issue in 1 file · 1 warning.

1 warning

src/features/task-detail/components/TaskLogsPanel.tsx

Reviewed by React Doctor for commit 3af86a2.

A failed creation can leave the task row behind: the saga's rollback delete
is swallowed on failure, and a create-request timeout commits server-side
with nothing to roll back. Such a task legitimately reappears in the feed
(it exists), and opening it dead-ended on "Select a repository folder" —
a repo-less task has no repo to map, so hasDirectoryMapping is永false and
the picker never made sense.

Provision the scratch dir on open instead, the same way creation does:
TaskLogsPanel ensures it when a local repo-less task resolves no cwd (the
folder picker remains only as the fallback if provisioning errors), and
navigationTaskBinder does the same on the imperative openTask path. The
workspace server already synthesizes scratch dirs into getAll, so the
session resolves the new dir as its cwd.

Generated-By: PostHog Code
Task-Id: d7169be9-8012-4434-a325-c578adac0458
@adboio adboio closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant