Skip to content

client: a locked Bot card with no tasks draws no heading - #2298

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-schedules-locked-empty-card
Nov 3, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-schedules-locked-empty-card

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2286

Written-by: Dev-2
Owner: Dev-2
Reviewer: Birfy
Tier: T1 — the paths are T1 (core/src/client/**, core/client.js, patches/**, core/test/**, changelog.d/**) and docs/** is T0; no T2/T3 path and no diff-pattern match.
Claim-Id: 136192f1c516471c9bef46a26efacb6d
Branch: dev/2-schedules-locked-empty-card
Base: e8cfd17
Tree: 003906770511e489c44ba6013b461d915845a6cf
Verified commit: 99a7a22
Pushed head: 99a7a22

Scope — a Bot's Scheduled tasks card in a read-only window dropped its New task row but kept the heading, so a Bot with no scheduled tasks showed Scheduled tasks over an empty body. BotSchedules now returns null for a locked card whose task list is empty, the same shape ScheduleSummary (#2232, P-457) and RoomSchedules (#2039) already take. Three states stay as they were: a writable card keeps New task, a locked card with tasks keeps its heading and rows, and the Automation-tasks-off view keeps its Switch on Automation tasks on the Plugins page. card and Open Plugins button — that branch is guarded by view.available, not by the lock.

Files (8, +72/−3)

  • core/src/client/schedules.js (+5) — the early return, after the read-failure and no-view answers
  • core/test/schedules-client.test.js (+28) — the locked-empty case with a writable control, and the locked-with-tasks case
  • docs/subsystems/core-client.md (+1/−1) — one sentence on the row
  • changelog.d/2286-locked-empty-card.fixed.md (+1)
  • core/client.js (+1), patches/ds-bot/0008-client-bundle.patch (+2/−1), patches/ds-bot/0001-core-fixes.patch (+6/−1), patches/ds-bot/files/test/schedules-client.test.js (+28) — regenerated on this base with build-client + generate; the bundle diff is that one added line, not a re-layout

Readings at 99a7a221d (committed, clean tree)

  • TZ=UTC ARCH_DOCS_BASE=e8cfd175e01959c62ab9e8d866e28d35dbc8fbd6 npm run verify — exit 0, 8 suites, 4658 tests / 4658 pass / 0 fail, arch-docs: OK (8 changed file(s)) (core 2709, social 570, tree 132, timeline 140, workflow 411, .github/scripts 633, interop 37, live-e2e 26; the base answers 4656, so the two new cases are the whole difference).
  • node core/scripts/build-client.mjs --check — exit 0.
  • node scripts/ds-bot-patches.mjs check — ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/.
  • node scripts/ds-bot-patches.mjs canonical — ok patches/ds-bot/ is what generate writes (generate is a no-op); a second generate on the committed tree wrote nothing (git status --porcelain empty afterwards).
  • node .github/scripts/changelog.mjs check — 30 fragment(s) in changelog.d/ are well formed.
  • Red first, on a clean base tree carrying only the two new cases: 54 tests / 53 pass / 1 fail — a locked zero-task card still draws a section, saw Scheduled tasks (core/test/schedules-client.test.js:827, expected 0 / actual 1). The control case (locked card with tasks) is green before and after; the same file is 54 / 54 / 0 with the change. core/src/client/schedules.js and core/test/schedules-client.test.js are byte-identical at 55503e16 and at this base, so the measurement holds at e8cfd175.
  • Conflict markers: git grep -nE '^(<{7}|={7}|>{7})' -- docs core patches changelog.d answers no line (exit 1).

Not run — the smoke test (no index.js or src/host/ change), the pack check, typecheck and actionlint of the CI package job, and any live-runtime probe on this tip.

Checkpoint

{
  "pr": 2298,
  "claim": "Dev-2",
  "issue": 2286,
  "summary": "A Bot's Scheduled-tasks card in a read-only window now draws nothing when the Bot has no scheduled tasks, instead of the heading over an empty body. The rule is one early return in BotSchedules, guarded on the lock and on view.available so the Automation-tasks-off hint card still draws; a writable card keeps New task and a locked card with tasks keeps its rows. Two cases cover the locked-empty state with a writable control, and the locked-with-tasks state.",
  "files": ["core/src/client/schedules.js", "core/test/schedules-client.test.js", "docs/subsystems/core-client.md", "changelog.d/2286-locked-empty-card.fixed.md", "core/client.js", "patches/ds-bot/0008-client-bundle.patch"],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=e8cfd175e01959c62ab9e8d866e28d35dbc8fbd6 npm run verify; node core/scripts/build-client.mjs --check; node scripts/ds-bot-patches.mjs check; node scripts/ds-bot-patches.mjs canonical", "result": "green", "at": "99a7a221de58469b04eb2821361fb06b169ee01a" },
  "next": "none — ready for review"
}

@HugoXK

HugoXK commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy — review request at this tip: 99a7a221de58469b04eb2821361fb06b169ee01a.

Tree 003906770511e489c44ba6013b461d915845a6cf, single parent / base e8cfd175e01959c62ab9e8d866e28d35dbc8fbd6 (the live main, #2265's merge commit). 8 files +72/−3. The generated half is exactly one added line in core/client.js, with the matching hunk in patches/ds-bot/0001 (+6/−1) and patches/ds-bot/0008 (+2/−1) — not a re-layout. docs/subsystems/core-client.md moves +1/−1 and changelog.d/2286-locked-empty-card.fixed.md is +1.

What it does. BotSchedules in a read-only window drops the New task row but kept the heading, so a Bot with no scheduled tasks showed Scheduled tasks over an empty body. The change is one early return — if (locked && view.available && tasks.length === 0) return null — the same shape ScheduleSummary (#2232, P-457) and RoomSchedules (#2039) already take. Three states stay as they were: a writable card keeps New task, a locked card with tasks keeps its heading and rows, and the Automation-tasks-off view keeps its Switch on Automation tasks on the Plugins page. card because that branch is guarded by view.available, not by the lock.

State: ready (not draft), maintainer_can_modify: true, mergeable: true / clean, zero comments at this tip. Tier in the body is T1 by path — core/src/client/**, core/client.js, patches/**, core/test/**, changelog.d/**, plus one docs/** line; no T2/T3 path.

Readings at this tip (99a7a221d, committed, clean tree):

  • TZ=UTC ARCH_DOCS_BASE=e8cfd175e01959c62ab9e8d866e28d35dbc8fbd6 npm run verify — exit 0, 8 suites 4658 / 4658 / 0 (core 2709, social 570, tree 132, timeline 140, workflow 411, .github/scripts 633, interop 37, live-e2e 26), arch-docs: OK (8 changed file(s)).
  • node core/scripts/build-client.mjs --check — exit 0.
  • node scripts/ds-bot-patches.mjs check — ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/.
  • node scripts/ds-bot-patches.mjs canonical — no-op; a second generate on the committed tree wrote nothing.
  • node .github/scripts/changelog.mjs check — 30 fragment(s) in changelog.d/ are well formed.
  • Red first, clean base carrying only the two new cases: 54 / 53 / 1 — a locked zero-task card still draws a section, saw Scheduled tasks (core/test/schedules-client.test.js:827, expected 0 / actual 1). Same file 54 / 54 / 0 with the change; the locked-with-tasks control is green in both.

Checks at this tip: 14 check-runs, 14 success + 0 cancelled — tests-ok, enqueue-guard, merge-gate, judge, package, plugins (social/tree/timeline/workflow), agent-audience (two runs), reviewed tip, risk tier, ubuntu-latest · Node 24 · DSH 0.2.0-rc.2. No conflict markers in docs core patches changelog.d.

Fixes #2286.

@Birfy
Birfy added this pull request to the merge queue Nov 3, 2026
Merged via the queue into ThinkFlowLab:main with commit 5d6193a Nov 3, 2026
14 checks passed
@Birfy
Birfy deleted the dev/2-schedules-locked-empty-card branch November 3, 2026 11:07
A read-only window's Bot settings card dropped its New task row but kept
the "Scheduled tasks" heading, so a Bot with no tasks showed a heading over
an empty body. The details line and a group chat's section already draw
nothing in the same state (ThinkFlowLab#2246, P-482).
HugoXK added a commit to HugoXK/FlyBot that referenced this pull request Nov 3, 2026
…2299)

Fixes ThinkFlowLab#2284
Written-by: Dev1
Owner: Dev1
Reviewer: Birfy
Claim-Id: fdf1298faa3542aea854e775ae0e4364
Branch: dev/1-inbox-readonly-actions
Base: 5d6193a
Tree: 2a61cce
Verified commit: 922a2acb6239f703f8a96675df87f467614dc133
Pushed head: 8dbfc9d

## Scope

A read-only window's Inbox drew the whole *Needs you* action set, and
every one of those actions is a write the host refuses with
`bot/read-only`: answering a question (`answer-question`), the task
input (`task-answer-input`), **Accept** (`task-accept-result`) and
**Send back** (`task-send-back`). The rows and their **Open** action
stay; the four writes are not drawn, and one sentence at the top of the
dialog carries the host's own read-only words (the same `bt-read-only`
`role="status"` hint the Settings header, the sidebar, the schedule page
and the boards draw). An **Approval** card keeps **Reject** and
**Allow**: `approval-answer` is one of the reads a read-only channel
allows, so it is not part of this defect. A writable window — including
a blank or missing `readOnly` — draws exactly the tree it drew before,
pinned by a sha256 of the fixture.

The gate is `lockedWindow` imported from `schedules.js` (ThinkFlowLab#2232/ThinkFlowLab#2298);
no second copy of the predicate. The card builds its write block with a
spread so the writable children list is byte-for-byte the same, and the
dialog's hint is added the same way.

Changed files (8, +345/−10):

- `core/src/client/inbox.js` (+10/−2) — import `lockedWindow`; `locked`
in `InboxCard` and `InboxDialog`; the two write components are drawn
only when unlocked; one hint line at the top of the dialog body
- `core/test/inbox-readonly.test.js` (new, +157) — six cases: the three
locked cards (result, question, task input), the locked dialog's one
hint, the approval reverse, and the writable reverse with the recorded
tree hash
- `core/client.js` (+4/−2) — regenerated by `npm run build`
- `patches/ds-bot/0008-client-bundle.patch` (+5/−3),
`patches/ds-bot/files/src/client/inbox.js` (+10/−2),
`patches/ds-bot/files/test/inbox-readonly.test.js` (new, +157) —
regenerated by `node scripts/ds-bot-patches.mjs generate`
- `docs/subsystems/core-client.md` (+1/−1) — the `inbox.js` subsystem
row
- `changelog.d/2284-inbox-readonly-actions.fixed.md` (new, +1)

## Red first, on the new base `5d6193a0`

With only `core/test/inbox-readonly.test.js` added to the clean base
tree: **6 tests / 2 pass / 4 fail**. The four reds are the writes and
the hint; the two greens are the reverses that must not move.

- `inbox-readonly.test.js:111` — result card: expected `["Open"]`,
actual `["Send back","Accept","Open"]`
- `inbox-readonly.test.js:115` — question card: expected `["Open"]`,
actual `["A","B","Submit","Open"]`
- `inbox-readonly.test.js:121` — task input: expected `["Open"]`, actual
`["Submit","Open"]`
- `inbox-readonly.test.js:127` — dialog: expected 1 `bt-read-only`
`role="status"` line carrying the lock text, actual `0`
- Green before and after: an approval keeps `["Reject","Allow
once","Always allow for this Bot","Always allow for this
group","Open"]`; a writable window keeps `["Send
back","Accept","Open"]`, `["A","B","Submit","Open"]`,
`["Submit","Open"]` and its recorded tree sha256
`b19823e6ca04389a3325e312aaf4807b84b55b882a255c3546d15c9c8ec23d41` /
3088 bytes.

After the fix the file is **6/6/0**.

## Gates at this tip

- `node core/scripts/build-client.mjs --check` — silent, exit 0
- `node scripts/ds-bot-patches.mjs generate` twice; the second pass
writes nothing (sha256 of every `patches/ds-bot/**` file plus
`core/client.js` identical before and after)
- `node scripts/ds-bot-patches.mjs canonical` — `ok patches/ds-bot/ is
what generate writes (generate is a no-op)`
- `node scripts/ds-bot-patches.mjs check` — three `ok` lines (`ds-bot/`
= the pin; 10 patches apply cleanly in order; `core/` equals `ds-bot/` +
`patches/ds-bot/`)
- `TZ=UTC ARCH_DOCS_BASE=5d6193a06b8a4cae2b650b1ee6d7d0cd6baf4dcb npm
run verify` — exit 0, 8 suites, **4664 tests / 4664 pass / 0 fail**:
core 2715 (clean base 2709 + the 6 new cases), social 570, tree 132,
timeline 140, workflow 411, `.github/scripts` 633, interop 37, live-e2e
26; lint 74/36/9/2/16/0 warnings, **0 errors** in every package;
`arch-docs: OK (8 changed file(s))`

Not run: the smoke test (this changes no `core/index.js` or
`core/src/host/` file), and the CI `package` job's own extras (pack
check, typecheck, actionlint) which `verify` does not include.

## Checkpoint

<!-- flybot:checkpoint -->
```json
{
 "pr": 2299,
 "claim": "Dev1",
 "issue": 2284,
 "summary": "A read-only window's Inbox drew the whole Needs-you action set, and the host refuses every one of those writes with bot/read-only. The four writes (answer a question, the task input, Accept, Send back) are no longer drawn when the window is locked, and the dialog carries the same bt-read-only hint the Settings header and boards draw. Rows and Open stay, and an Approval keeps Reject and Allow because approval-answer is one of the reads a read-only channel allows. A writable window draws exactly the tree it drew before, pinned by a fixture sha256.",
 "files": [
  "core/src/client/inbox.js",
  "core/test/inbox-readonly.test.js",
  "docs/subsystems/core-client.md"
 ],
 "checks": {
  "ran": "TZ=UTC ARCH_DOCS_BASE=5d6193a0 npm run verify; node core/scripts/build-client.mjs --check; node scripts/ds-bot-patches.mjs check; CI at this tip: tests-ok, Node 24, plugins, package, merge-gate",
  "result": "green",
  "at": "8dbfc9dee7b9c33e9d4f5247b951e2f228c9891e"
 },
 "next": "none — T1, PASS at this tip, green tests-ok; enqueue through the merge queue"
}
```
<!-- /flybot:checkpoint -->
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.

client: a read-only Bot card with no scheduled tasks draws only the 'Scheduled tasks' heading

2 participants