Skip to content

v0.6.58: queue abort state machine improvement, contributing guide #4298

Merged
icecrasher321 merged 2 commits intomainfrom
staging
Apr 25, 2026
Merged

v0.6.58: queue abort state machine improvement, contributing guide #4298
icecrasher321 merged 2 commits intomainfrom
staging

Conversation

@icecrasher321
Copy link
Copy Markdown
Collaborator

* fix(mothership): queue supersede crash

* add test

* abort observed marker
* chore(guide): update contributing guide

* fix md
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Apr 25, 2026 1:51am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 25, 2026

PR Summary

Medium Risk
Touches Copilot streaming abort/cancellation state handling (Redis marker polling and stream termination), which can affect whether runs are treated as cancelled vs errored in production. Changes are covered by new unit tests but still impact a core runtime path.

Overview
Improves Copilot stream abort handling across processes. When the Go SSE body closes without a terminal event, runStreamLoop now checks the Redis abort marker and reclassifies the outcome as aborted (optionally surfacing onAbortObserved with the new AbortReason.MarkerObservedAtBodyClose) instead of always erroring.

Tightens cancellation semantics and polling. Streaming/headless lifecycles now treat result.cancelled as a first-class cancelled outcome (not an error), wire onAbortObserved to abort the local controller with a reason, expand explicit-stop classification to include the new abort reason, and reduce the abort-marker poll interval to 250ms with tests ensuring correct marker clearing/ordering.

Docs: updates .github/CONTRIBUTING.md with the current monorepo layout, per-app .env setup, and workflow/tooling guidance (including references to .agents/skills/*).

Reviewed by Cursor Bugbot for commit d93a6f5. Configure here.

@icecrasher321 icecrasher321 merged commit d6c1bc2 into main Apr 25, 2026
31 checks passed
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR fixes a crash where the Go backend "supersedes" a queued request by closing the SSE body without emitting a terminal event — previously misclassified as a 503 ClosedNoTerminal error. The fix adds a Redis abort-marker check at body close; if the marker is present the stream is reclassified as Aborted/cancelled with correct tracing; if Redis is unavailable, the code fails safely to the existing error path. Accompanying changes tighten the abort state machine (abort-before-clear ordering, no-double-abort guard, 250 ms poll cadence) and fix the headless.ts outcome priority so a narrow success-wins-over-abort race is classified correctly.

Confidence Score: 5/5

Safe to merge — the fix is tightly scoped, fails safely when Redis is unavailable, and is backed by targeted unit tests for every new branch.

No P0 or P1 issues found. The abort-at-body-close path correctly defaults to the existing 503 error when the marker check throws. Abort-before-clear ordering and the no-double-abort guard are both verified by new tests. Outcome classification priority (success > cancelled > error) is logically correct. The poll cadence reduction is an intentional trade-off clearly documented in the code.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/copilot/request/go/stream.ts Core fix: adds Redis abort-marker check at SSE body close; correctly falls back to the existing 503 error path when the check fails (fail-safe)
apps/sim/lib/copilot/request/session/abort-reason.ts Adds MarkerObservedAtBodyClose abort reason and includes it in isExplicitStopReason so body-close aborts are classified as explicit_stop, not unknown
apps/sim/lib/copilot/request/session/abort.ts Poll interval reduced 1s→250ms; abort fires before clearAbortMarker to prevent a window where marker is gone but signal is still unset; double-abort guard prevents redundant clears
apps/sim/lib/copilot/request/lifecycle/start.ts Wires onAbortObserved to fire the local AbortController; adds result.cancelled to outcome classification so body-close aborts propagate to cancelled (not error) even before signal.aborted is set
apps/sim/lib/copilot/request/lifecycle/headless.ts Fixes outcome priority: success now beats abortSignal.aborted (avoids misclassifying a narrow race-win as cancelled); adds result.cancelled as a cancel discriminator
apps/sim/lib/copilot/request/types.ts Adds optional onAbortObserved callback to OrchestratorOptions; backward compatible since existing callers require no changes
apps/sim/lib/copilot/request/go/stream.test.ts Four new tests covering: abort reclassification at body close, onAbortObserved callback, no-callback when marker absent, and fail-safe when Redis throws
apps/sim/lib/copilot/request/session/abort.test.ts Two new tests verifying abort-before-clear ordering and no-double-abort guard, both important invariants of the abort state machine
apps/sim/lib/copilot/request/lifecycle/start.test.ts New test verifies a cancelled result publishes a cancelled completion event (not an error), decoupled from abortSignal.aborted state
.github/CONTRIBUTING.md Documentation update: adds apps/realtime description, per-app .env setup, db:migrate instructions, CI check commands, and corrects stale paths

Sequence Diagram

sequenceDiagram
    participant Client
    participant SimSSE as Sim SSE (start.ts)
    participant StreamLoop as runStreamLoop (stream.ts)
    participant Go as Go Backend
    participant Redis

    Client->>SimSSE: POST /api/copilot/chat
    SimSSE->>StreamLoop: runCopilotLifecycle(onAbortObserved)
    StreamLoop->>Go: fetch SSE stream
    Go-->>StreamLoop: text events (no terminal)
    Note over Go: Queue supersede — body closed early
    Go-->>StreamLoop: body close (no terminal event)

    alt streamComplete=false and signal not aborted
        StreamLoop->>Redis: hasAbortMarker(messageId)
        alt marker present
            Redis-->>StreamLoop: true
            StreamLoop->>SimSSE: onAbortObserved(MarkerObservedAtBodyClose)
            SimSSE->>SimSSE: abortController.abort(reason)
            StreamLoop->>StreamLoop: wasAborted=true, endedOn=Aborted
            StreamLoop-->>SimSSE: result cancelled=true
            SimSSE-->>Client: complete event status=cancelled
        else marker absent
            Redis-->>StreamLoop: false
            StreamLoop->>StreamLoop: throw CopilotBackendError 503
            SimSSE-->>Client: error event
        else Redis unavailable
            Redis-->>StreamLoop: throws
            StreamLoop->>StreamLoop: log warn, fall through to error
            StreamLoop->>StreamLoop: throw CopilotBackendError 503
        end
    end
Loading

Reviews (1): Last reviewed commit: "chore(guide): update contributing guide ..." | Re-trigger Greptile

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