Skip to content

A room board reached from a Bot board counts its active cards twice in the rail #2069

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: e4910b8f53384edcbdfb47a9540eefb9
Branch: dev/2-room-rail-double-count
Base: 5b862c6
At: 2026-11-01T17:43:55Z

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

The defect

A room board opened from a Bot board counts the room's active cards twice in its rail. The rail is supposed to read {done}/{total} for the cards the board actually draws; on a room board that is the room's active list plus one archive page, but the hook's own state is never reset when the scope changes from a Bot to a room, and the rail adds both lists.

Code on main 5b862c6e (core/src/client/kanban.js):

  • :167 — const [own, setOwn] = useState([]); the effect is keyed on key (:169), which changes when the scope changes.
  • :180-181 — the non-room read is actions?.tasks?.() with no argument; the host's default read is every task the Bot may act on (core/src/host/tasks.js:1397-1399, all.filter(mayAct || ancestorOwned)), so room cards land in own as well as in groupTasks.
  • :186-189 — setOwn(list) only runs in the scope.kind !== 'group' branch; going Bot → room leaves own holding the Bot board's read.
  • :401 — [...own, ...(scope?.kind === 'group' ? groupTasks : []), ...(archive ?? []).slice(0, ARCHIVE_SHOWN)] therefore counts the room's active cards twice.

Reproduction

Product's probe (same harness as core/test/kanban.test.js): a room war with one active Writer card and one done card in the archive page. First read on the real path is the Bot board (the rail's first entry, :377), which fills own with [task-open-s]; then the scope switches to the room:

bot board (default scope)      rail Writer = "0/1"   (own holds: task-open-s)
room board after the rail click rail Writer = "1/3"  drawn: not-started=1 / in-progress=0 / done=1  → true value "1/2"
control own = []               rail Writer = "1/2"

A card from another room left in own reaches a Bot rail the board does not draw at all (rail Chief = "0/1" with no Chief card drawn), which is the same bug from the other side. Read arguments confirm the split: bot board read args = [], archive read args = [{botId:'a', archive:true, limit:20}].

Expected behaviour

The rail counts what the board draws, and only that: on a room board groupTasks plus the archive page; on a Bot board own (already filtered to that Bot) plus the archive page. Minimal fix, one line plus a comment:

[...(scope?.kind === 'group' ? groupTasks : own), ...(archive ?? []).slice(0, ARCHIVE_SHOWN)]

#2045's one-page cap stays as it is.

Red first — and the fixtures that must change with it

Base: live main 5b862c6e5ecdd0a472826162ebb2abab63b91544.

  • New case: render the Bot board first (so own is filled by a real read), then switch the scope to the room; railMeta('s') must be 1/2 where it is 1/3 today.
  • The existing room cases are false green and must be fixed in the same PR. boardWith({ kind: 'group', … }, [], archive, groupActive) presets own = [], which the real path never produces: on a real board the initial scope is rail.bots[0] (:377), so own is always filled before any room is opened. A test that starts a room board with an empty own cannot see this bug. Seed own from the Bot board read, as the new case does.
  • Everything already asserted stays asserted, verbatim: 1/2, 2/3, 0/1, 1/4, 3/5, 19/21, 20+ done, 18+ done, 2+ done, 0/20 (core/test/kanban.test.js:344-431).

Scope

  • core/src/client/kanban.js — the one line and its comment (P-364's comment above it needs the room branch stated correctly).
  • core/test/kanban.test.js — the new case and the fixture correction.
  • The built client and patches/ds-bot/ (0008 diff, files/src/client/…, files/test/…) as generate writes them; build-client --check must be 0.
  • docs/subsystems/core-client.md — the P-364 paragraph gains one sentence: a room board counts groupTasks plus the archive page, never own.
  • changelog.d/<this issue>-room-rail-double-count.fixed.md.
  • T1 / XS.

Gates

TZ=UTC ARCH_DOCS_BASE=5b862c6e npm run verify, ds-bot-patches check + canonical, build-client --check, checkpointReasons = [], maintainer_can_modify: true. FlyBot Test and FlyBot Security self-tests run on the new tip before the reviewer is named; a Verdict request on a tip whose advisory is still running is how a half-checked tip reaches the merge queue.

Dedupe on live main: #2048 and #2063 (both closed, the P-364 halves) and #2045/#2058 (page-full lower bound) are the neighbourhood; no open issue covers this double count.

Activity

  1. HugoXK commented on Nov 1, 2026

    @HugoXK
    ContributorAuthor

    Claim-Id: e4910b8f53384edcbdfb47a9540eefb9
    Bot: FlyBot Lead
    Branch: dev/2-room-rail-double-count
    Base: 5b862c6 (live main)
    Owner: Dev-2
    Reviewer: Birfy
    Claimed-at: as recorded by the claim helper at 2026-11-01T17:43:57Z

    Taken by FlyBot (owner decision 2026-10-26: we implement what we report). Branch and PR follow within 24h; the PR opens with Fixes #2069.

    Please do not pick this up without a pickup-ok comment from FlyBot Lead.

  2. HugoXK commented on Nov 2, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: e4910b8f53384edcbdfb47a9540eefb9
    Reason: #2076 merged at 18:39:29Z as squash e36b8ae; issue closed completed 18:42:37Z.
    At: 2026-11-02T00:04:30Z

  3. added 2 commits that reference this issue on Nov 2, 2026
    e36b8ae
    6f1c016
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