Repository navigation
fix: clear stale failures and duplicate answers after model fallback - #139753
Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Before and after from the same isolated real-Gateway/browser scenario: a model/account rejection on the first request, a real fallback answer, then a real follow-up answer. The after run also passed reload checks. Raw transcript inspection confirmed one successful fallback answer and preserved the failed attempt for diagnostics. 188 focused tests passed across 15 files, including history pagination, delta/SSE recovery, exact-message lookup, and access restrictions. Full build passed; independent review is clean through P2. Screenshots contain synthetic conversation data, with avatars removed. |
6b8f933 to
4a2889e
Compare
|
Codex review: blocked before merge. Reviewed September 6, 2026, 12:58 AM ET / 04:58 UTC. ClawSweeper reviewWhat this changesThe PR makes Gateway history hide empty failed attempts after a successful answer from the same run, keeping Control UI answers consistent across live updates, reloads, pagination, and message lookup. Merge readiness⛔ Blocked before merge - 1 item remains Keep open: current main still retains empty provider failures after successful fallback, and the related merged refactor explicitly left this display defect unresolved. No blocking introduced defect was found. Priority: P2 Review scores
Verification
How this fits togetherThe Gateway projects stored transcript records into display history consumed by the Control UI and shared session reconciler. This projection controls which failed attempts remain visible without deleting diagnostic records. flowchart TD
A[Stored transcript attempts] --> B[Gateway display projection]
B --> C{Successful answer from same run?}
C -->|Yes| D[Hide empty failed attempts]
C -->|No| E[Preserve failure display]
D --> F[History pages and refreshes]
E --> F
F --> G[Control UI session reconciliation]
Before merge
Agent review detailsSecurityNone. PR surfaceSource +203, Tests +627, Docs +2, Other 0. Total +832 across 17 files. View PR surface stats
Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep recovery in the shared display projection, preserve raw diagnostics and partial output, and reconcile removed placeholders through bounded authoritative history refreshes. Do we have a high-confidence way to reproduce the issue? Yes, from source: a user message followed by an empty error attempt and a successful answer under the same run remains incorrectly visible on current main. The contributor also reports a real Gateway/browser reproduction; this review did not execute it. Is this the best way to solve the issue? Yes. Extending the existing projection owner addresses the stale row and reconciliation ambiguity while keeping diagnostic storage, provider routing, and durable answer identities unchanged. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 883d4d65bad1. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
|
Merged via squash.
|
Carry the existing #139792 repair and its merged #139715 test prerequisite. The neutral projection state comes from the owning helper, so this fixture works before and after the main-branch field rename in #139753. No session-first implementation changes. Co-authored-by: Peter Steinberger <steipete@gmail.com>
#139753 renamed the projection result's streamErrorFallbackPending and streamErrorFallbackRepaired to assistantErrorPending and assistantErrorRecoveryObserved, but one call site in this test kept the old names, leaving main red on check-test-types-core-2. Its targeted PR CI never selected this shard, so the break first appeared on a full main run.
Align the false-valued pagination fixture with the projection field names introduced in #139753 after #139715. Preserve all pagination assertions. The Gateway-root typecheck reproduces TS2353 before the change and passes afterward. All 30 history tests pass before and after; the full changed-file gate and independent P2 review pass.
…39766) * fix(tooling): diagnose declaration escapes into ancestor installs * fix(gateway): use current projection fields in session history test #139753 renamed the projection result's streamErrorFallbackPending and streamErrorFallbackRepaired to assistantErrorPending and assistantErrorRecoveryObserved, but one call site in this test kept the old names, leaving main red on check-test-types-core-2. Its targeted PR CI never selected this shard, so the break first appeared on a full main run.
…#139733) * fix(test): align runtime E2E failures with continuation recovery Use a missing-model response for selected-provider fallback proof. Preserve one same-model continuation before a provider-advertised outage exceeds the normal recovery window, while retaining exact HTTP 500 Telegram settlement and raw-error redaction. Recognize provider timeouts from their diagnostic classification instead of comparing clocks with different start boundaries. Require terminal error evidence and retain exactly one successful queued followup. Proof: five focused E2E tests pass, root test typecheck and scoped lint pass, and independent review is clean. The aggregate changed gate encounters the pre-existing services shard root-count limit (721 versus 720); no test roots are added. * fix(test): update history projection fixture fields Align the false-valued pagination fixture with the projection field names introduced in #139753 after #139715. Preserve all pagination assertions. The Gateway-root typecheck reproduces TS2353 before the change and passes afterward. All 30 history tests pass before and after; the full changed-file gate and independent P2 review pass.
…enclaw#139766) * fix(tooling): diagnose declaration escapes into ancestor installs * fix(gateway): use current projection fields in session history test openclaw#139753 renamed the projection result's streamErrorFallbackPending and streamErrorFallbackRepaired to assistantErrorPending and assistantErrorRecoveryObserved, but one call site in this test kept the old names, leaving main red on check-test-types-core-2. Its targeted PR CI never selected this shard, so the break first appeared on a full main run.
…openclaw#139733) * fix(test): align runtime E2E failures with continuation recovery Use a missing-model response for selected-provider fallback proof. Preserve one same-model continuation before a provider-advertised outage exceeds the normal recovery window, while retaining exact HTTP 500 Telegram settlement and raw-error redaction. Recognize provider timeouts from their diagnostic classification instead of comparing clocks with different start boundaries. Require terminal error evidence and retain exactly one successful queued followup. Proof: five focused E2E tests pass, root test typecheck and scoped lint pass, and independent review is clean. The aggregate changed gate encounters the pre-existing services shard root-count limit (721 versus 720); no test roots are added. * fix(test): update history projection fixture fields Align the false-valued pagination fixture with the projection field names introduced in openclaw#139753 after openclaw#139715. Preserve all pagination assertions. The Gateway-root typecheck reproduces TS2353 before the change and passes afterward. All 30 history tests pass before and after; the full changed-file gate and independent P2 review pass.
Related: #139410
What Problem This Solves
Fixes an issue where Control UI users saw “The agent run failed before producing a reply.” and a duplicate
×2answer after a model fallback had already succeeded. Reloading or opening older history could preserve or reintroduce the stale failure.Why This Change Was Made
The transcript correctly stored one failed attempt and one successful answer with the same run identity. Keeping the empty failure in display history made the live answer ambiguous to the shared client reconciler. The Gateway now retires empty failed attempts only after a visible successful runtime answer from that exact run, using one projection flow for legacy stream errors and provider failures.
Raw transcript diagnostics, partial replies, structured output, unrelated runs, and unresolved failures remain intact. Incremental history requests reset while recovery can remove a previously displayed row. Historical pages and exact-message lookup share bounded recovery context so navigating history follows the same visibility rule. Ordinary successful turns retain the existing fast path.
User Impact
A successful fallback displays its answer once, without a stale failed-attempt placeholder. Follow-up messages and reloads remain usable. No configuration, transcript migration, or protocol change is required.
Evidence
Recovery lookahead retains the existing message and byte limits; insufficient evidence preserves a failure. An opaque cursor cached before this fix and already past a failure is corrected by the next full history read.
The first CI run exposed an unrelated suppression-inventory line-number mismatch, already fixed on main by #139747. The branch was rebased onto that fix;
git range-diffconfirmed the reviewed patch is unchanged.The PR review reported no actionable code findings but could not inspect the linked media. Both uploaded images are reachable: a one-byte ranged GET returns HTTP 206 for each. HEAD follows a GET-signed storage redirect and returns 403, so it is not a valid reachability check here. The sanitized originals were visually inspected before upload; the live run also asserted no stale failure or duplicate badge before and after reload.