Repository navigation
core: the read-only reads test passes on a dry answer — assert each row's own key - #2280
Conversation
66211ac to
23da818
Compare
…owLab#2278) The test added with ThinkFlowLab#2269 was the only guard against a read name falling out of `channel.js`'s READS whitelist, but it asserted only "not refused with bot/read-only". An answer past the gate but dry passed: `folder-list` answered bot/refused with no browser, `connector-app-status` answered "Connect Composio first", `project-decision` answered the "nothing listed" half, and `project-of` / `project-board` / `folders` answered ok with empty data. Each of the 11 READS rows now checks the data its screen draws, and the fixtures make that data real: a `browse` directory picker for the folder rows, a signed-in Composio session with its host stubbed for the connector row, and a Project working folder holding the decision file the board itself lists (ThinkFlowLab#2041). Four rows that only checked a shape now check values: the board's `counts` and its credential-less `metrics` (ThinkFlowLab#1829), the dossier's Chief row (ThinkFlowLab#1864), the assistant memory entry (ThinkFlowLab#1712), and the `picker` kind the Browse entry needs. A refusal as bot/read-only (the whitelist lost the name) and a dry answer (the fixture never made the data) are reported as two separate lists, so a red names the defect.
23da818 to
e6bb416
Compare
|
@Birfy —
What it does: the read-only reads test now checks the values each screen draws instead of the shape of the answer. Before this change a dry answer passed: the guard only asked "not refused with Self-test: the four rows go red when their seeded data is removed, and again when the readers are made to answer dry; deleting a name from the channel's read list reddens the row that names it ( |
…ays nothing about why (ThinkFlowLab#2277) Fixes ThinkFlowLab#2276 Fixes ThinkFlowLab#2279 Fixes ThinkFlowLab#2283 Three read-only slices on one branch. They all end in the same client bundle and the same generated patch split, so they share one build and one `generate`: the alternative was three PRs each rewriting `0008-client-bundle.patch` and fighting over `core/client.js`. ## What each one fixes - **ThinkFlowLab#2276 — the Memory panel** (`core/src/client/memory-panel.js`, +9/−5): a read-only window no longer draws **Remove** or the ask/update form, both of which the host refuses (`memory-forget`, `memory-ask`), and says why in the host's own sentence from `roster.readOnly`. The entries themselves and **Regenerate summary** (a read) keep working. Test: `core/test/memory-panel-readonly.test.js` (3 tests). - **ThinkFlowLab#2279 — the details drawer's Settings view** (`core/src/client/details-drawer.js`, +5/−3): it draws the host's read-only sentence in the form's place instead of mounting `BotSettingsForm`, reading the same window lock (`lockedWindow`) the settings page reads. A writable window keeps the form unchanged. The same file hands the roster back to `ScheduleSummary`: without it the details overview drew its "No scheduled tasks yet. Add one" entry in a read-only window, and that entry opens the create form a locked Settings page does not draw (ThinkFlowLab#2232/P-457). The suite for this change now renders the overview path, because `core/test/schedules-client.test.js` calls `ScheduleSummary` with a roster of its own and cannot see a call site that forgets one. Test: `core/test/details-bot-settings-readonly.test.js` (3 tests). - **ThinkFlowLab#2283 — the ask_user card** (`core/src/client/questions.js` +38/−24, `core/src/client/cells.js` +1/−1): a read-only window draws no answer control on the card, and the answers it already holds stay readable. Test: `core/test/questions-readonly.test.js` (6 tests). `docs/subsystems/core-client.md` carries all three bullets, and each change has its own fragment under `changelog.d/` (ThinkFlowLab#2276, ThinkFlowLab#2279, ThinkFlowLab#2283). ## Files 21 files, `+17621/−16580`. The semantic change is six files plus three new tests, three changelog fragments and the one-line `topics.json` mapping; everything else is the generated split: `core/client.js` and its `0008-client-bundle.patch` (a module-order relocation of `questions.js` and `schedules.js` inside the bundle — the bulk of the line count, not new code), `0001-core-fixes.patch`, `0003-flybot-api-client.patch`, `0012-room-membership.patch`, and the three whole-file mirrors under `patches/ds-bot/files/test/`. `patches/ds-bot/topics.json` is in the diff for one reason: `src/client/questions.js` is an upstream file FlyBot edits, so `generate` refuses the split until that file has a topic (`0003-flybot-api-client`), and without that one line `core/` cannot be rebuilt. ## Red first, then green - The overview half of ThinkFlowLab#2279 has its own red: with the drawer not passing `roster` to `ScheduleSummary`, `core/test/details-bot-settings-readonly.test.js` was `# tests 3 / # pass 2 / # fail 1`, `no create entry is drawn in a read-only window` — actual `['No scheduled tasks yet. Add one']`, expected `[]`. With the roster passed again it is `3/3/0`. - The other two suites were written against the behaviour they lock (a read-only window draws no write entry, a writable one keeps it), so each asserts both sides: the Memory panel `3/3/0` and the ask_user card `6/6/0` on this tip. ## Evidence, measured on this tip's tree - Suites, each run with `TZ=UTC node --import ./test/harness-resolve.mjs --test <file>`: - `memory-panel-readonly` `3/3/0`, `details-bot-settings-readonly` `3/3/0`, `questions-readonly` `6/6/0` (tests/pass/fail). - Regressions in one run, `# tests 173 / # pass 173 / # fail 0`: `memory` `97/97/0`, `memory-empty` `6/6/0`, `memory-search` `4/4/0`, `schedules-client` `52/52/0`, `questions` `2/2/0`, `settings-readonly-head` `3/3/0`, `sidebar-readonly` `4/4/0`, `composer-locked` `2/2/0`, `readonly-window-reads` `3/3/0`. - `TZ=UTC npm run verify` at the repo root — exit 0 on this tree (core lint + `arch-docs`, plugin lint, `build-client.mjs --check`, `ds-bot-patches.mjs check`, the core suite and both plugin suites). - `ARCH_DOCS_BASE=89125458 npm run lint` — `Found 74 warnings and 0 errors` (warnings pre-existing), `arch-docs: OK (21 changed file(s))`. - `node scripts/ds-bot-patches.mjs check`: ``` 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/ ``` - `node scripts/ds-bot-patches.mjs canonical` — `ok patches/ds-bot/ is what generate writes (generate is a no-op)`: `generate` was run twice on this tree and the second pass wrote nothing. - `npm run build` (in `core/`) reproduces the committed `core/client.js` byte-for-byte: a second build leaves the tree clean. - The branch was rebased from `19e206ec` onto `89125458` after ThinkFlowLab#2280 merged, and `build`, `generate`, `check`, `canonical` and `verify` were all re-run there. ## What I did not run - The bench smoke test — this branch touches no `core/index.js` and no `core/src/host/` file. Verified head: `bb5a863229103b45a50baec3ca71d3d4e295e4a8` (tree `e43d9a1538ed12b01adad475f2c856ab3fe9418b`, single parent `891254589abb9aa6ac42bc1bb64874c716648876`).
Fixes #2278
What was wrong
core/test/readonly-window-reads.test.js(#2269) is the only guard against a read name falling out ofchannel.js'sREADSwhitelist, but it asserted only "the answer is not refused withbot/read-only". An answer that is past the gate and dry still passed, so the guard was green on a tree where a read-only window draws those screens empty. Measured on the tree of this PR's base with the file as it shipped:folder-list{"ok":false,"error":{"code":"bot/refused","message":"This DeepSeek Harness cannot list folders"}}connector-app-status{"ok":false,"error":{"code":"bot/refused","message":"Connect Composio first"}}project-decision{"ok":true,"value":{"ok":true,…}}— the "nothing listed" halfproject-of{"ok":true,"value":{"project":null}}project-board…"reason":"no working folder: this Project names none"folders{"ok":true,"value":{"team":null,"picker":null,"folders":[]}}Six reads were dry; the old file was
# tests 3 / # pass 3 / # fail 0on that same tree.What this changes
Test-only: no source change, no shared fixture.
core/test/readonly-window-reads.test.js— each of the 11READSrows now checks the values its screen draws, not the shape of the answer, so a dry answer is red instead of passing for "not refused". What each row proves: the row itself (tasks,projects,project-read,project-of,project-read's project,project-decision's file text and the decisions the board listed), the count beside it and its numbers (project-board:taskspluscounts.waiting === 1/inflight 0/blocked 0;metrics.ok === falsewith reasonno-credentialsand every metricnull, 项目看板:7 个指标卡 + 在跑任务表 #1829), the people (project-team: a Chief row withbotId === 'a', notrows: []or[null, null], Project board shows each Project Bot's dossier (persona, memory, skills), and the owner opens their agent from their own chat #1864), the memory entry (project-memory: a decision whose text isA decision, not an empty record, Stage 2.5: the Project Assistant, minimal version (private memory + daily 09:00 digest) #1712), the folder rows and the chooser kind (folders:picker === 'browse'plus the working folder;folder-list: an entry nameddecisions), and the connector's app state (connector-app-status:gmail === 'ready'). A row's payload may be a function of the answers above it, used only byproject-decision, which opens a name the board itself listed (Project board decision rows can be listed but never opened #2041) rather than one this file made up. A refusal asbot/read-only(the whitelist lost the name) and a dry answer (past the gate, no data) are reported as two separate lists, so a red names which defect it is.directoryPickerof thebrowsekind on the fake context for the folder rows; a signed-in Composio session (state seed +COMPOSIO_API_KEYinsecrets.json, with onlyhttps://backend.composio.dev/stubbed and the realfetchrestored on stop) for the connector row; a Project working folder holdingdecisions/2026-01-01-x.mdfor the decision and board rows.patches/ds-bot/files/test/readonly-window-reads.test.js— the same bytes.core/is carried asds-bot/+ patches, and this test file is one of the whole-file overlay entries, so a change undercore/test/is only consistent once the overlay copy is regenerated.packagestepds-bot/ matches the pin, patches apply, core/ is ds-bot/ + patches (#34)caught exactly that (core/test/readonly-window-reads.test.js: differs from ds-bot/ + patches) before this file was regenerated in.Red first, then green
# tests 3 / # pass 3 / # fail 0. The six dry answers above went unnoticed (false green).# tests 3 / # pass 3 / # fail 0, run twice with the same counts.channel.js'sREADSmakes the read-only case red and names it —'folder-list'removed →# tests 3 / # pass 2 / # fail 1,not ok 1 - … a read-only window still answers these reads: folder-list. The same shape was reproduced forconnector-app-statusandproject-decision.channel.jswas restored and the tree of this commit (below) re-verified green afterwards.status/queueRoleand thebrowsechooser stripped from the fixtures — i.e. exactly the four dry answers that shape-only checks used to accept — the same case is red and names those four rows:project-board,project-team({"rows":[null,null]}),project-memory("decisions":[]) andfolders("picker":"native"), plusfolder-listbecause anativechooser has no listing:# tests 3 / # pass 1 / # fail 2. Restored, then green again.What I ran
TZ=UTC node --import ./test/harness-resolve.mjs --test test/readonly-window-reads.test.js—# tests 3 / # pass 3 / # fail 0(twice, and once more after the patch overlay was regenerated).git checkout -- core/src/host/channel.jsand a green run on the restored tree.node scripts/ds-bot-patches.mjs generate— 307 overlay files written, of which exactly one changed (patches/ds-bot/files/test/readonly-window-reads.test.js, +84/−33); no.patchfile changed.node scripts/ds-bot-patches.mjs check—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).mainb451e3b3(this PR's base moved after core: a read-only window's create entries no longer open the scheduled-task form #2246 merged), thennode scripts/ds-bot-patches.mjs generateagain — it wrote nothing (no overlay or patch file changed),checkandcanonicalstill green, and the affected suite re-ran green on the rebased tree.ARCH_DOCS_BASE=b451e3b3 npm run lint—Found 74 warnings and 0 errors(warnings pre-existing),arch-docs: OK (2 changed file(s)).git show --stat— 2 files, +216/−68 (the test and its overlay copy, same 142-line diff each).What I did not run
npm run verify— not run in this worktree. The change is test-only with no source edit; the affected suite, the patch checks above and lint were run directly.changelog.d/fragment and no subsystem doc (test-only, no user-visible change).Verified head:
e6bb416cc52c0583348469d8a94b656f4e5ab8d1(treeb201349f4c5d170b4b9a1db48ed6207404d938a5, single parentb451e3b361771e85db156845f89a254c62ac275d) — the pushed tip, whose tree is byte-for-byte the tree the run counts above were taken on.