Skip to content

Settings: a refused write is reported on the scrolling page's first line, above the viewport, so the sentence that explains it is never seen #2194

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: c228bfb6db5c4c038e8acf1b34e56873
Branch: dev/1-settings-refusal-line
Base: 9ede925
At: 2026-11-02T16:00:30Z

Owner: Dev-1
Tier: T1

What happens

Every write the host refuses while the Settings dialog is open is reported on the first line of the scrolling page, above the viewport once you have scrolled down — so the sentence that explains the refusal is painted outside the visible area and the control you just toggled stays as it was. In a read-only window the write is refused by design (core/src/host/channel.js:294-296, set-flags is not in READS), so this is the normal path there, not an edge case.

Evidence on live main 9ede9258 (identical in f88d9133):

  • core/src/client/settings.js:206 builds the message: errorLine = h('div', { className: 'bt-error', role: 'alert', style: { padding: 0 } }, error).
  • core/src/client/settings.js:226-227 errorLine is the first child of div.bt-settings-scroll, i.e. inside the element that scrolls.
  • core/src/client/styles.js:497 .bt-settings-scroll { flex: 1; overflow-y: auto; ... }; core/src/client/styles.js:337 .bt-error { ... } has no position: sticky / fixed.
  • core/src/client/settings.js:177-179 the failure path only calls setError; grep -n "scrollTop\|scrollTo(" core/src/client/settings.js core/src/client/bot-settings.js → 0 hits, nothing scrolls the message back into view.
  • The page is long enough for this to happen: BotSettingsForm (core/src/client/bot-settings.js:196-269) draws 13 cards, and Pin / Hide from sidebar (:257-258) and the Main Bot switch (:254) are all below the first screen.

Reproduction

  1. Open the same ~/.dsh in a second dsh window (the second one is read-only — this is the normal way bot/read-only appears).
  2. In that window: Settings → Bots → pick a Bot → scroll down to the Sidebar cards.
  3. Toggle Pin (or Hide from sidebar).
  4. The host refuses with bot/read-only; the sentence is written into .bt-error, but that node is at the top of the scrolling page and the viewport is below it. The switch renders from bot.pinned, so it does not move either.
  5. Result: the click looks like it did nothing, and the reason is off-screen.

Expected behaviour

A refusal stays in view at the moment it happens: the sentence either sits next to the control that was refused, or is pinned outside the scrolling area (below .bt-settings-head, which does not scroll). This is the same rule the Workflow plugin now follows for its dialogs (#2193): the host's sentence is shown where the action was taken, not somewhere the user cannot see.

The usage page keeps its current behaviour.

Scope

  • core/src/client/settings.js — move the refusal line out of .bt-settings-scroll (to just below .bt-settings-head, above the scrolling page), with the horizontal padding matched to the page's own inset.
  • core/test/settings-error-placement.test.js (new) — a test that drives the real SettingsDialog and asserts the role="alert" node is not a descendant of .bt-settings-scroll, with the text equal to the host's sentence.
  • Regenerated core/client.js and the patches/ds-bot/* mirrors (0008-client-bundle.patch, 0014-flybot-branding.patch, files/test/settings-error-placement.test.js).
  • docs/subsystems/core-client.md — one sentence on where a refusal is drawn.
  • changelog.d/<this issue>-settings-refusal-line.fixed.md.

Out of scope: changing what the host refuses, the wording of any host message, the behaviour of the individual forms, and .bt-error's global styling.

Prior art / duplicates

Searched before opening (settings refusal, bt-settings-scroll, settings alert scroll, and the closed set around bt-error):

  • #2176 / #2187 are the two Workflow settings pages' read-only entry points — the plugin page, not this dialog.
  • #2193 (open, ours) is the same defect class in the Workflow plugin's Rename/Delete/Create dialogs; different page, different file, and it does not move this node.
  • #1522 reports a swallowed stage control; #1820 is the Project memory Save button; #2140 is a credentials name refusal. None of them touch settings.js.
  • #1536 / #1762 / #1777 / #291 / #421 are scroll/layout issues in other panels.

No open or closed issue covers the Settings dialog's refusal line.

Acceptance

  1. With a refused write in the Settings dialog, the role="alert" node with the host's exact sentence is present and is not a descendant of .bt-settings-scroll.
  2. The new test fails against the current settings.js and passes after the fix.
  3. The usage page renders exactly as before.
  4. npm run verify green; patches check / canonical clean; arch-docs: OK.

Activity

  1. HugoXK commented on Nov 2, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: c228bfb6db5c4c038e8acf1b34e56873
    Reason: merged as 63faa79
    At: 2026-11-02T16:41:22Z

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