Skip to content

workflow: assigning a held card straight to a Bot leaves the source lane's graph silent #2485

Closed

Description

@HugoXK

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: c4637240bc5e4299ae63d5802ec34b8e
Branch: dev/5-bot-assign-source-log
Base: 80bc66c
At: 2026-11-05T01:40:40Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead

workflow.assign({ botId }) hands a card that a workflow lane holds straight to a Bot, and the lane that loses it records nothing — the source graph stays silent.

This is the second door into the same defect #2480/#2481 closed for re-matching: the re-match path (rematch/ingest) now writes one 任务已改投 · {task} → {to} line on the source lane, but the explicit "assign this card to that Bot" call never reaches that code.

Reproduction (live main 7f341a1b91aca95971e3c5634898794be0e41e09)

  1. A workflow lane W1 holds task T: state.claims[T] = { kind: 'workflow', id: W1 }, and W1's graph has its normal lines.
  2. Call assign({ botId: '<a live Bot id>', taskId: T, title: T }).

What happens: assign() short-circuits at plugins/workflow/src/service.js:1308 —

if (body.botId) return answer(routeBot(body))

— and routeBot() (plugins/workflow/src/service.js:922) only does rememberClaim(taskId, { kind: 'bot', id: bot.id }) + write(). It never calls the logSource() closure that #2481 added at :1829 for the re-match path, and the workflow(workflowId) item is never even looked up.

Result: the call returns { ok: true, matched: true, decision: { kind: 'bot', id: … } }, the claim moves to the Bot, and state.lanes[W1] gains 0 lines (source_delta: 0 on a real state file). The lane's graph and the Bot's view disagree about where the card went.

Same shape on the pre-#2481 base (f8ec27c2): the call path is identical, so this is not a regression from #2481 — it is the other door #2481 deliberately did not take (that PR's diff ends at the re-match handler).

Expected

One system line on the source lane, identical in shape to the #2480 fix:

kind: 'system'
key: 'Task re-matched · {task} → {to}'
text: '任务已改投 · {task} → {to}'

with {to} the Bot's roster name when the roster lists it and the id as fallback (the convention #2481 landed and #2475 uses for handoff.from). The destination's own state must not change; one write(), not two. When there is no lane holding the card (an unclaimed card assigned straight to a Bot), there is no source graph to write on and the call stays silent exactly as it is today.

Scope

  • plugins/workflow/src/service.js — routeBot() writes the source line when a non-Bot claim is being replaced; no change to the re-match path, to rememberClaim, or to the write count.
  • plugins/workflow/test/ — a case that pins "assign to a Bot from a held lane leaves exactly one source line, and the line names the Bot", plus the two no-op cases (no prior claim; already held by that Bot).
  • changelog.d/ fragment. No docs change expected: invariant 8 already states the contract this call is failing to honour (Docs-not-needed: with that reason is fine if the code says so).
  • Not in scope: core/client.js, patches/, the source-graph UI.

Dedupe (2026-11-05)

  • Issue search repo:ThinkFlowLab/FlyBot routeBot in:title,body → 0 hits.
  • reroute → 6 hits, all closed: #1668, #2470, #2472, #2480, #2481 (+ #2210, unrelated handoff contracts). None covers the botId door.
  • Live main grep: routeBot at service.js:922, logSource only at :1829-:1865 (re-match handler). No issue and no code covers the botId path.

Activity

  1. HugoXK commented on Nov 5, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: c4637240bc5e4299ae63d5802ec34b8e
    Reason: merged as f295853 (#2487)
    At: 2026-11-05T02:10:04Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions