Repository navigation
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: 51b59b987fa04ba2826cdffe436e8997
Branch: dev/3-402-condition-when
Base: c4dc6e4
At: 2026-11-02T11:48:45Z
A Condition link that cannot be honoured is saved as if it were a plain Link, silently. In Settings → Workflows, choose Condition and leave the output name blank, or type one the graph will not accept (result_ok, ready.now, with space): Add link succeeds, no error appears, and what lands on disk is an unconditional edge. At run time that branch is then taken whether or not the condition holds — the opposite of what the user asked for.
The canvas gives no second chance to notice: only loop edges are drawn dashed (plugins/workflow/client.js:1294); a Condition link is drawn exactly like a plain one, and the Settings canvas never shows the kind.
Reproduction (live main c4dc6e490c621d2d3681da4d808689b171c37efa)
Deterministic, through the real normalizeGraph, on the base commit (node /home/xuke/.dsh/bot/workspace/tmp/probe2152/condition.mjs):
good condition : [{"from":"a","to":"b","when":{"output":"ready","eq":"yes"}}]
blank output : [{"from":"a","to":"b"}]
underscored : [{"from":"b","to":"c"}]
So {when: {output: ''}} and {when: {output: 'result_ok'}} both come back as a Link with no when at all, and the save reports success.
Cause
plugins/workflow/src/graph.js:106-114—cleanWhenreturnsnullwhen the value is not an object, whenoutputis empty, or when it does not matchPORT_RE(:51/^[a-z][a-z0-9-]{0,40}$/).:141-143—cleanEdgereadsconst when = cleanWhen(edge.when, true)and then spreads...(when ? { when } : {}): a rejectedwhenis indistinguishable from an absent one.:562-564— the run loop doesif (!edge.when) take = true, so the downgraded edge fires unconditionally.plugins/workflow/client.js:1602— the form sendsedge.when = edgeForm.untilverbatim, including{output: '', eq: ''};:1761disables Add link only whenfrom/toare empty.
Expected
A when that is present but unusable is a refusal, not a downgrade: the save fails and says why (e.g. A condition link needs an output name like "ready"), through the existing save() → wf-err channel. The same rule applies to a loop's until: absent is fine (no early stop), but a partially filled one is refused rather than dropped. Legal values are preserved exactly as they are today.
Scope
plugins/workflow/src/graph.js—cleanEdge(and the caller that reports the error) rejects an edge whosewhen/untilis present but invalid instead of dropping it; no change to what a validwhen/untilmeans, no change to ranking or the run loop.plugins/workflow/client.js— Condition requires a non-empty output name before Add link is enabled, and a host refusal surfaces inwf-err; read-only canvas keeps committing nothing.plugins/workflow/test/*.test.js— the cases below.
plugins/** is not in patches/ds-bot/files/ and not in any patches/ds-bot/000*.patch (checked against the base tree: the patch scheme mirrors core/ and .github/scripts/), so no generate and no bundle rebuild is involved.
Acceptance (red first, on the base commit)
{when: {output: ''}}→ a save error, and nothing is written (today: ok, edge withoutwhen).{when: {output: 'result_ok'}}→ a save error (same today-gap).{when: {output: 'ready', eq: 'yes'}}→ kept exactly.- A loop sending
{until: {output: ''}}→ a save error; a loop with nountilstill saves. - Existing graphs read back unchanged: templates,
deliveryWorkflow,weeklyWorkflowand their condition edges stay green. - Read-only canvas: a click still commits nothing.
Dedupe
Searched live main and the issue log before opening: condition link (25 hits), edge condition workflow (15), unconditional edge (6), titles unconditional / edge condition / when output — nothing covers a malformed when being dropped silently. Backlog P-79 is "an onFail edge cannot be added", P-32 is "the inspector cannot change outputs"; both are different surfaces. The suggestion to turn the free-text output name into a dropdown of the source node's outputs belongs to this same form, so it is not filed separately.
Activity
HugoXK commentedon Nov 2, 2026
Release
Written-by: FlyBot Lead
Released: 51b59b987fa04ba2826cdffe436e8997
Reason: merged as 41ff819 at 2026-11-02T12:57:33Z
At: 2026-11-02T12:58:59Z