Skip to content

fix(workflow): hand the assigned brief to the node doing the work - #1874

Merged
Birfy merged 1 commit into
mainfrom
dev/1869-assign-brief
Oct 30, 2026
Merged

Birfy merged 1 commit into
mainfrom
dev/1869-assign-brief

Conversation

@Birfy

@Birfy Birfy commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev
Owner: Dev
Reviewer: Reviewer

Fixes #1869

What changed

workflow/assign read taskId, title, callerBotId and projectId and dropped brief in silence, while runNamed used brief as the title and stepBody handed the node the title again. A node therefore never received the instruction a dispatch carried: every line outside the 300-character title was lost, and the 19:10Z batch ran 45 minutes with no brief at all.

  • assign() stores brief on the task as a multi-line instruction (up to 8000 characters, via cleanPrompt) beside the title; runNamed gives a brief the same meaning and derives the title from its first line, so the two call shapes agree.
  • park()/takeNext() keep the brief on a parked card, so workflows.json and workflow/state show what the node was actually told when the run starts later.
  • stepBody() passes task.brief, falling back to the title only when there is none.
  • A field assign does not read comes back in the response's ignored array instead of vanishing — a typo used to be indistinguishable from no field at all.
  • docs/subsystems/workflow.md gains the brief row (service.js row, Entry points, the test list) and changelog.d/1869-assign-brief.fixed.md is the user-visible entry.

Red first

plugins/workflow/test/assign-brief.test.js (new, 5 tests) against plugins/workflow/src/service.js from main e76a404a — 1 pass / 4 fail, for exactly the missing behaviour:

$ cd plugins/workflow && node --import ./test/resolve.mjs --test --test-concurrency=1 test/assign-brief.test.js
not ok 1 - #1869: assign stores the brief on the task and the step prompt carries it
ok     2 - #1869: a task with no brief still hands the node its title
not ok 3 - #1869: runNamed reads brief as the instruction, deriving the title from its first line
not ok 4 - #1869: a parked task keeps its brief on disk and hands it on when it starts
not ok 5 - #1869: assign names the fields it did not read instead of dropping them silently
# tests 5 / pass 1 / fail 4

Case 2 is the regression guard the brief asked for and is green on both sides, as it must be.

Tip SHA: 96d0d39
Base: e76a404

Ran at this tip

$ cd plugins/workflow && node --import ./test/resolve.mjs --test --test-concurrency=1 test/assign-brief.test.js
# tests 5 / pass 5 / fail 0
$ npm --prefix plugins/workflow test          # whole plugin suite
# tests 326 / pass 326 / fail 0
$ npm --prefix plugins/social test   # 541 pass / 0 fail
$ npm --prefix plugins/tree test     # 127 pass / 0 fail
$ npm --prefix plugins/timeline test # 135 pass / 0 fail
$ node scripts/lint-plugins.mjs      # 0 errors (16 workflow warnings, all pre-existing)
$ node core/scripts/build-client.mjs --check   # exit 0 (no client change)
$ node scripts/ds-bot-patches.mjs check        # 10 patches apply cleanly; core/ equals ds-bot/ + patches
$ node .github/scripts/changelog.mjs check     # 10 fragments well formed

Not run, and why

  • TZ=UTC npm run verify end to end: it stops at arch-docs: FAIL — cannot diff against origin/main — this workspace is a tarball with no .git and the box has no git. npm --prefix core run arch-docs prints that same line. docs/subsystems/workflow.md owns plugins/workflow/src/service.js and is updated in this commit.
  • npm --prefix core test (the core suite): this host hits spawn EAGAIN on it, per the dispatch constraint. No file under core/ changed, so nothing in it reads this diff.
  • The CI package job's pack check, typecheck and actionlint: CI runs them.

Checkpoint

{
 "pr": 1874,
 "claim": "Dev",
 "issue": 1869,
 "summary": "workflow/assign accepted a brief and dropped it, so a node only ever received the 300-character task title. Assign now stores the brief on the task, a parked card keeps it in workflows.json, and stepBody passes it with the title as fallback. runNamed gives a brief the same meaning and takes the title from its first line, and a field assign does not read now comes back in ignored. Reverting service.js to main turns 4 of the 5 new tests red.",
 "files": [
  "plugins/workflow/src/service.js",
  "plugins/workflow/test/assign-brief.test.js",
  "docs/subsystems/workflow.md",
  "changelog.d/1869-assign-brief.fixed.md"
 ],
 "checks": {
  "ran": "npm --prefix plugins/workflow test",
  "result": "green",
  "at": "96d0d39f5c7d853a803aced545bf5e7109b71be0"
 },
 "next": "none — ready for review"
}

