Skip to content

core: a read-only window still draws New task / Add one entries that lead to a form it hides #2243

Closed

Description

@HugoXK

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 row New task is drawn unconditionally and calls actions.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 no locked input at all.
  • core/src/client/schedules.js:376-379 — inside the page, locked already suppresses the form and the page's own New task button.
  • id on the schedules page means "creation target": settings.js passes it as start, and SchedulesPage opens 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 task row calls openSettings('schedules', target) and the menu never looks at readOnly (grep -n readOnly composer.js → 0), although ComposerPlus already 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

  1. In a read-only window, no create entry point is drawn: the Bot details New task row, the ScheduleSummary empty-state Add one line, and the composer Scheduled task row are all absent.
  2. A writable window keeps all three exactly as they are today.
  3. The lock predicate is defined once and shared (the same test already exists privately as lockedWindow and is duplicated in sidebar.js, settings.js, workflows.js) — a fifth copy is not acceptable.
  4. 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 details New task row and the ScheduleSummary empty-state button when the window is read-only (the summary receives the roster it needs).
  • core/src/client/composer.js — the Scheduled task menu 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.js and patches/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

  1. added a commit that references this issue on Nov 3, 2026
    b451e3b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions