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: a41089f1cdd34475b08a8e4188440002
Branch: dev/4-p457-schedules-create-entries
Base: 5a21d5b
At: 2026-11-03T01:06:12Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Credit: found by FlyBot Product (P-457 audit).
Kind: defect — a read-only window shows two create-entry points that lead to a creation form it deliberately hides, so the click lands on an empty page with no form, no control and no refusal line.
Source: every line below re-read by Lead on live main 5a21d5b44700533d6ba1789f094875cb1121dbe6 (the main that already carries #2239).
Dedupe (searched before opening)
Searched open and closed issues for New task read-only, Add one schedules, scheduled task read-only, openSettings schedules: 41 / 31 / 9 / 11 hits, none for this gap. The nearest are the parent #2232 (closed completed, "a read-only window still offers every scheduled-task write") and its child #2235 (closed, which hid the write controls), plus #2200 (workflow panel) and #2153 (diagnostics). No open issue covers the entry points that survived #2235.
What happens today
#2235 (227b94b6) taught SchedulesPage to hide its create surface in a locked window, but the two entry points that put a user into "create mode" were left alone:
core/src/client/schedules.js:460— the Bot details rowNew taskis drawn unconditionally and callsactions.openSettings('schedules', bot.id).core/src/client/schedules.js:497—ScheduleSummary's empty state (No scheduled tasks yet. Add one/No scheduled tasks you can see. Add one) does the same and has nolockedinput at all.core/src/client/schedules.js:376-379— inside the page,lockedalready suppresses the form and the page's ownNew taskbutton.idon the schedules page means "creation target":settings.jspasses it asstart, andSchedulesPageopens in adding mode. So the click arrives at a page that has the list, the Quiet hours block, and no form and no New task control — only the header's read-only sentence explains why.- Same family, third entry point:
core/src/client/composer.js:150/:170— the composer's+ → Scheduled taskrow callsopenSettings('schedules', target)and the menu never looks atreadOnly(grep -n readOnly composer.js→ 0), althoughComposerPlusalready reads the whole roster.
Regression, not a new requirement: on 98639924 the form still opened and the host refused the create with a visible sentence; after #2235 the form is gone while the entry points remain, so the result changed from "a visible refusal" to "nothing happens".
Reproduction
Open a second window on the same home (the later window is read-only) → open a Bot with no scheduled tasks → in its details panel click Add one (or, in the Bot settings page, the Scheduled tasks card's New task) → the settings page opens on Scheduled tasks: the list and Quiet hours are there, but there is no form and no New task control, and no refusal is shown. Keyboard and mouse behave the same. The composer + menu's Scheduled task row behaves identically.
Red-first (captured on 227b94b6, sources untouched, tests only)
cd core && node --test test/probe-schedules-entry.test.js → # tests 52 / # pass 50 / # fail 2:
not ok 50 - a read-only window draws no create entry point
BotSchedules offers New task (expected [])
not ok 52 - the details line alone offers Add one in a read-only window
locked offers No scheduled tasks yet. Add one; writable offers No scheduled tasks yet. Add one
ok 51 - SchedulesPage({…, start:'b1'}) draws no form and no New task in a locked window
51 is the proof that the destination page already has no way forward; the writable-window counter-proof (both entries present) passes in the same run. The composer half has its own red-first: cd core && node --test test/probe-composer-locked.test.js → # tests 2 / # pass 1 / # fail 1 (the writable case passes and sends ['schedules','b1']; the locked case draws the row and still sends it).
Expected
- In a read-only window, no create entry point is drawn: the Bot details
New taskrow, theScheduleSummaryempty-stateAdd oneline, and the composerScheduled taskrow are all absent. - A writable window keeps all three exactly as they are today.
- The lock predicate is defined once and shared (the same test already exists privately as
lockedWindowand is duplicated insidebar.js,settings.js,workflows.js) — a fifth copy is not acceptable. - Nothing else about the schedules page changes: no form is added back inside a locked window and no refusal copy is invented.
Scope
core/src/client/schedules.js— drop the detailsNew taskrow and theScheduleSummaryempty-state button when the window is read-only (the summary receives the roster it needs).core/src/client/composer.js— theScheduled taskmenu row respects the same lock.- One shared helper for "this window is read-only" instead of a new inline copy.
core/test/— the cases above as permanent tests (red-first evidence already captured);docs/subsystems/core-client.md— the schedules paragraph that still claims the empty-state button is the only way into the form;changelog.d/fragment.- Regenerated
core/client.jsandpatches/ds-bot/0008-client-bundle.patch(bundle lane; this issue holds that lane until it merges). - Out of scope: adding a refusal line, and any change to the settings page's own guard.
Activity
core: a read-only window's create entries no longer open the schedule…