Commit 70704d9
fix(first-run-tour): stop promising a result once acceptance is lost (#15172)
Stacked on #15091 — base is `fix/14619-tour-unaccepted-run`, merge after
it.
#15091 gave the first-run tour a 15s acceptance deadline, which covers a
submission the backend refuses outright. It left one hole: a run that
*was* accepted and then loses its job without an outcome. Two live paths
do that, and **neither is the mid-run credits path this description
originally led with** — thanks @benjcooley for catching that:
| path | what it leaves behind | covered before this PR? |
| --- | --- | --- |
| accepted job dropped with **no status ever written** — the cloud
"waiting for a machine" job cancelled or reconciled away | nothing | ❌
no branch can fire |
| `handleServiceLevelError` ("Job has stagnated") — drops the job,
records a prompt error, never touches `workflowStatus` | a stale
`running` | ❌ the stale `running` shadowed the error branch |
| ~~mid-run credits (`handleAccountPreconditionError`)~~ | ~~stale
`running`~~ | ✅ **already covered** — #15161 clears the status, so it
ends via the existing `undefined`-after-`running` branch |
In the uncovered cases `runState` sits on `generating` forever and the
card keeps promising "Hang tight, your result lands right here the
moment it's ready."
The controller had two disarms and no re-arm. This makes losing
acceptance a signal in its own right: extend the existing
`tourRunAccepted` watcher so true -> false fails the run when it is
still `generating`.
```ts
watch(tourRunAccepted, (accepted) => {
if (accepted) stopAcceptDeadline()
else if (runState.value === 'generating') runState.value = 'failed'
})
```
No re-armed deadline — this is immediate, not a second timer.
The `'generating'` gate is what keeps healthy runs safe: every run
leaves the queue when it finishes. `handleExecutionSuccess` and
`handleExecutionError` write the terminal status and call
`resetExecutionState` in the same synchronous handler, and the status
watcher is registered before this one, so a finished run has already
left `generating` by the time this fires. Test 3 below covers exactly
that tick.
Tests, in the existing `'a run behind a dropped socket'` describe:
- accepted job removed with no status -> `failed`
- accepted job, status `running`, removed (the stagnation case) ->
`failed`
- accepted job, status `completed` written in the same tick as the
removal -> stays `succeeded`
- accepted job, status `failed`, then removed -> stays `failed`
The first two fail on the base branch (`expected 'generating' to be
'failed'`). Of the last two terminal-status guards, **only the
`completed` one discriminates** — ungated, the `failed` case writes
`'failed'` over `'failed'` and still passes. It is kept as documentation
of intent, not as a guard; the earlier claim that both pinned the gate
was wrong.
Two tests added in review:
- `stays failed when an unrelated workflow churns the status map` — pins
the transition gate below. Fails without it (`expected 'generating' to
be 'failed'`).
- `gives up on a stagnated job that leaves an error and a stale status`
— the other half of the stagnation path. Documents it; does not
discriminate the gate.
**Review fix:** the status watcher's `status === 'running'` branch was
unconditional, and its source re-evaluates whenever the `workflowStatus`
map is replaced (`mutateStatus` swaps the whole map, so *any* workflow's
change re-runs it) or an error flag flips. With a stale `running`
sitting there, each re-evaluation put the card back on "your result
lands right here" after this watcher had already failed the run. It is
now gated on an actual transition into `running`, which also removes the
registration-order dependency the old comment overclaimed away.
Complementary to #15161 (**merged 2026-08-13**), which fixes the same
user-visible symptom from the store side by clearing the stale status.
Independent of it: this is the controller refusing to promise regardless
of whether the store cleans up. Both are wanted; neither duplicates the
other.
Requested by @benjcooley in review on #15091 (acceptance-loss watch for
the mid-run credits variant) and by CodeRabbit (acceptance-loss
coverage, terminal statuses stay terminal).
## Tests
- 58 unit tests green in `useFirstRunTourController.test.ts` (54
existing + 4 new), full-file and each new test in isolation.
- `pnpm lint`, `pnpm typecheck`, `pnpm format:check` pass.
---------
Co-authored-by: Connor Byrne <c.byrne@comfy.org>1 parent 2e0ba75 commit 70704d9
2 files changed
Lines changed: 138 additions & 1 deletion
File tree
- src/renderer/extensions/firstRunTour/tour
Lines changed: 110 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
205 | 211 | | |
206 | 212 | | |
207 | 213 | | |
| |||
506 | 512 | | |
507 | 513 | | |
508 | 514 | | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
509 | 619 | | |
510 | 620 | | |
511 | 621 | | |
| |||
Lines changed: 28 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
79 | 88 | | |
80 | 89 | | |
81 | 90 | | |
| |||
118 | 127 | | |
119 | 128 | | |
120 | 129 | | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
121 | 147 | | |
122 | 148 | | |
123 | 149 | | |
| 150 | + | |
124 | 151 | | |
125 | 152 | | |
126 | 153 | | |
| |||
0 commit comments