Repository navigation
Commit 0dbcd79
authored
fix(workflow): an early-ended failed run logs neither the early end nor why, and a silent reply claims it stopped there (#1615)
Fixes #1577
Owner: Dev2
Reviewer: Reviewer
Written-by: Dev-2
Base: bde09d1 (live `main` when this
branch was cut)
Tip: 5fc75fb (the fork head; tree
`588d5fec…`)
Tree: 588d5fe
## What was wrong
`#1572` made a failure able to end the run early (`needs-human`,
`already-claimed`, `tip-unchanged`, `open-pr`): `failNode`
(`plugins/workflow/src/graph.js:721-735`) marks the node `done`, returns
`finished: true` with `earlyEnd`, and `service.js:448` finishes the run
with `run.earlyEnd`. `linesFor` receives `earlyEnd` at `service.js:497`,
but neither fail branch in `narrate.js` read it — only the complete
branch checks `finished`.
So the log of a run that ended early said neither that it ended early
nor why: with an empty reply it printed `Verify 这一步失败了,停在本节点。` while the
run was `done` and every node `done`, and the `⏹ 提前结束 · <reason>` line
that `#1572` earned never appeared. A reader could not tell "the Bot
failed and the run stopped" from "the pass produced no new tip, so the
run was closed on purpose".
## What changed
`plugins/workflow/src/narrate.js` only — both fail branches (live
`:102`, non-live `:154`) ask one helper first:
- `earlyEndLines(workflow, event)` returns `null` unless `event.earlyEnd
!= null`. When it is set, it emits the Bot reply if `event.text` has
one, then a `kind: 'system'` frame: key `⏹ Ended early · {reason}`,
params `{ reason }`, text `⏹ 提前结束 · <reason>`. No `tone`, so it never
renders in the failure colour.
- With no reply there is no bot line at all, rather than a line that
says the step failed: an empty bubble would be noise, and the sentence
it used to carry was false.
- The complete branch is untouched: a complete step that ends the run
early still closes on `✓ 完成 · …` and does **not** add a `⏹` line, so the
two paths never double up.
- Plain failures still say `停在本节点`, and `recovered` still says `↺ 失败恢复 →
…`; the regression tests pin both on this tip.
`graph.js` and `service.js` are untouched: `nodeStatus`, `finished`,
`doneCount` and `run.earlyEnd` keep exactly the semantics `#1572`
landed. The new line follows this file's existing frame contract
(English key + params + stored Chinese text, `#1489`), so the shell can
translate it and older rows keep the fallback.
## Red → green, honestly
Red first on the live base `bde09d1c`, with only
`plugins/workflow/test/narrate-early-end.test.js` added and `narrate.js`
at `main`: `TZ=UTC node --import ./test/resolve.mjs --test
test/narrate-early-end.test.js` — **7 tests, 3 pass, 4 fail**, exactly
the four early-end tests:
- `live fail with earlyEnd and no reply says early end, never failure`
- `live fail with earlyEnd keeps the Bot reply and adds the early-end
line`
- `non-live fail with earlyEnd says early end, never failure`
- `service: a Verify reply that marks tip-unchanged narrates the early
end`
The three that pass on the base are the regression locks (complete path
still `✓ 完成` with no `⏹`, plain failure still `停在本节点`, recovered still
`↺ 失败恢复`).
At this tip: the same file **7/7 pass**, and `TZ=UTC npm --prefix
plugins/workflow test` — **221 tests, 221 pass, 0 fail**.
## Files
```
3 files changed, 119 insertions(+)
crucially unchanged: plugins/workflow/src/graph.js, plugins/workflow/src/service.js
plugins/workflow/src/narrate.js | 15 ++++
plugins/workflow/test/narrate-early-end.test.js | 103 ++++++++++++++++++++++++
changelog.d/1577.fixed.md | 1 +
```
## Checks
`TZ=UTC ARCH_DOCS_BASE=bde09d1c npm run verify` at tree `588d5fec…` —
**exit 0**: core **1903**, social **528**, tree **125**, timeline
**129**, workflow **221**, `.github` **549**, interop **37**, live-e2e
**24**; oxlint **0 errors** (only the repository's pre-existing
warnings); `build-client --check` clean; `arch-docs: OK (3 changed
file(s))`; `ds-bot-patches check`: `ok ds-bot/ =
Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)`, `ok 10 patches
apply cleanly in order`, `ok core/ equals ds-bot/ + patches/ds-bot/`.
`node .github/scripts/changelog.mjs check` — fragments well formed, exit
0.
Not run: no live instance (no instance access), no browser; CI was not
waited on.
Docs-not-needed: narration copy only — `graph.js` and `service.js` keep
the state semantics `docs/subsystems/workflow.md` already describes, so
the page needs no new rule.
## Checkpoint
<!-- flybot:checkpoint -->
```json
{
"pr": 1615,
"claim": "Dev2",
"issue": 1577,
"summary": "A run that ended early (needs-human, already-claimed, tip-unchanged, open-pr) was narrated as a failed step: the log said the node failed and stopped there, and the reason never appeared. Both fail branches in narrate.js now ask one helper first and emit ⏹ 提前结束 · <reason>, keeping the Bot reply when there is one and emitting no bot line when there is none. The complete path still closes on ✓ 完成 with no second line, and plain failures and recoveries keep their wording. graph.js and service.js are untouched.",
"files": [
"plugins/workflow/src/narrate.js",
"plugins/workflow/test/narrate-early-end.test.js",
"changelog.d/1577.fixed.md"
],
"checks": {
"ran": "TZ=UTC ARCH_DOCS_BASE=bde09d1c npm run verify, exit 0 (core 1903, social 528, tree 125, timeline 129, workflow 221, .github 549, interop 37, live-e2e 24, oxlint 0 errors); narrate-early-end.test.js red first on bde09d1 3/7, green 7/7 here",
"result": "green",
"at": "5fc75fb29893f7fc5fae83f3de2bd6d361427583"
},
"next": "none — ready for review"
}
```
<!-- /flybot:checkpoint -->
Co-authored-by: HugoXK <hugoxk@users.noreply.github.com>1 parent a6755fa commit 0dbcd79
3 files changed
Lines changed: 119 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
92 | 103 | | |
93 | 104 | | |
94 | 105 | | |
| |||
100 | 111 | | |
101 | 112 | | |
102 | 113 | | |
| 114 | + | |
| 115 | + | |
103 | 116 | | |
104 | 117 | | |
105 | 118 | | |
| |||
147 | 160 | | |
148 | 161 | | |
149 | 162 | | |
| 163 | + | |
| 164 | + | |
150 | 165 | | |
151 | 166 | | |
152 | 167 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
0 commit comments