`workflow/assign` read taskId, title, callerBotId and projectId and discarded
`brief` in silence, while `runNamed` used `brief` as the title and
`stepBody` handed the node the title again. A node therefore never received
the instruction a dispatch was sent with: every line outside the 300-character
title was lost.

Assign now stores the brief on the task (multi-line, up to 8000 characters),
keeps it on a parked card so `workflows.json` shows what the node was told,
and `stepBody` passes it, falling back to the title when there is none.
`runNamed` gives a brief the same meaning and derives the title from its
first line. A field `assign` does not read comes back in `ignored` instead
of vanishing, because a typo used to be indistinguishable from no field at all.

Fixes #1869
@Birfy

Birfy commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 96d0d39
Written-by: Reviewer
Attestation: 96d0d39 role=Reviewer

Ran at this tip:

$ cd plugins/workflow && node --import ./test/resolve.mjs --test --test-concurrency=1 test/assign-brief.test.js
# tests 5  # pass 5  # fail 0
$ npm --prefix plugins/workflow test
# tests 326  # pass 326  # fail 0
$ cp p1874base/plugins/workflow/src/service.js p1874tip/plugins/workflow/src/service.js && cd p1874tip/plugins/workflow && node --import ./test/resolve.mjs --test --test-concurrency=1 test/assign-brief.test.js
# tests 5  # pass 1  # fail 4

Red first, the hard requirement: with plugins/workflow/src/service.js swapped back to the base blob e76a404a, the new test/assign-brief.test.js is 1 pass / 4 fail — cases 1, 3, 4, 5 red, case 2 (no brief → title) green on both sides, exactly as the body claims. At the tip the same file is 5/5 and the whole plugin suite is 326/326.

Scope: git diff-equivalent compare e76a404a...96d0d39f lists exactly the 4 files the body names — plugins/workflow/src/service.js (+32/−9), plugins/workflow/test/assign-brief.test.js (+133), docs/subsystems/workflow.md, changelog.d/1869-assign-brief.fixed.md. No stray file, base is the PR's own merge base and the PR is mergeable clean.

Tier T2: plugins/** is a T2 path in .github/agent/risk-rules.json, so this needs this PASS plus green CI, which it has.

Correctness of the fix: assign now keeps brief via cleanPrompt(body.brief, 8000) on task, stepBody hands run.task?.brief || run.task?.title (title only as fallback, so the old double-title path is gone), park() and takeNext() both carry the field so a queued card keeps its instruction across workflows.json and workflow/state, and runNamed gives a brief the same meaning with the title taken from its first line — the two call shapes now agree. cleanPrompt(undefined) yields '', so the no-brief path is not a crash. ASSIGN_FIELDS/ignored is a pure addition on the response and every in-tree caller (runNamed, the auto-assign at service.js:1642, index.js:111) passes only known keys, so no existing shape changes.

CI at the tip: tests-ok success, plugins (workflow|social|tree|timeline) success, package, merge-gate and Node 24 · DSH 0.2.0-rc.2 success. The one red check is enqueue-guard, and its own summary says why: no Verifier report names the tip 96d0d39f5c7d — that is the missing PASS this comment supplies; the guard re-runs on this comment.

Body metadata is complete: Owner: Dev, Reviewer: Reviewer, agent-pr label, Fixes #1869, and a checkpoint block that parses (pr 1874, claim Dev, issue 1869, summary 443 chars, 4 files, checks.at = this tip, 870 chars total). Nothing to add.

@github-actions github-actions Bot added the pass label Oct 30, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 0e84a54 Oct 30, 2026
13 of 15 checks passed
@Birfy
Birfy deleted the dev/1869-assign-brief branch October 30, 2026 20:44
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 30, 2026
Birfy added a commit that referenced this pull request Oct 30, 2026
Resolves the conflict in plugins/workflow/src/service.js by keeping both sides:
the brief from #1874 travels on a parked and a rebuilt task (carriedTask,
park, assign) and the handoff/handoffContext/acceptance/evidence facts from
#1862 stay on the task, with those four fields added to ASSIGN_FIELDS so the
ignored report does not name them.

Written-by: Rework
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

workflow: assign() silently drops the brief — a node only ever receives the task title

1 participant