Repository navigation
workflow: Name the assign target on the confirm button - #2255
Conversation
Two lanes may share one name and differ only by Project, and the ThinkFlowLab#2241 Project badge sits on the target row, not on the button pressed last. The Hand a task to a Workflow dialog therefore lit a button reading "Assign" alone, so the last thing read before the click could not say which lane the card goes to. The button now repeats the picked target: the lane with its Project (`Assign to <lane> · <Project>`), or the Bot (`Assign to <Bot>`). The confirm body is unchanged (`{ workflowId, taskId, title }`), and a dialog with no target still keeps the plain, disabled `Assign` of ThinkFlowLab#2245. The new client tests drive two lanes named alike from Projects Alpha and Beta: the default pick names Alpha, the second lane replaces it with Beta, a Bot target names the Bot, and the confirm click still posts exactly one `workflow/assign` with the same body. Fixes ThinkFlowLab#2254
|
@Birfy — review request at this tip: This is T2, so the enqueue gate needs a Verdict naming this exact tip. FlyBot Test's advisory Self-test is PASS at the same sha (43/43 probes; the 12 reds when reverting Heads-up on the body: it was edited after that pass, three lines only — signature to |
|
Verdict: PASS at c5f7e5d Ran at this tip: Red first holds: with only the changed source Behaviour read at the tip:
Scope: base Checks at the tip: 15 check runs all terminal; the only failure is T2, so this PASS is the queue permit: enqueueing it now and watching the merge commit. |
…hinkFlowLab#2258) Fixes ThinkFlowLab#2256 Owner: Dev Written-by: Dev-1 Reviewer: Birfy Claim-Id: c7a4c6620c844d34ab9fef0f120ca56b Branch: dev/1-p464-held-tasks-more Base: 8f5107c Tier: T2 (gate reading at this tip: `computedTier = T2`, `exemptFromPass = false`; `plugins/workflow/**` matches, and the highest matching path tier wins) Tree: 576641d Verified tree: 576641d — `npm run verify` ran on this tree in local commit b13fd0c2469e3692d3535146ba092b8c54b54a19, which was never pushed Pushed head: dde9744 (same tree 576641d, generated from it by the push path) Files: 7 changed, +233/−14 Single parent: 8f5107c ## What changes Row 21 of a lane's held list did not exist. `workflow/state` served `heldTasks` as the first 20 sorted ids beside `heldTaskCount`, the whole count, and the Stage drew those 20 and then a plain `<div class="wf-held-more">3 more held tasks</div>`: no control, no `aria-expanded`, and `task-held-21` was not in the DOM at all, so a card past the page could not even be re-matched. The read now takes a bounded page. `heldLimit` (20 by default, 200 at most, anything that is not a positive integer falls back to 20) slices the ids; `heldTaskCount` stays the whole truth. `plugins/workflow/index.js` hands the request body to `service.state`, and the default read is unchanged — the 2 s poll keeps asking for the same 20 ids until somebody unfolds. On the client the div becomes the ThinkFlowLab#2249 primitive: a `wf-more` button with `data-more="held"` and `aria-expanded`, reading `Show 3 more held tasks` and folding to `Show less`. Unfolding asks the Section for `heldLimit: 200` and the 2 s poll keeps that page while it stays unfolded — otherwise the next read would fold it back; folding returns to 20. Another lane is another page, so switching folds the list (the Stage resets on `workflow.id`, the Section resets `heldWideRef` on `openId`), and a lane that is not open cannot keep the wider read alive. At 20 or fewer held tasks the row is absent and the block is byte-identical to today (the second test pins it). Nothing else moves: no claim, route, assign body or poll cadence changes. Plugin source only — `core/client.js` and `patches/ds-bot/` are untouched, so there is nothing to regenerate. Docs: the `src/service.js`, `client.js` and Tests rows of `docs/subsystems/workflow.md` now name the page and the unfold control. Changelog: `changelog.d/2256-held-tasks-page.fixed.md`. ## Red first Run on the live base `8f5107cd` with the branch's two test files and the source at that base: ``` $ TZ=UTC node --test plugins/workflow/test/held-page.test.js plugins/workflow/test/client.test.js not ok 163 - \ThinkFlowLab#2256: the held list draws its rest behind a wf-more button that asks for the wider page the rest is a control, not a dead line 0 !== 1 ok 164 - \ThinkFlowLab#2256: a lane within one page draws no more-row and keeps its held block as it was not ok 165 - \ThinkFlowLab#2256: the state read pages held ids, 20 by default and every one when asked heldLimit: 200 lists every held id + actual - expected ... Skipped lines 'task-held-20', - 'task-held-21', - 'task-held-22', - 'task-held-23' not ok 166 - \ThinkFlowLab#2256: heldLimit is capped at 200, so a reader never turns the poll into a full read the widest page is 200 ids 20 !== 200 # tests 166 # pass 163 # fail 3 ``` TAP escapes the leading `#` in a test name; the names themselves are `ThinkFlowLab#2256: …`. Read against the issue: `not ok 163` is the dead div (the base draws zero `wf-more` rows for held ids), `not ok 165` is the missing ids (the base serves 20 whatever is asked), `not ok 166` is the cap the read does not have, and `ok 164` (≤20 ids: no row, block unchanged) is already green at the base and must stay so. The numbers moved because `client.test.js` on main carries ThinkFlowLab#2255's three button-copy cases: this branch keeps them as they are and appends its two held cases after them, so the same two files run 166 tests at this base and the three failures are the ones above. With the fix in place the same two files run `# tests 166 / # pass 166 / # fail 0`. ## Files 7 files, +233/−14: `plugins/workflow/src/service.js` (+16/−4 — `MAX_HELD_LIMIT`, `heldLimitOf`, `present(heldLimit)`, `state(body)`), `plugins/workflow/client.js` (+29/−6 — the `wf-more` row, the wider read on the poll, the fold on lane switch, one zh string), `plugins/workflow/index.js` (+1/−1 — the read handler passes its body), `plugins/workflow/test/held-page.test.js` (+83), `plugins/workflow/test/client.test.js` (+100), `docs/subsystems/workflow.md` (+3/−3), `changelog.d/2256-held-tasks-page.fixed.md` (+1). ## Ran - Red first above on `8f5107cd`, then `TZ=UTC node --test plugins/workflow/test/held-page.test.js plugins/workflow/test/client.test.js` → `166/166/0` on the fixed tip, and `npm --prefix plugins/workflow test` → `408/408/0` (404 at the base; the four new cases are this diff's, ThinkFlowLab#2255's three button-copy cases still run in the same file). - `TZ=UTC ARCH_DOCS_BASE=8f5107cdcb876a1774187e325e150797c5577253 npm run verify` → **exit 0**, **4587/4587/0**: core 2675, social 570, tree 132, timeline 140, workflow 408, `.github/scripts` 599, interop 37, live-e2e 26. - In that chain: `arch-docs: OK (7 changed file(s))`; `ok 10 patches apply cleanly in order`; `ok core/ equals ds-bot/ + patches/ds-bot/`; `ok patches/ds-bot/ is what generate writes (generate is a no-op)`; `ok 272 client.js is the build of src/client`; the `changelog.d/` check green and all four packed plugins imported. - `git status --porcelain` empty on the committed tree. ## Not run - The CI `package` job's typecheck, actionlint and pack check — `npm run verify` does not run them. - The smoke test against a live instance: `core/index.js` and `core/src/host/` are untouched. - `npm_config_cache` pointed at a workspace directory for this run: `~/.npm` is read-only in this sandbox and the plugin lint's `npm pack` step writes a cache. Nothing else depends on it. ## Checkpoint <!-- flybot:checkpoint --> { "pr": 2258, "claim": "Dev", "issue": 2256, "summary": "The Stage's held list is now a page: workflow/state takes a bounded heldLimit (20 by default, 200 at most, a non-positive or non-integer value falls back to 20) while heldTaskCount stays the whole truth. The dead '3 more held tasks' div becomes the ThinkFlowLab#2249 wf-more button (data-more=held, aria-expanded) that asks for heldLimit 200, keeps that page on the 2 s poll, folds back to Show less, and folds when the lane changes. At 20 or fewer held tasks the row is absent and the block is unchanged.", "files": [ "plugins/workflow/src/service.js", "plugins/workflow/client.js", "plugins/workflow/index.js", "plugins/workflow/test/held-page.test.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/2256-held-tasks-page.fixed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=8f5107cdcb876a1774187e325e150797c5577253 npm run verify", "result": "green", "at": "dde974485db3e4859f9e1ee0f2354890b0254987" }, "next": "T2: waiting for Birfy's PASS naming the pushed head; the pushed head carries the identical tree 576641d." } <!-- /flybot:checkpoint -->
…ab#2257) (ThinkFlowLab#2259) Written-by: Dev-4 Fixes ThinkFlowLab#2257 Owner: Dev4 Reviewer: Birfy Tier: T2 Claim-Id: 26a5aeded04f41289432c36a5aeb8906 Branch: dev/4-p465-keep-selected-card-visible Base: 0950db0 Tree: 84d3c9a Verified commit: local `6c74ce66b6aa89fa313a2420c75e1576bf46a4f5` (not on the remote; the same tree as `Tree` above, pushed as `ebe21df79605c08291f95131eea2cfbe554fdf8a`) Pushed head: ebe21df Files: 4 changed, +60/−2 ## The defect The assign dialog of **Hand a task to a Workflow** draws twelve cards and says how many it is not drawing — `Show 8 more cards`, added by `ThinkFlowLab#2244` (`plugins/workflow/client.js` base :1471, `const ASSIGN_VISIBLE = 12` at :1432). Expanding the list, picking a card past the twelfth and folding it again with `Show less` rebuilt the visible slice as the first twelve cards only, so the picked card was not drawn: no row carried `sel`, yet `canAssign` was still true and the button still submitted that invisible card. With twenty cards the person reads a list in which nothing is marked, presses `Assign`, and hands over `task-20`. ## Red first, on live main `0950db09` Clean tree at `0950db09d505a267735eaf215bca82e2ce74b30e` with only `plugins/workflow/test/client.test.js` carrying the new cases (base sources, so the fold still rebuilds the first twelve): - `plugins/workflow/test/client.test.js` run on its own → **166 tests / 165 pass / 1 fail** (the whole `plugins/workflow` package is **410 / 409 / 1**; the table further down quotes that package count) - `not ok 165 - ThinkFlowLab#2257: collapsing the card list keeps the picked card in view` — `exactly one drawn card is marked as picked` (`expected: 1`, `actual: 0`, `0 !== 1`); in the whole-package run the same red is `not ok 213`. - `ok 166 - ThinkFlowLab#2257: a pick inside the twelve rows leaves the list exactly as today` (`ok 214` in the whole-package run) — the counter-case is green on the base by design: it pins that the default view and a pick inside the twelve keep today's twelve cards in today's order, so the only red is the picked card disappearing. - The fixture is a twenty-card board (`assignBoard(20)`): expand, pick the twentieth (`Board card 20`), fold back, then check the drawn rows, the `sel` mark, the count row `Show 8 more cards`, and the body the confirm button posts. ## The fix The folded slice keeps the picked card in it, drawn first (`plugins/workflow/client.js` tip :1474–:1477): ```js const pickedIndex = tasks.findIndex(task => task.id === taskId) const shownTasks = tasksExpanded ? tasks : pickedIndex >= ASSIGN_VISIBLE ? [tasks[pickedIndex], ...tasks.slice(0, ASSIGN_VISIBLE - 1)] : tasks.slice(0, ASSIGN_VISIBLE) ``` `ASSIGN_VISIBLE` stays 12 at :1432, so the collapsed list still draws twelve rows and the count row still says `Show 8 more cards` (it is computed from `tasks.length - shownTasks.length` at :1503). A pick inside the twelve takes the same path as before, unchanged. `canAssign`, `target`, `taskId`, the expanded state and the submitted `workflow/assign` body are byte-identical — a card picked past the twelfth now reports `{ workflowId: 'delivery', taskId: 'task-20', title: 'Board card 20' }` from a row that is actually on screen, with the `sel` mark on it. - `plugins/workflow/client.js` (+7/−1): the picked-card slice and its three-line comment. - `plugins/workflow/test/client.test.js` (+51): the two cases and their two small helpers (`selCards`, `cardTitle`). - `docs/subsystems/workflow.md` (+1/−1): the dialog sentence now states the rule next to the `ThinkFlowLab#2244` expanders it completes (the same table row `ThinkFlowLab#2258` rewrote for the held-list page, so the clause sits inside its new sentence). - `changelog.d/2257-hand-a-task-keeps-the-picked-card-in-view.changed.md` (+1). ## Delta, file by file | file | +/- | kind | | --- | --- | --- | | `plugins/workflow/client.js` | +7/−1 | written | | `plugins/workflow/test/client.test.js` | +51 | written (two new cases and their helpers) | | `docs/subsystems/workflow.md` | +1/−1 | written | | `changelog.d/2257-hand-a-task-keeps-the-picked-card-in-view.changed.md` | +1 | written (new) | | **total** | **+60/−2** | 4 files, no generated file | `plugins/` carries no generated bundle, so nothing here is produced by `npm run build` or `ds-bot-patches generate`; `patches/ds-bot/**` and `core/client.js` are untouched, and `node scripts/ds-bot-patches.mjs generate` after the edit left `patches/` byte-identical. ## What I ran at local `6c74ce66b6aa89fa313a2420c75e1576bf46a4f5` (pushed as `ebe21df79605c08291f95131eea2cfbe554fdf8a`) `TZ=UTC ARCH_DOCS_BASE=0950db09d505a267735eaf215bca82e2ce74b30e npm run verify` → **exit 0** | suite | tests / pass / fail | | --- | --- | | core | 2675 / 2675 / 0 | | plugins/social | 570 / 570 / 0 | | plugins/tree | 132 / 132 / 0 | | plugins/timeline | 140 / 140 / 0 | | plugins/workflow | 410 / 410 / 0 | | `.github/scripts` | 599 / 599 / 0 | | interop | 37 / 37 / 0 | | live-e2e | 26 / 26 / 0 | | **total** | **4589 / 4589 / 0** | - After the fix, `plugins/workflow/test/client.test.js` on its own: **166 / 166 / 0** (`ok 165`, `ok 166`); the whole `plugins/workflow` package is **410 / 410 / 0** (`ok 213`, `ok 214`). - `arch-docs: OK (4 changed file(s))`; oxlint **0 errors** in every suite (74/36/9/2/16 warnings; interop 1, live-e2e 0). - `ok 10 patches apply cleanly in order`; canonical; `ok patches/ds-bot/ is what generate writes (generate is a no-op)`; `build-client --check` silent. ## Tier, by path (not by a label) `createGate(risk-rules).judge(files)` over exactly these four paths, from `0950db09`'s `.github/agent/risk-rules.json`: `risk-tier: T2; basis: plugins/workflow/client.js=T2, plugins/workflow/test/client.test.js=T2, changelog.d/2257-hand-a-task-keeps-the-picked-card-in-view.changed.md=T1, docs/subsystems/workflow.md=T0` 62 changed lines in 4 files, no generated file. ## Not run - The smoke bench (`dev/bench.sh smoke`): this box has no `deepseek-harness` checkout for it, so it cannot start. `core/index.js` and `core/src/host/` are untouched by this change. - No browser was available, so the dialog states are exercised through the module tests rather than by clicking. - `plugins/workflow/client.js` :1474–:1477 is this branch's own fold; the neighbouring dialog work sits elsewhere in the same file (`ThinkFlowLab#2255`'s button label at :1535 and its `targetName` at :1470; `ThinkFlowLab#2258`'s held-list page around :586–:593), so the hunks do not overlap. ## Checkpoint <!-- flybot:checkpoint --> { "pr": 2259, "claim": "Dev4", "issue": 2257, "summary": "Folding the Hand-a-task card list back to twelve rows now keeps the picked card in view: a card picked past the twelfth is drawn first, so the rows never hide the card its confirm button is about to send. Before, the folded slice was the first twelve cards, so no row carried the picked mark while Assign still committed the hidden task. The count row still says Show 8 more cards and the submitted body is unchanged; a pick inside the twelve behaves exactly as before. Two client tests drive a twenty-card board.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/2257-hand-a-task-keeps-the-picked-card-in-view.changed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=0950db09 npm run verify (4589/4589/0)", "result": "green", "at": "ebe21df79605c08291f95131eea2cfbe554fdf8a" }, "next": "T2: waiting for a PASS naming this tip; enqueue-guard will refuse until one exists" } <!-- /flybot:checkpoint -->
Written-by: Dev-4
Fixes #2254
Owner: Dev4
Reviewer: Birfy
Tier: T2
Claim-Id: 860a1014446b40ccb2e6300985f9d78e
Branch: dev/4-p463-assign-names-target
Base: 575fadf
Tree: d5e92acaf5aa5e2b08c480e47e9b24d7b62dc62e
Verified commit: local
49261b05b3dc120dd722799d324dc5c515f2178e(not on the remote; the same tree asTreeabove, pushed asc5f7e5dbe77002f45b7ff9f0e42cffb1234c5a1d)Pushed head: c5f7e5d
Files: 4 changed, +89/−8
The defect
Hand a task to a Workflow gained two ways to tell two lanes apart — the Project badge on every target row (
#2242) and the Project on the row a lane's own name sits in (#2241) — but the confirm button still readAssignalone (plugins/workflow/client.jsbase :1504, tip :1512–1513). With two lanes that share one name, the identifying row scrolls out of the dialog's footer exactly when the person presses the button, so the last thing read before the click cannot say which lane the card goes to.Red first, on live main
575fadf3Clean tree at
575fadf346e4297c641f74a5d79244d1ccf0cb58with onlyplugins/workflow/test/client.test.jscarrying the new cases (base sources, so the button still readsAssign):plugins/workflow/test/client.test.js→ 404 tests / 401 pass / 3 failnot ok 208 - #2254: two lanes with one name: the confirm button names the picked lane and its Project—the default lane's Project is on the button, saw Assign(expected: true,actual: false)not ok 209 - #2254: a Bot target names the Bot on the confirm button—expected: 'Assign to Writer Bot',actual: 'Assign'not ok 210 - #2254: the named confirm button posts the same assign body—precondition: the second lane is the target(expected: true,actual: false); its own body assertion is the regression guard for the unchangedworkflow/assignpayload, and it is the label line that fails on the base.Release lane, one in ProjectAlphaand one inBeta: the default pick must nameAlpha, picking the second must nameBetaand dropAlpha, a Bot target must name the Bot, and the confirm click must still post exactly oneworkflow/assignwith{ workflowId, taskId, title }.The base already carries
#2252's cases, so the three new failures sit at 208/209/210.The fix
The footer button names the target it is about to use (
plugins/workflow/client.jstip :1512–1513, the label readstargetName, resolved once per render at tip :1451–1454):targetNameis resolved once per render from the same state the click posts: the Bot's name for abot:<id>target, else the picked lane's name with its Project —Release lane · Beta— else''. A dialog with no target keeps today's plainAssign, still disabled (#2245's behaviour, pinned by that case). Nothing else moves:canAssign,target,taskId, the submit body and the#2244expanders are byte-identical.plugins/workflow/client.js(+10/−1): the label and its three-line comment, plus theAssign to {target}entry in the plugin's own zh fallback dictionary.plugins/workflow/test/client.test.js(+77/−6): the three new cases, plus the six places that found the button by the exact textAssignnow match the same button by its unchanged prefix.docs/subsystems/workflow.md(+1/−1): one sentence stating the rule next to the Project-badge rule it completes.changelog.d/2254-hand-a-task-names-its-target.changed.md(+1).Delta, file by file
plugins/workflow/client.jsplugins/workflow/test/client.test.jsdocs/subsystems/workflow.mdchangelog.d/2254-hand-a-task-names-its-target.changed.mdplugins/carries no generated bundle, so nothing here is produced bynpm run buildords-bot-patches generate;patches/ds-bot/**andcore/client.jsare untouched, andnode scripts/ds-bot-patches.mjs generateafter the edit leftpatches/byte-identical.What I ran at local
49261b05b3dc120dd722799d324dc5c515f2178e(pushed asc5f7e5dbe77002f45b7ff9f0e42cffb1234c5a1d)TZ=UTC ARCH_DOCS_BASE=575fadf346e4297c641f74a5d79244d1ccf0cb58 npm run verify→ exit 0.github/scriptsplugins/workflow/test/client.test.json its own: 404 / 404 / 0 (the base's 401 plus the three that were red).arch-docs: OK (4 changed file(s)); oxlint 0 errors in every suite (74/36/9/2/16 warnings, the same counts as live main; interop 1, live-e2e 0).ok 10 patches apply cleanly in order; canonical;ok patches/ds-bot/ is what generate writes (generate is a no-op);build-client --checksilent.Tier, by path (not by a label)
createGate(risk-rules).judge(files)over exactly these four paths, from575fadf3's.github/agent/risk-rules.json:risk-tier: T2; basis: plugins/workflow/client.js=T2, plugins/workflow/test/client.test.js=T2, changelog.d/2254-hand-a-task-names-its-target.changed.md=T1, docs/subsystems/workflow.md=T097 changed lines in 4 files, no generated file.
Not run
dev/bench.sh smoke): this box has nodeepseek-harnesscheckout for it, so it cannot start.core/index.jsandcore/src/host/are untouched by this change.Checkpoint
{
"pr": 2255,
"claim": "Dev4",
"issue": 2254,
"summary": "The confirm button of Hand a task to a Workflow now names the target it will use: the picked lane with its Project, or the Bot. It read Assign alone before, so two lanes that share one name were indistinguishable at the click. The name comes from the same state the click posts, and the submit body stays { workflowId, taskId, title }; with no target the plain Assign stays disabled as #2245 left it. Three client tests drive two lanes named alike from Projects Alpha and Beta, and a Bot target.",
"files": [
"plugins/workflow/client.js",
"plugins/workflow/test/client.test.js",
"docs/subsystems/workflow.md",
"changelog.d/2254-hand-a-task-names-its-target.changed.md"
],
"checks": {
"ran": "TZ=UTC ARCH_DOCS_BASE=575fadf3 npm run verify (4583/4583/0)",
"result": "green",
"at": "c5f7e5dbe77002f45b7ff9f0e42cffb1234c5a1d"
},
"next": "T2: waiting for a PASS naming this tip; enqueue-guard will refuse until one exists"
}