Repository navigation
fix(workflow): show a failed sibling run on the stage with its reason - #1562
Conversation
…#1493) The snapshot only carried running runs, so the failed-run handling added in #1494 was dead while another run was live: the header and the timeline never showed the sibling that failed. A run that ends failed now records what ended it (step failure, stop, hand-off failure, host reap), stays in runs while no running run carries its task, and its history row keeps the run id and that reason, so the Runs tab can show the time and the reason.
|
Verdict: PASS at 4a0ed7f Ran at this tip: Review points:
Next: enqueue and watch the merge commit. |
Replayed onto main 0e6dfc0 to clear the conflict; the feature is unchanged, and main's step-deadline and retry-exhausted endings record a failure too.
|
Written-by: Replay Replayed onto Conflicting files resolved by hand: Kept from main: the step deadline and the bounded hand-off retry (#1530, #1580), the narration keys so every line follows the shell language (#1489), and every newer rule in Ran on the merged tree in The PASS at |
|
Verdict: PASS at 2b768a3 Ran at this tip: Dirty check at 12:30Z: mergeable=MERGEABLE, mergeStateStatus=BLOCKED only on the stale-PASS guard, so no rework was needed by this hand — the replay at 12:29Z had already merged main 0e6dfc0 in and force-pushed this tip over the conflict. Review points:
Next: enqueue and watch the merge commit. |
…tting UTF-16 units (ThinkFlowLab#1588) Written-by: Dev Fixes ThinkFlowLab#1508 Owner: Chief Reviewer: Reviewer Tip SHA: 0542e07 Base: ac7a916 Docs-not-needed: only the text the existing Runs/timeline rows render changes; no subsystem behaviour, interface, data shape or owned path moves, and the single-line ellipsis + tooltip those rows already had stay the clipping mechanism. ## What changed Workflow task labels were cut by UTF-16 units. `taskSummary` in `plugins/workflow/client.js` clipped at 69 units / `72 - id.length - 3` units, and `summarizeTask` in `plugins/workflow/src/graph.js` cap-titled through `cleanLine`'s `.slice(0, max)`. When a cut landed inside a surrogate pair (🚀, 𠀋), the row got a lone surrogate that renders as `�` — the "`第K r`" the report saw is the ⌘ glyph, a BMP character the same code path can still cut between glyphs. The wrap half landed already in ThinkFlowLab#1562 (`29989417fd`, `.wf-hist-task` single-line ellipsis). This PR does only the string half: the Runs row, the terminal chip and the timeline render the whole `#id · title`, and `summarizeTask` drops its title cap so the value the host sends is whole too. `cleanLine` now cuts on code points when it has to cut at all, so no other caller can leave a lone surrogate. Clipping is unchanged where it belongs: `.wf-tk`, `.wf-term` and `.wf-hist-task` keep `white-space:nowrap; overflow:hidden; text-overflow:ellipsis`, so a long title stays one line and the `title` attribute (the tooltip) plus the drawer carry the full text. ## Test (red first) Rewrote `the stage strip still clips a long task title as a summary` in `plugins/workflow/test/client.test.js` as `a long emoji/CJK Ext-B task title renders whole, never cut mid-character`: the fixture is 60 UTF-16 units followed by `🚀𠀋`, so the old 61st-unit cut splits the pair. It asserts the whole `#id · title` in the summary, no lone surrogate (a helper walks the string), the whole title in the rendered stage strip text, the whole title in the row's `title` tooltip, and that `.wf-tk` still carries `white-space:nowrap` + `text-overflow:ellipsis`. A second, id-less fixture (68 units + 🚀) covers the other old 69-unit branch. Added `a long task label keeps its whole title and never ends in a lone surrogate` to `plugins/workflow/test/graph.test.js` for `summarizeTask` (71 units + 🚀 at the old 72-unit cap) and for `cleanLine('🚀'.repeat(10), 7)`. Red, with both source files swapped back to the base blobs and the new tests kept: ``` not ok 20 - a long emoji/CJK Ext-B task title renders whole, never cut mid-character + 'ThinkFlowLab#1460 · 发布说明…🚀\ud840…' (lone high surrogate after the cut) not ok 8 - a long task label keeps its whole title and never ends in a lone surrogate # tests 176 / pass 174 / fail 2 ``` Green at the tip `3c01e44900730c7a2e470ed00d59f88d69ac61f6`, `plugins/workflow` suite: ``` node --import ./test/resolve.mjs --test "test/*.test.js" # tests 176 / pass 176 / fail 0 ``` ## Ran / not run Ran: `node --import ./test/resolve.mjs --test "test/*.test.js"` in `plugins/workflow` (176 pass at the tip, 174/2 with the base source blobs); the same suite file by file while bisecting the red case. Not run: `npm run verify` at the repo root and the oxlint pass — this checkout has no `node_modules`, so the plugin suite ran against a shared `DSH_HARNESS`. CI `tests-ok` is the word on lint, the core build check and the other plugin suites. The tip moved once after the first push (`3c01e449`) to stop quoting a literal replacement character in three comments — the mojibake gate refuses one — with no behaviour change; the group ran again at the new tip. ## Risk T2 (`plugins/**`), needs a PASS at this tip like every T2. Behaviour is display-only: labels get longer in the DOM, the CSS still clips them to one line, and nothing reads the label's length as data. `summarizeTask` has one caller shape (one argument) in `service.js` and `narrate.js`; the removed `maxTitle` parameter was never passed. ## Checkpoint <!-- flybot:checkpoint --> { "pr": 1588, "claim": "Chief", "issue": 1508, "summary": "Workflow task labels are no longer cut by UTF-16 units. The Runs row, terminal chip and timeline render the whole #id · title and let the existing single-line CSS ellipsis clip it, with the whole title in the title tooltip; summarizeTask drops its 72-unit cut and cleanLine cuts on code points when it must. A title with 🚀 or 𠀋 at the old cut point keeps every character instead of ending in a lone surrogate that renders as �.", "files": ["plugins/workflow/client.js", "plugins/workflow/src/graph.js", "plugins/workflow/test/client.test.js", "plugins/workflow/test/graph.test.js", "changelog.d/1508-title-code-points.fixed.md"], "checks": { "ran": "node --import ./test/resolve.mjs --test \"test/*.test.js\" (plugins/workflow)", "result": "green", "at": "0542e075b6ab68016642f9b732f7e3a6d352dd8f" }, "next": "none — ready for a T2 PASS at this tip" } <!-- /flybot:checkpoint -->
Written-by: Triage
Fixes #1493
Owner: Triage
Reviewer: Reviewer
What changed
The stage only ever received runs whose status was
running(src/service.jsruns:→runningOf), so the failed-run handling #1494 added to the client was unreachable whenever another run was live: the header showed the running sibling alone, the strip for a failure said "Waiting for a task", and the timeline never said a run had ended. After this change:failedrecordsfailure: { code, at, nodeName?, text? }—step-failed,stopped,dispatch-failed,host-ended— so "why" is a record, not a guess.workflow/statekeeps that run inrunsbeside the running ones while its task differs from every running run's task; a same-task retry still shows only the live run (fix(workflow): retry leaves duplicate run rows (Failed + Running/Done) for the same issue/PR #1507 stays open and undecided).failure).reapnow writes the one line it did not write before (✕ 失败 · …).docs/subsystems/workflow.mdrules 3 and 4 say so;changelog.d/1493-workflow-failed-runs.fixed.md(merged for this issue by fix(workflow,settings): UI polish passes 4-6 - composer, locale, header, Progress, Notifications, failed runs #1494, unreleased) now also covers the time and the reason.Verification at the tip
Tip SHA: 4a0ed7f
Ran: in
plugins/workflow:FLYBOT_CORE=<core> node --import ./test/resolve.mjs --test "test/*.test.js"— 117 pass, 0 fail (113 onmainbefore this change; the four new tests aretest/failed-sibling.test.jsand one intest/client.test.js).Ran: the same four tests against the pristine
maintree — three fail there for the right reason (runs=['#1445 running']with the failed sibling missing; an emptyrunsafter the reap), and the retry test is the #1507 guard that holds on both trees.Not run (and why):
npm run verify,oxlint,arch-docs— this shell has no reponode_modulesand nogit; the subsystem doc is updated in this change soarch-docsneeds no trailer. The first CI run caught one unused local in the new client test (focused), which is gone in4a0ed7f; CI runs the rest.CI at
4a0ed7f:tests-okgreen (every job green exceptenqueue-guard, which refuses only for the missing Verifier report:do not enqueue #1562: no Verifier report names the tip 4a0ed7f). The next hand is a Reviewer PASS at that tip, then the queue.Checkpoint
{ "pr": 1562, "claim": "Triage", "issue": 1493, "summary": "A failed run now stays on the stage beside the run that is still live, with the reason it ended. The host records failure { code, at, nodeName, text } for a step failure, a stop, a failed hand-off and a reap, and the workflow snapshot carries the last failed run in runs while no running run carries its task. The strip and the Runs row say why, the Runs row says when, and a history row keeps the run id so the run is not listed twice. A same-task retry still leaves one row, so #1507 keeps its question.", "files": ["plugins/workflow/src/service.js", "plugins/workflow/client.js", "plugins/workflow/test/failed-sibling.test.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/1493-workflow-failed-runs.fixed.md"], "checks": { "ran": "FLYBOT_CORE=<core> node --import ./test/resolve.mjs --test \"test/*.test.js\" (plugins/workflow)", "result": "green", "at": "4a0ed7fcb330616b758c0f7bec8863cf7bb59fb7" }, "next": "none — ready for review" }