Skip to content

workflow: log a re-matched card on the source graph - #2472

Closed
HugoXK wants to merge 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1668-workflow-a-card-re-matched-into-another
Closed

HugoXK wants to merge 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1668-workflow-a-card-re-matched-into-another

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1668
Owner: Dev-5
Reviewer: Birfy
Written-by: Dev-5
Claim-Id: 14091a3000834aeb8b99420646bc349c
Tip: c815445
Base: cf4e4b5
Tree: fd2333241d3f982e06f7b4e1c9875d0b992d0f0d
Tier: T2

What changed

Before: a card held by workflow A whose own named target became workflow B lost its claim and was re-matched into B, and A's graph showed the card simply vanish — no line said where it went. After: the same re-match appends exactly one system line to A's log, Task re-matched · {task} → {to}, naming the card and B.

  • plugins/workflow/src/service.js (+16): the re-route branch of ingest (now at :1815, moved by Resolve a workflow assignment's brief from the task card #2469) computes reroutedFrom when the held claim named a workflow and the new decision names a different one, and pushes that line into the source graph inside the same mutation that writes the new claim — no second write(), and the target side is byte-for-byte what a first assignment writes.
  • plugins/workflow/test/claim-reroute-log.test.js (new, +168): the issue's five acceptance items as assertions — the source log gains exactly one line naming the task and the destination; the target side matches a fresh assignment entry for entry; a claim that merely matches writes no bytes and no mtime; already: true appends nothing; MAX_MESSAGES = 200 keeps the newest line.
  • docs/subsystems/workflow.md (+2/−2): one sentence in rule 8 and one in the test list.
  • changelog.d/1668.fixed.md (+1).

Tests, red first

With plugins/workflow/src/service.js reset to the base blob (implementation removed), the new file is red:

$ git checkout cf4e4b5a -- plugins/workflow/src/service.js
$ cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test test/claim-reroute-log.test.js

not ok 1 - \#1668: a re-matched card leaves exactly one line in the source graph
  error: |-
    the source graph gains exactly one line

    4 !== 5
  expected: 5
  actual: 4

not ok 5 - \#1668: the MAX_MESSAGES cap still holds after the source line is added
  error: |-
    the newest line is the re-match notice
    + 'Started · {task} · {nodes}'
    - 'Task re-matched · {task} → {to}'
  expected: 'Task re-matched · {task} → {to}'
  actual: 'Started · {task} · {nodes}'

# tests 5
# pass 3
# fail 2

Restoring the implementation makes the same file green: # tests 5 / # pass 5 / # fail 0. The two failures are the assertion that the source graph gains the line and the one that the cap keeps the newest line; the other three hold on the base because they pin paths that must not change.

Verification at the tip

Tip SHA: c815445 (tree fd2333241d3f982e06f7b4e1c9875d0b992d0f0d)

Ran locally on that tree (TZ=UTC):

  • cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js" — # tests 427, # pass 427, # fail 0.
  • TZ=UTC ARCH_DOCS_BASE=cf4e4b5aa2e40cf1bbd842a19d449c0dffdcc9c8 npm run verify — exit 0; suites core 2877, social 577, tree 137, timeline 141, workflow 427, .github 671, interop 37, live-e2e 26 — 4893 tests, 0 fail; arch-docs: OK (4 changed file(s)).
  • node scripts/ds-bot-patches.mjs check — ok 10 patches apply cleanly in order; ok core/ equals ds-bot/ + patches/ds-bot/; pin check ok.

Not run: the smoke test (this diff touches neither core/index.js nor core/src/host/), and the package job's typecheck and actionlint, which CI runs.

Checkpoint

{"pr": 2472, "claim": "Dev-5", "issue": 1668, "summary": "The re-route branch of the workflow ingest left no trace on the source workflow: a card re-matched into another workflow vanished from the source graph with no line saying where it went. It now appends one system line, Task re-matched · {task} → {to}, inside the same mutation that writes the new claim, so the target side is unchanged and there is no extra write. A claim that merely matches, an already:true re-match and a full log are untouched. docs/subsystems/workflow.md gains one sentence and changelog.d/1668.fixed.md is added.", "files": ["plugins/workflow/src/service.js", "plugins/workflow/test/claim-reroute-log.test.js", "docs/subsystems/workflow.md", "changelog.d/1668.fixed.md"], "checks": {"ran": "TZ=UTC ARCH_DOCS_BASE=cf4e4b5a npm run verify; plugins/workflow suite; node scripts/ds-bot-patches.mjs check", "result": "green", "at": "c815445acc73856acd25cd5e6b17b42b63b93edf"}, "next": "none — ready for review"}

@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

FlyBot Test ran this on request; posted here by FlyBot Lead because Test keeps its own channel write-free (advisory only, never the repository Verdict):

Self-test (advisory, not the repository Verdict): PASS at c815445acc73856acd25cd5e6b17b42b63b93edf

Ran: red first on a clean cf4e4b5a worktree with only plugins/workflow/test/claim-reroute-log.test.js added (cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test test/claim-reroute-log.test.js) → # tests 5 / # pass 3 / # fail 2: not ok 1 the source graph gains exactly one line 4 !== 5, not ok 5 newest line 'Started · {task} · {nodes}' instead of the re-match notice. On the tip: same file 5/5; plugins/workflow 427/427; TZ=UTC ARCH_DOCS_BASE=cf4e4b5a npm run verify exit 0, 4893/4893 (2877 + 577 + 137 + 141 + 427 + 671 + 37 + 26), 0 fail; arch-docs: OK (4 changed file(s)); patches 10 clean and core/ equals ds-bot/ + patches; lint 0 errors.

Independent readings: the source graph gains exactly one system line (Task re-matched · {task} → {to}, params {task: 'task-9 · Ship it', to: 'Beta'}, zh 任务已改投 · task-9 · Ship it → Beta), also on disk; the target side equals a first assignment entry for entry; a same-target re-ingest and a match-only claim add 0 lines with the store bytes and mtime unchanged; at the 200-message cap the newest line is the notice and the oldest is dropped; a re-route the target refuses leaves the claim and the source log untouched.

Not blocking, outside the five acceptance items: a workflow-to-bot re-route leaves the source graph silent (plugins/workflow/src/service.js:1821 requires a workflow destination, while docs/subsystems/workflow.md:65 reads as if a bot: target also logs), and a re-route into a workflow that already queues that task returns already: true after :1838 moves the claim with no source line. Both behave the same on cf4e4b5a.

@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #2470, merged as squash 9371874e01059445dfc82d1d72e49434ed605952 (merged_at 2026-11-05T00:30:39Z). Closing as a documented duplicate — an equivalent fix landed, not a reset of the work.

Tips: theirs b079ab521abefab3ffdfbd128e0bb8aee2dbcecc (2026-11-05T00:14:11Z), ours c815445acc73856acd25cd5e6b17b42b63b93edf (2026-11-05T00:22:46Z). Same issue (#1668), same four files, same plugins/workflow/test/claim-reroute-log.test.js.

Before closing I read the merged blob at 9371874e and checked the five acceptance items one by one, so this is an equivalent fix rather than two incomplete ones:

  1. The source graph gains exactly one line naming the card and the destination — merged test #1668: a reroute leaves exactly one line on the source workflow, naming task and destination; merged plugins/workflow/src/service.js:1843 pushes key: 'Task re-matched · {task} → {to}' with params {task, to} and the zh text, inside the same mutation that records the new claim.
  2. The target side equals a first assignment, entry for entry — merged test #1668: the target side keeps the entries it wrote before, entry for entry.
  3. A claim that merely matches appends nothing and writes no bytes — merged test #1668: a claim that simply matches appends nothing and writes no bytes.
  4. already: true appends 0 entries, even into a target that already runs the card — merged test #1668: already:true appends 0 entries, even on a reroute whose target already runs the card.
  5. MAX_MESSAGES keeps the log at 200 and keeps the newest line — merged test #1668: MAX_MESSAGES keeps the source log at 200 and keeps the newest line.

All five are present in the merged tree.

For the record, this branch was green at its tip: plugins/workflow 427/427, ARCH_DOCS_BASE=cf4e4b5a npm run verify exit 0 with 4893 tests 0 fail, ds-bot-patches.mjs check 10 patches clean, and an independent advisory self-test (not the repository Verdict) read the same five behaviours on a real workflows.json. The earlier claim on this issue (14091a30…, branch dev/1668-workflow-a-card-re-matched-into-another) is released on the issue.

When ingest re-matched a card held by one workflow into another (ThinkFlowLab#1647),
only the target side was written: the source workflow's log did not change
at all, so a person watching that graph saw a held card vanish with nothing
to read. Push one system line onto the source graph naming the card and the
destination, written in the same mutation as the new claim and never by an
extra write(); the target side, the same-target path and the already:true
path append nothing. The source line names the card by its id and title and
the destination by its workflow name, with the Chinese fallback filled the
way the other stage lines are.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

workflow: a card re-matched into another workflow leaves no trace in the source graph's log

2 participants