Stopping the bot previously halted conversation syncing too. On the
multi-account path the run-flag check sat above both the reply-sync and
response-check branches, so a stop left only MediaSyncService's coarse
30-minute chat refresh. The legacy single-account path did the opposite
and kept syncing while stopped — one boolean meaning two things.
Replace the boolean with an explicit three-way mode:
running — discover, screen, send, automate replies
scan — refresh chats, detect replies, check responses; send nothing
and discover nothing; actionable replies surface as backlog
stopped — everything halts, including background media sync
scan differs from browser.dryRun, which still discovers and pays for AI
screening before suppressing the send.
The mode persists in runtime_state.bot_mode; a migration backfills it
from bot_running, and rows written by an older build still read
correctly. Both loops now gate on the mode, the account runtime loop
reconciles background media sync on transitions only, and the dashboard
and agent API expose all three states.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The settings page had accumulated five tabs whose names no longer matched
their contents, three different save models, and the whole subreddit
configuration buried under a tab named after a checkbox.
Structure:
- Subreddits becomes its own page: a list showing each community's mode,
tone, computed share of polling, and live sent/reply stats, with one
subreddit edited at a time in a drawer.
- Accounts becomes its own page. It is session lifecycle, not config.
- Settings collapses to one scrolling page: Safety, Pacing (Monitoring and
Rate limits merged), Targeting, Notifications, Advanced.
- The sidebar is grouped, having gone from 9 to 11 destinations.
Saving:
- Every section owns its own draft, validation, risk gate and save via
useConfigCard, submitting only the keys it owns. A syntax error in the
advanced JSON can no longer block a rate-limit change, and enabling an
autonomous policy is its own deliberate commit.
- UnsavedChangesProvider restores the leave-page guard across cards that no
longer share a draft.
Subreddit editing:
- Errors are keyed by field name instead of array index, removing the
defensive invalidation that existed because row indices shifted on add
and remove. Confirming an autonomous mode can no longer be attributed to
the wrong row.
- Weight is shown as the share it actually produces, live while editing.
- Bulk actions cover start/pause polling, tone, policy and removal, because
production runs 30-40 subreddits and per-row editing does not scale.
Bulk policy changes name every subreddit turning autonomous, and
normalise the hybrid mode's turn budget, which has no form to catch it.
Physique targeting moves into its own Targeting card. It sends only
reddit.physiqueTargeting, which the config route applies independently, so
it cannot clobber the pacing card's fields. Turning screening on now warns
that it will reduce how many posts qualify.
Also surfaces the effective sending rate, since the hourly limit and the
minimum delay both throttle and only the binding one matters.
Legacy ?section= links redirect or resolve to anchors.
Fixes found while verifying in a browser: a radio-card rule was shrinking
nested number inputs; .share-preview had no styles; the throughput readout
reported a rate from a blank field; and the reconcile logic warned about a
server change whenever a sibling card saved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Shared foundation:
- New Modal component on native <dialog>.showModal() (focus trap, inert
background, Escape, focus restore, scroll lock); all eight dialogs and
both globalThis.confirm calls migrated to it
- Design tokens for success/warning/danger surfaces; pill danger variant;
.sr-only utility; toast layering above dialog backdrops; not-allowed
cursor for validity-disabled buttons
Conversations/attention: auto-scroll with jump-to-latest, per-conversation
draft persistence, suggestion undo, 30s auto-refresh with refresh controls,
unread emphasis and counts, blur-consistent share dialog, empty-accounts
guidance, collapsed user lookup, relative timestamps, danger pills for
critical items
Media/library/outreach: click-blurred-to-reveal, lightbox with arrow
navigation and captions, dirty-form preservation across refetches, upload
validation with thumbnail preview, save feedback, result counts with
load-more and clear-filters, ticking countdowns from a single clock
Overview/performance/operations/settings: mutation errors inside the
confirm dialog, live sending-window countdown, offline-aware loading
states, per-panel loading/error with retry, 7/30/90-day range toggle,
console scroll yielding with shown/retained counts, risky-save matching
by subreddit name instead of index, useBlocker unsaved-changes guard,
single-pass validation with focus-to-first-error, access panel JSON
validation and input reset
Tests: 806 -> 844 passing; both typechecks clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>