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: d0305775a2e54c859fd92ec21340049b
Branch: dev/1-workflow-listrow-live-count
Base: 8afc1d3
At: 2026-11-02T18:53:42Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
Credit: audit and draft by FlyBot Product
Kind: bug (read-only surface + list status)
Source: FlyBot Product audit P-433 (the dot's count) + P-438 (mount-time ingest); Lead triage and line re-read on live main 8afc1d3c (after #2215 merged).
Dedupe (searched before opening)
Search API over issues: wf-live, activeCount, workflow/ingest. Open hits that touch this file: #2202 (a refused dialog edit is announced twice), #1668 (a re-matched card leaves no trace in the source workflow), #787 (the orchestration baseline). Closed hits on the same file are the list's write controls (#2200/#2205), the Stage's running count (#1463), idle/queued strips (#1469) and the two-per-2s stage poll (#1564). No issue covers the live dot's count or the mount-time workflow/ingest; neither is covered by a linked PR. #2215 (merged at 8afc1d3c) touched the Stage's controls and did not touch either place cited below.
What happens today
Two gaps in the same list, same file, same component. Line numbers are live main 8afc1d3c.
A. The live dot carries no number. The row draws wf-live as a bare, aria-hidden dot whenever activeCount > 0 (plugins/workflow/client.js:2211); activeCount never reaches the row's accessible name, a visible count node, or its title (its other uses are the busy flag at :373 and the Stage summary at :581). A read-only reader — whose only live signal is exactly this view — cannot tell one running run from five. The number exists in the Stage summary (:581, tr('{count} running · queue {depth}')), but you have to open the row to see it.
B. The mount effect writes in a read-only window. Section's mount useEffect (plugins/workflow/client.js:1974-1999) reads the board (:1986, host('tasks')) and, for every card with status === 'open', calls call('workflow/ingest', task) (:1990), replacing the pack each time (:1992). It never consults locked (:1956, computed from readOnlyReason at :1955; the list body does consult it at :2204/:2212). workflow/ingest is not declared a read (plugins/workflow/index.js:121), so a read-only host refuses every call (core/src/host/channel.js:295-296, with flybotIsRead from core/src/host/hooks.js:1099); the client swallows the refusal (:1994-1996), so the only trace is N refused writes. Counted by call, not by effect — ingest is a claim/match write by definition and a reader opening the list did not ask for it.
Reproduction (measured on 8afc1d3c with the repository's own client.test.js renderer and the real plugins/workflow/client.js)
A. mount(client.Section, { roster: { bots: [] }, call, actions: {} }) with one workflow { activeCount: 3, run: { live: true, status: 'running' } }: the row button's text, aria-label and title contain no 3; no .wf-live-n node exists; the tree holds one span.wf-live carrying no text and aria-hidden.
B. read-only roster (readOnly: '<host sentence>') + globalThis.__flybot__.host = async name => name === 'tasks' ? [three open cards, one accepted] : …: after mount the call sequence is ['workflow/state', 'workflow/ingest', 'workflow/ingest', 'workflow/ingest'] with ids task-1/2/3; no status line and no alert. A writable roster sends the same three calls.
Probe: plugins/workflow/test/probe-matrix.test.js in Product's evidence tree (rows 13 and 13b); same readings re-taken on 8afc1d3c.
Expected behaviour
A. When activeCount > 0, the number appears in the row's accessible name (aria-label) and in a visible count node next to the dot (.wf-live-n, not drawn at 0) — the two together, matching the red-first below; no new visual density. When activeCount is 0, there is no dot, no count node and no digit in the row.
B. In a read-only window the mount effect sends no workflow/ingest call: one guard before the tasks read (:1986) skips the ingest loop while keeping the projects read (:1980) so the Project filter still fills. A writable window keeps ingesting every open card exactly as today.
Scope
plugins/workflow/client.js— the row (:2199-2211) and the mount effect (:1974-1999).plugins/workflow/test/client.test.js— the two red-first tests below.changelog.d/<this issue>-list-live-count.fixed.md;docs/subsystems/workflow.mdif it describes the list.
Not in scope: batching the ingest into one call (product's P-440, a separate enhancement that waits for this lane), the Stage controls, core.
Red first
New tests in plugins/workflow/test/client.test.js (whole-tree counts; red on today's code). Both assertions are required and neither substitutes for the other:
A. One workflow with activeCount: 3 ⇒ the row button's accessible name (aria-label) contains 3 and the visible count node .wf-live-n (whole-tree query) has text 3; with activeCount: 0 ⇒ span.wf-live count is 0, .wf-live-n count is 0, and no digit appears in the row. (Today: dot yes, number no.)
B. read-only roster + three open cards ⇒ calls.filter(c => c.name === 'workflow/ingest').length === 0; writable roster with the same fixture ⇒ === 3. (Today: 3 and 3.)
Acceptance
- Both tests fail before the change and pass after.
plugins/workflowsuite green,npm run verifygreen (TZ=UTC),arch-docs: OK.- Read-only mount sends no write; a writable mount still ingests every open card; at
activeCount: 3the row's accessible name and.wf-live-nboth show3, and both are gone when idle.
Activity
workflow: the list row says how many runs are live, and a read-only m…
workflow: the list row says how many runs are live, and a read-only m…
HugoXK commentedon Nov 2, 2026
Release
Written-by: FlyBot Lead
Released: d0305775a2e54c859fd92ec21340049b
Reason: merged as #2224 (9863992, 19:58:15Z); issue closed completed
At: 2026-11-02T20:04:45Z