Repository navigation
fix(workflow): the history row a graph edit writes carries no id, so the stopped attempt is never marked superseded #1611
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 0a5324772fb14d038262688a288a525a
Branch: dev3/fix/history-row-id
Base: 655aa71
At: 2026-10-29T00:20:22Z
Problem
#1604 taught the Runs list to mark an older attempt as superseded by <id>, but two of the six places that append to lane.history still push a bare row with no id. On those two paths the marker can never appear, because the client skips rows without an id.
Live main 655aa714609b34836d4b021072f6a3cbe593f0dd, plugins/workflow/src/service.js:
:667-675historyRow(run)returns{ id, task, status, at, failure? }; used at:606,:662,:1099,:1240.:1391(saveGraph— the edit dropped a node that was still running, so the run is ended) still pushes{ task: run.task, status: run.status, at: run.updatedAt }— noid, althoughrun.idis in scope.:1629(purgeDemosmigration) pushes{ task: run.task, status: run.status, at: run.updatedAt ?? 0 }— noid(note: there the demo map key isid, sorun.idmay be absent and the key must be used).
plugins/workflow/client.js:746-770 markSuperseded(rows) refuses to mark such a row: if (!row.id || !newest.id) continue. client.js:284 (history: [...(laneOf(item.id).history ?? [])]) hands the rows to the client unchanged.
Reproduction
- Start a workflow run and let it reach a running node.
- In the graph editor, delete that running node and save.
saveGraphends the run, pushes the bare history row (:1391) and emits the■ 已停止system message. - Start the same task again, let the new attempt finish, open Runs/History.
Observed: the old row has no superseded by marker — it reads like a sibling of the retry. Expected: the older attempt is marked as superseded by the newer one, which is the whole point of #1507/#1604.
A probe with the host's real row shape (history: [{ task, status: 'failed', at }] plus one live run with an id) imported from client.js reports supersededBy=undefined / expected the older host row to name the newer attempt, while plugins/workflow/test/client.test.js stays green — the existing #1507 test (around :2112) builds its input by hand with id: 'run-old', a field saveGraph never writes.
Scope (S)
service.js:1391→ use the existinghistoryRow(run).service.js:1629→historyRow(run), with no id fallback. Theidin that loop is the lane key (const lane = state.lanes[id]at:1626), not a run id: using it would write a workflow id into a history row, andmarkSupersededwould renderretry of <workflow id>;runHistoryRowswould also treat it as a run id when deduping. A legacy demo row withoutrun.idtherefore stays without an id andmarkSupersededskips it, exactly as today.- Add one regression test that builds the input from the host's real shape (a row from the
saveGraphend path — no hand-writtenid) and asserts the older attempt getssupersededBy/retryOf; keep the existing#1507test green.
Out of scope: changing nodeStatus, rendering copy, or a general "client fixtures must come from the host" contract (worth a separate later item; not needed for this fix). Do not refactor historyRow or the four appends that already use it — only the two bare pushes at :1391 and :1629 change, so this cannot collide with any follow-up to #1604.
Acceptance
- Deleting a running node, then re-running the task, marks the stopped attempt as superseded in the Runs list.
- The new test fails on
655aa714and passes with the fix; the existing#1507test is unchanged and green. - The regression test pins all three shapes, not just "it works now":
- the row the
saveGraphend path pushes (:1391) carries the run's realid; - the row
purgeDemospushes (:1629) carries the run'sidand the test asserts it is not the lane key — a demo record under lanewf-xwithrun.id: 'run-demo'must yieldid: 'run-demo', so a future id fallback fails the suite; a demo record withoutrun.idyields a row with noid; - a legacy row with no
idis still skipped bymarkSupersededwhile the newer attempt is marked — "same as today" is an assertion, not prose.
- the row the
- No history row ever carries a lane id as its
id(no fakeretry of <workflow id>). plugins/workflowsuite green,npm run verifyexit 0 at the PR tip.
Branch
dev3/fix/history-row-id
Activity
HugoXK commentedon Oct 29, 2026
Release
Written-by: FlyBot Lead
Released: 0a5324772fb14d038262688a288a525a
Reason: Issue closed via merged #1613; claim no longer needed.
At: 2026-10-29T02:18:28Z