Repository navigation
board: a read-only window draws no task-board write (#2248) - #2261
Merged
Merged
Conversation
Collaborator
Author
|
Checkpoint summary rewritten to four sentences after the first enqueue-guard read (that run read the body before the edit; the gate re-reads at queue entry). All other checks at |
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Nov 3, 2026
Birfy
force-pushed
the
dev/2248-readonly-task-board
branch
from
November 3, 2026 05:22
890e47a to
4cd7d3e
Compare
Replay follow-up: drop the stray core-test.log the replay commit carried.
HugoXK
added a commit
to HugoXK/FlyBot
that referenced
this pull request
Nov 3, 2026
…d-task form (ThinkFlowLab#2246) Written-by: Dev-4 Fixes ThinkFlowLab#2243 Owner: Dev4 Reviewer: Birfy Tier: T1 Claim-Id: a41089f1cdd34475b08a8e4188440002 Branch: dev/4-p457-schedules-create-entries Base: 5008116 Tree: 93e92c8 Verified commit: local `51040d46c2fe287320e520b860213bc6f9486f91` (the same commit that was pushed) Pushed head: 51040d4 Files: 12 changed, +6975/−6064 (six written, six generated) Rebased onto `50081167e81ac5ee182e6cc5d1a25ab248329e32` (live main: `ThinkFlowLab#2263`, then `ThinkFlowLab#2261`); every reading in this revision is from that base. Two earlier revisions of this body quoted `5a21d5b4` and then `03a125306` — the code and the case names are the same, the counts move with main. ## What the rebase onto `50081167` had to resolve `ThinkFlowLab#2261` (`ThinkFlowLab#2248`, the other team's task-board change, merged upstream) rewrites `core/src/client/kanban.js` and its tests. This change touches `schedules.js`, `composer.js` and `details-drawer.js`; the two change sets meet in three generated or shared files and overlap in no source line: - `core/client.js` — generated bundle, both change sets in it; regenerated by `npm run build` (not hand-merged). - `patches/ds-bot/0008-client-bundle.patch` — generated mirror of that bundle; the rebase conflicted here (generated text), and the committed version is what `generate` writes. - `docs/subsystems/core-client.md` — one table row each: `kanban.js` (theirs) and `schedules.js` (this change); both rows stand as written. Both behaviours are kept: `ThinkFlowLab#2261`'s read-only task board is in `kanban.js`, tests and bundle exactly as it landed, and this change's read-only create entries are on top of it. `build-client --check` is silent, `node scripts/ds-bot-patches.mjs check` answers `ok core/ equals ds-bot/ + patches/ds-bot/`, and `canonical` answers `ok patches/ds-bot/ is what generate writes (generate is a no-op)` — the mirrors are generated output, not a resolution by hand. ## The defect ThinkFlowLab#2235 made a read-only window draw no create form (`settings.js`: `locked ? null : adding ? TaskForm : …`), but three entries still lead into it, and each one lands on a page that draws nothing: - `core/src/client/schedules.js:461` — `BotSchedules` draws its `New task` row unconditionally (it is `TaskList`'s `extra` row), and the row calls `actions.openSettings('schedules', bot.id)`. - `core/src/client/schedules.js:485` — `ScheduleSummary` never read the roster at all, so its empty state's `Add one` (`No scheduled tasks yet. Add one`) called the same thing. - `core/src/client/composer.js:170` — the `+` menu's `Scheduled task` row calls `openSettings('schedules', target)`. `settings.js` turns the `start` id into `adding`, so the settings page really does believe a form is open and then draws no form: a click that looked live ends on an empty page. ## Red first, on live main `50081167` Clean tree at `50081167e81ac5ee182e6cc5d1a25ab248329e32` with only the two test files touched. - `core/test/schedules-client.test.js` alone → **52 tests / 50 pass / 2 fail** - `not ok 50 - P-457: a read-only Bot card draws no New task row` — `a read-only Bot card still offers New task, saw New task` - `ok 51 - P-457: a locked page opened with a start id draws no create form` — green on the base, the counter-case that must stay green - `not ok 52 - P-457: a read-only details line offers no Add one, and a writable one does` — `the locked details line draws no button`, `actual [ 'No scheduled tasks yet. Add one' ]`, `expected []` - `core/test/composer-locked.test.js` alone → **2 / 1 / 1** - `not ok 2 - read-only window: no menu row opens the schedules page` — `a read-only window still offers the row: ["Add files","Reference a chat","Scheduled task"]`, `expected: true`, `actual: false` The composer case is the one Product's earlier probe could not mount; it is a real test now, with the three stubs the probe needed (`createPortal: node => node`, `useState` fed `{left:0,bottom:0}` then `null`, `useRef: current => ({current})`). The whole `core` package on the same red tree (both files at their package numbers): **2685 / 2682 / 3** — `not ok 277`, `not ok 1990`, `not ok 1992`, the same three cases. After the fix, on this tip: `schedules-client.test.js` alone **52 / 52 / 0**, `composer-locked.test.js` alone **2 / 2 / 0**; the whole `core` package **2685 / 2685 / 0**. ## The fix - `core/src/client/schedules.js`: `lockedWindow(roster)` (the module-private rule that was already at `:122`) is **exported once** instead of copied a fifth time — the same predicate still sits in `workflows.js:570/639`, `sidebar.js:371` and `settings.js:232`, and this change does not touch those four. `BotSchedules` draws `extra: locked ? [] : [ … New task … ]`. `ScheduleSummary` takes `roster` and, when the window is locked and the Bot has no tasks, returns `null`; with tasks it still draws the read half, because those rows only open the settings list (`openSettings('schedules')`, no Bot id) and open no form. - `core/src/client/composer.js`: the local `schedule()` helper is gone (`:147-151` on the base, call site `:150`); the menu row itself (`:170`) becomes `locked ? null : …` and imports `lockedWindow` from `./schedules.js` instead of growing a fifth copy. - `core/src/client/details-drawer.js:350`: passes the `roster` it already holds into `ScheduleSummary`. - `docs/subsystems/core-client.md`: the two sentences that contradicted each other are now one rule — a read-only window draws neither the empty state's button nor a Bot card's `New task` row. - New tests: 3 in `core/test/schedules-client.test.js` (read-only card, read-only details line, plus the locked page that stays empty), and `core/test/composer-locked.test.js` in full (read-only draws no row, writable still posts `('schedules', 'b1')`). Writable counter-cases live in the same tests: the writable Bot card still has its `New task` row, the writable details line still draws `Add one`, and the writable composer row still calls `openSettings('schedules', <bot id>)`. ## Which six files are written and which six are generated Written by hand — six: - `core/src/client/schedules.js` (+10/−6) - `core/src/client/composer.js` (+5/−5) - `core/src/client/details-drawer.js` (+1/−1) - `core/test/schedules-client.test.js` (+32) - `core/test/composer-locked.test.js` (+82, new) - `docs/subsystems/core-client.md` (1 line changed) Generated, never hand-edited — six: - `core/client.js` (`npm run build`; +1688/−1687) - `patches/ds-bot/0008-client-bundle.patch` (4993/4354) - `patches/ds-bot/0001-core-fixes.patch` (12/7) - `patches/ds-bot/0012-room-membership.patch` (37/3) - `patches/ds-bot/files/test/schedules-client.test.js` (+32) - `patches/ds-bot/files/test/composer-locked.test.js` (+82) ## The generated diff is module order, not a hand edit `core/client.js` and `patches/ds-bot/0008-client-bundle.patch` — **+1688/−1687 and +4993/−4354** — are **esbuild module order, not a logic rewrite**: `composer.js` now imports `./schedules.js`, so the `schedules` block moved in front of the `composer` block in the bundle. Generated only by `npm run build` and `node scripts/ds-bot-patches.mjs generate`; `build-client --check` and a no-op `generate` prove it. `composer.js` imports `./schedules.js`, so the `schedules` block moved in front of the `composer` block in the bundle. Both files are written only by `npm run build` and `node scripts/ds-bot-patches.mjs generate`; neither was edited by hand, and `build-client --check` plus `generate` being a no-op prove it. `patches/ds-bot/0001-core-fixes.patch` and `0012-room-membership.patch` follow the same two source files. There is no `patches/ds-bot/files/src/client/schedules.js` mirror, and none was invented. ## What I ran at `51040d46c2fe287320e520b860213bc6f9486f91` `TZ=UTC ARCH_DOCS_BASE=50081167e81ac5ee182e6cc5d1a25ab248329e32 npm run verify` → **exit 0** | suite | tests / pass / fail | | --- | --- | | core | 2685 / 2685 / 0 | | plugins/social | 570 / 570 / 0 | | plugins/tree | 132 / 132 / 0 | | plugins/timeline | 140 / 140 / 0 | | plugins/workflow | 411 / 411 / 0 | | `.github/scripts` | 599 / 599 / 0 | | interop | 37 / 37 / 0 | | live-e2e | 26 / 26 / 0 | | **total** | **4600 / 4600 / 0** | - `arch-docs: OK (12 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 ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)`; `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)`; `build-client --check` silent. - The five tests these two files add are the only difference between the red tree's 2685 and a base tree without them; every other core test is `ThinkFlowLab#2261`'s and the ones before it. ## Tier, by path (not by a label) `createGate(risk-rules).judge(files)` over exactly these 12 paths answers: `risk-tier: T1; basis: core/client.js=T1, core/src/client/**=T1, core/test/**=T1, patches/ds-bot/**=T1, docs/subsystems/core-client.md=T1` ## 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 window states are exercised through the modules and the tests rather than by clicking. ## Checkpoint <!-- flybot:checkpoint --> { "pr": 2246, "claim": "Dev4", "issue": 2243, "summary": "The three entries ThinkFlowLab#2235 left in a read-only window — BotSchedules' New task row, ScheduleSummary's empty-state Add one, and the composer's + menu Scheduled task row — now draw nothing, so no click lands on a create form the locked page hides. lockedWindow is exported once from schedules.js and reused by composer.js rather than copied a fifth time, the details line passes the roster, and a Bot that has tasks still lists them. Tests pin both read-only shapes and keep the writable entry points and their openSettings arguments unchanged. client.js/0008 is module order, not a hand edit.", "files": [ "core/src/client/schedules.js", "core/src/client/composer.js", "core/src/client/details-drawer.js", "core/test/schedules-client.test.js", "core/test/composer-locked.test.js", "docs/subsystems/core-client.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=50081167 npm run verify (4600/4600/0)", "result": "green", "at": "51040d46c2fe287320e520b860213bc6f9486f91" }, "next": "T1: waiting for tests-ok at this tip; no PASS required" } <!-- /flybot:checkpoint --> Co-authored-by: FlyBot Dev-4 <dev4@flybot.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Written-by: Dev
Fixes #2248
Owner: Chief
Reviewer: Reviewer
Tier: T1
Branch: dev/2248-readonly-task-board
Base: 03a1253
Tip SHA: 0bb21f6
The defect
The task board behind
KanbanDialog(core/src/client/kanban.js) tookrosterbut never asked whether the window is read-only, so a second, read-only window still drew Add task, Start, Complete and draggable cards, and accepted a drop on a column. The host refused each write (bot/read-only) and the board said nothing, so every control there was a dead line — P-455, the same family already closed on the sidebar / context-menu / other surfaces (#2215 #2221 #2223 #2233 #2236 #2239).Red first
Clean tree at base
8f5107cdcb876a1774187e325e150797c5577253with onlycore/test/kanban.test.jscarrying the two new cases (base sources):node --test core/test/kanban.test.js→ 28 tests / 27 pass / 1 failnot ok 27 - P-455: a read-only window draws no write on the task board— actual{buttons:['Add task','Start','Complete'], newTaskForms:1, draggable:['task-open123456','task-working456789','task-done789012']}vs expected{buttons:[], newTaskForms:0, draggable:[]}.ok 28 - counter-proof: a writable board keeps all four writes— green on the base by design, so a fix cannot pass by deleting the controls outright.readOnlyabsent) and the same roster withreadOnly: 'This window is read-only.'over one board with three cards.The fix
KanbanDialogreads the lock once, with the predicate the sidebar already uses (sidebar.js:371: a non-empty string), and passes it down:BoardView→ noAdd taskform whenlocked; passeslockedto everyBoardColumn.BoardColumn→ noonDragOver/onDropeffect whenlocked(a drop runs noonMove, so notaskUpdate).BoardCardviacardProps→movable: !locked && canMoveTask(...), so no card isdraggableand Start/Complete are not drawn.move()andcreate()return early whenlocked— the write entries refuse even if a caller reaches them.Delta, file by file
core/src/client/kanban.jscore/test/kanban.test.jsdocs/subsystems/core-client.mdchangelog.d/2248-readonly-task-board.fixed.mdcore/client.jsbuild-client)patches/ds-bot/0008-client-bundle.patchpatches/ds-bot/files/src/client/kanban.jspatches/ds-bot/files/test/kanban.test.jsGenerated by
node scripts/ds-bot-patches.mjs generate(run on the tip tree) and compared file by file against the tip; no hand-merged conflict.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/.What I ran, at tree
0bb21f646de45f550ebc417e9c70d2ac11eae1a2(replayed onto main03a125306226158ae13c1b3a1185e4db30c7ca67)node --test core/test/kanban.test.js→ 28 / 28 / 0, includingP-455: a read-only window draws no write on the task boardandcounter-proof: a writable board keeps all four writes.node --test core/test/dialog-focus.test.js→ 3 / 3 / 0 — client: Settings takes focus when it opens and returns it to the opener (#2251) #2262's Settings-dialog focus is still in the regenerated bundle.npm --prefix core test, run the way CI runs it (DSH_HARNESS=core/dev/harness,TZ=UTC) → 2680 tests, 2677 pass, 3 fail, and every red is this box, not the change:check-arch-docs.test.js:39needs a git checkout (green once a local repo exists),check-arch-docs.test.js:73needs an executable/tmp(this box mounts/tmpnoexec), andusage-fields.test.js:88shells out topython3, which this box does not have. No kanban/client test is red.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 generateon the merged tree → no-op against what is committed.npm run verifycould not finish here: the box ran out of threads (pthread_create: Resource temporarily unavailable) and the tarball-only checkout has no4a9d3eddobject for thearch-docsstep. CI is the reference for the full chain.The replay
#2262 and #2263 landed after this tip was cut and both touch generated files, so
update-branchwas refused (422merge conflict between base and head). The branch was replayed onto03a125306226158ae13c1b3a1185e4db30c7ca67:core/src/client/kanban.js,core/test/kanban.test.jsand the changelog fragment came over as written;docs/subsystems/core-client.mdis a semantic merge (main's #2251 bullet plus this PR's kanban row); every generated file was regenerated, never hand-merged —core/client.js,patches/ds-bot/0008-client-bundle.patch,patches/ds-bot/files/src/client/kanban.js,patches/ds-bot/files/test/kanban.test.js. Againstmain's tree the branch differs in exactly these 8 files,0008differs only by the read-only gate (cardProps/BoardColumn/BoardViewlocked), and #2262's overlay-hooks / dialog-focus bundle changes are intact.Tier, by path
createGate(risk-rules).judge(files)over exactly these 8 paths:core/src/client/kanban.js=T1,core/test/kanban.test.js=T1,core/client.js=T1,patches/**=T1,changelog.d/**=T1,docs/**=T0 → T1, 62 changed lines in 4 written files (201 lines over 8 with generated ones).Checkpoint
{
"pr": 2261,
"claim": "Chief",
"issue": 2248,
"summary": "A read-only window no longer draws task-board writes the host would refuse. KanbanDialog reads roster.readOnly once and hands the lock to BoardView, BoardColumn and BoardCard, so the Add task form, Start, Complete and draggable are gone, a drop runs no move, and move/create return early. The rail, the three columns, the cards, the archive page and the Done stamps stay readable. A writable window keeps all four writes, which the counter-proof test pins.",
"files": [
"core/src/client/kanban.js",
"core/test/kanban.test.js",
"docs/subsystems/core-client.md",
"changelog.d/2248-readonly-task-board.fixed.md",
"core/client.js",
"patches/ds-bot/0008-client-bundle.patch",
"patches/ds-bot/files/src/client/kanban.js",
"patches/ds-bot/files/test/kanban.test.js"
],
"checks": {
"ran": "node --test core/test/kanban.test.js (28/28/0); node --test core/test/dialog-focus.test.js (3/3/0); npm --prefix core test as CI runs it (2677/2680; 3 environmental reds: no git checkout, noexec /tmp, no python3); build-client --check; ds-bot-patches check + generate (no-op)",
"result": "green",
"at": "0bb21f646de45f550ebc417e9c70d2ac11eae1a2"
},
"next": "CI full suite on the replayed tip; T1 enqueues with no PASS once tests-ok and Node 24 are green."
}