Skip to content

[Bug]: Auto-settle on PR merge hides a thread that failed before finishing its work #27052

Open

Description

@doublesharp

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

Observed incident, confirmed through read-only inspection of T3's persisted events. This has not been reproduced with a controlled provider fixture.

  1. Leave auto-settle on PR merge enabled.
  2. Ask an agent to implement and deploy a site update.
  3. The linked PR merges while the agent continues the remaining release work.
  4. Before finishing that work, the turn fails with: Selected model is at capacity. Please try a different model.
  5. T3 automatically settles the thread immediately after the failed run.

Expected behavior

A thread whose latest run failed with an unresolved provider error should remain visible as needing attention, even if its linked PR merged. A merged PR does not establish that the requested deployment or verification finished.

Actual behavior

The failed thread moved into Settled and disappeared from the active list despite unfinished work. I noticed that the site had not updated, searched for the task, found it settled, and manually reopened it and sent a follow-up to restart the work.

Impact

Minor bug or occasional failure

The unfinished task becomes easy to miss because the thread is moved out of the active list immediately after the provider failure. In this incident, the work stayed stopped until I checked the unchanged site and found the settled thread.

Version or commit

Server version checked during investigation: 0.1.4-nightly.20261027.3783. The version was read from the running server, not recorded in the failure event itself.

Environment

macOS arm64; Codex provider; GPT-6.1 Sol. Codex CLI version was not collected.

Logs or stack traces

Sanitized summary of persisted records, not a raw log dump. Times are relative to the failed run's completion. Project, account, repository, branch, thread, run and command identifiers, private URLs, local paths, and absolute timestamps are omitted.

Approximately 3m48s before failure:
  Linked pull request state: merged

T-2 ms:
  Terminal item title: Provider error
  failure.class: provider_error
  failure.code: serverOverloaded
  failure.retryable: null
  failure.message: Selected model is at capacity. Please try a different model.

T+0 ms:
  Event: run.updated
  status: failed
  completedAt: recorded

T+57 ms:
  Event: thread.settled
  command_id prefix: server:auto-settle:
  settledOverride: settled
  settledAt: equal to failed run's completedAt
  Linked pull request snapshot state: merged

Approximately T+1h42m23s:
  Event: thread.unsettled
  User reopened the thread and sent a follow-up.
  Another run started.

The automatic command confirms server-triggered settlement. The linked PR was already merged, and the timing is consistent with merge-based settlement becoming eligible as soon as the run failed. No code change, automated regression test, or controlled reproduction was performed during this investigation.

Screenshots, recordings, or supporting files

The relevant event fields are included above. The original screenshot and raw records are omitted to avoid exposing private project details.

Workaround

Find the thread in Settled, reopen it, and manually resume the unfinished work.

Related reports

Prepared with Codex, GPT-6.1 Sol, through T3 Code.

Activity

  1. iwoplaza commented on Nov 13, 2026

    @iwoplaza

    This doesn't need the run to fail. It happens on a successful run too, and then the reply you asked for is what disappears.

    Steps:

    1. Keep Settle on merge on.
    2. Ask the agent for something (follow-up work, a check, anything).
    3. While it's still working, merge the thread's linked PR yourself (on the host or with the in-app merge button).
    4. The run finishes and the thread settles at once, with settledAt equal to the run's completedAt. The reply ends up in Settled before you've seen it.

    The cause is the same as in your incident. pullRequestSettles in ThreadSettlementService.ts only checks that mergedAt is at or after max(createdAt, latestUserAuthoredMessageAt). A merge that lands while the run is going counts, and the active run only delays settlement until the run ends, failed or not.

    I have a local fix. A merge or close that lands between the latest request and the end of its run no longer settles the thread. The exception is when that same run ran the host CLI merge or close itself (e.g. gh pr merge), so threads where the agent merges its own PR still settle right after, as they do now. That would cover the failed-run case here too, since a failure after a mid-run merge no longer settles the thread at all.

    So far I've reproduced it with a unit test on main and haven't recorded it in a running app. Happy to open a PR if this direction sounds right 🙏

    Investigated with Claude Opus 5.5 in Claude Code, run from T3 Code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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