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: a6741b41601c430a899b7f522ad42012
Branch: dev/2-tree-readonly-reorg
Base: 75e3c18
At: 2026-11-02T18:36:15Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
Owner: FlyBot Dev-2
Branch: dev/2-tree-readonly-reorg
Credit: audit and draft by FlyBot Product (P-439).
Kind: bug (read-only surface)
Source: FlyBot Product audit P-439, re-read by FlyBot Lead on live main 75e3c18d: plugins/tree/client.js has zero readOnly occurrences, tree/undo and tree/dismiss are registered without { read: true } (plugins/tree/index.js:63 and :64; only tree/reorg at :62 is a read), and the notice draws both buttons unconditionally.
Dedupe (searched before opening)
Issue searches (title+body): tree reorganized, reorg notice, tree undo read-only, Undo Dismiss tree. Hits are the tree self-organization feature itself (closed issue #446, closed PRs #448/#454/#828), an open sidebar-cosmetic issue #818, and open follow-ups #450 (memory handoff on merge, model pins) — none of them gates the reorg notice on roster.readOnly. Closed read-only issues/PRs (#2176/#2181/#2190/#2195/#2205/#2215) are all the workflow plugin. No issue covers this notice.
What happens today
makeReorgNotice (plugins/tree/client.js:444-471) is registered as a sidebar section (apply, :556, flybot.slots.register('flybot.sidebar.section', { id: 'flybot-tree-reorg', order: 89, component: makeReorgNotice(ctx.flybot) })). The section component is handed { roster, actions, call } by the shell (core/src/client/flybot-slots.js documents that shape), but ReorgNotice (:445) reads no props today.
When a reorganization ran within NOTICE_DAYS, noticeRun (:426-429) yields the run and the card is drawn by ReorgCard (:431-443), whose action row (:439-441) always renders Undo (:440, tree/undo) and Dismiss (:441, tree/dismiss).
In a read-only window the host refuses both writes (core/src/host/channel.js:295-296), the client catches the rejection into note (:465), and the reader is left with two buttons that can only fail. tree/reorg itself is a declared read, so the notice — title, time, the moved lines — is legitimate read-only information and should stay.
Why it is common rather than theoretical: reorgNotice is on by default (apply, :557), the daily tidy can produce a run every day, and the card stays visible for NOTICE_DAYS (7) — so a second, read-only window opened in that week usually carries this notice with a dead Undo on it.
Reproduction (measured on 75e3c18d)
- Mount the registered section component with
roster: { bots: [], readOnly: 'This window shows the team but cannot change it.' },flybot.call('tree/reorg')returning one run{ id: 'run-1', at: Date.now() - 60_000, summary: ['Moved 3 Bots'] },flybot.fields.ona no-op. - Read the tree:
button.flybot-reorg-btncount = 2 (Undo,Dismiss). ClickingUndoissuesflybot.call('tree/undo', { runId: 'run-1' }). - Same fixture with a writable roster (no
readOnly): identical output.
Probe: plugins/tree/test/probe-tree-readonly.test.js in the evidence tree tmp/a1105/m2 (plugins/tree/client.js unchanged by it).
Expected behaviour
With a read-only roster and a fresh run, the notice still shows what was reorganized — the title, the time, the moved lines, and the Kept: line when the run was undone — and draws no Undo and no Dismiss (button.flybot-reorg-btn count 0). On a writable roster the card is byte-for-byte what it is today: both buttons, same handlers, same busy/disabled behaviour and same note line on failure. The host keeps refusing those writes in a read-only window either way; this issue is about not offering the control.
Signal to use: roster.readOnly (trimmed, non-empty ⇒ locked), the same sentence and the same test the workflow page uses (plugins/workflow/client.js:1570-1571, :1954-1955). No new endpoint, no new protocol field.
Scope
plugins/tree/client.js—makeReorgNotice(:444-471): readroster.readOnly, and when it is set render the notice without the action handlers (the card must then draw no action buttons);ReorgCard(:431-443) draws its action row only when at least one handler is present.plugins/tree/test/— the red-first test below (client render only; the repo's existing tree tests show the rendering harness).changelog.d/<this issue>-tree-readonly.fixed.md;plugins/tree/README.mdif it describes the notice.
Not in scope: the daily tidy, the reorg journal format, tree/reorg's read flag, the archived/structure sections, and any workflow or core surface (those have their own issues).
Red first
New plugins/tree/test/reorg-readonly.test.js, whole-tree counts:
A. read-only roster + one fresh run ⇒ button.flybot-reorg-btn count = 0, while the card still renders: .flybot-reorg count 1 and its text contains the run's summary line. (Today: 2 buttons.)
B. writable roster + the same fixture ⇒ button.flybot-reorg-btn count = 2, the first is Undo and issues tree/undo with { runId }; clicking it in the read-only fixture is impossible (no button), so assert the call count of tree/undo/tree/dismiss under the read-only roster is 0. (Today: 2 buttons, clicking sends the write.)
C. no fresh run (older than NOTICE_DAYS, or dismissed === run.id) under either roster ⇒ no card at all (pins the existing freshness rule).
Acceptance
- A and B fail before the change and pass after; C passes before and after.
plugins/treesuite green,npm run verifygreen,arch-docs: OK.- A read-only window shows the reorganization notice and no write control on it; a writable window is unchanged.
Activity
HugoXK commentedon Nov 2, 2026
Release
Written-by: FlyBot Lead
Released: a6741b41601c430a899b7f522ad42012
Reason: merged via PR #2223 (c8d55d9)
At: 2026-11-02T19:39:26Z
tree: a read-only window still offers Undo and Dismiss on the reorgan…