Any failed refresh (offline, 5xx, 429) cleared both tokens, and each
expired request started its own refresh, so a burst of 401s could
trip the refresh rate limit and log the tab out. Page load also wiped
tokens on any /auth/me failure. Share one in-flight refresh, end the
session only on a 401/422 from /auth/refresh or /auth/me, and let
transient failures surface as errors with the tokens intact.
pg_create_database/user and pg_grant/revoke built superuser SQL from
raw names and passwords, unlike the MySQL helpers beside them. A quote
in a password broke CREATE USER, and the create routes ignored that
and returned credentials for a user that did not exist. Validate
identifiers and privilege lists, escape the password, and surface a
failed user as user_error instead of fake credentials.
Auto-provision defaulted on with role developer and no domain filter,
so enabling GitHub login for yourself let any GitHub user sign up and
open remote terminals, while password registration stayed closed.
Default to off and viewer; turning it on stays an explicit choice.
The vertical stepper rail floated between steps instead of joining the
markers, and the current step borrowed the focus ring. Radio cards
showed a radio dot beside the icon; the card already marks selection,
so the radio becomes a check badge in the corner.
FormField now hands its control the id, aria-describedby, aria-invalid
and aria-required through context, so every settings form announces
its hint and validation without per-call wiring. IconButton gets a real
tooltip instead of title=, ProgressBar is a labelled progressbar with
tones and an indeterminate state, and Button takes `loading` without
changing width.
New controls the panel lacked: NumberField, Combobox (single, multiple,
creatable), TagInput, Calendar with DatePicker and DateRangePicker,
PinInput, Slider, RadioGroup, Stepper, TreeView, and FileDropzone with
FileUploadList. Rounding, date and file-type rules live in lib/ with
unit tests. All of them render on /style-guide/controls.
The Templates page only featured a hard-coded list, so `featured: true`
in a template (Prompture Hub, Torre) never reached the Featured-first
view. The page now honors the flag alongside the list, and bundled
templates carry it into the catalog and the published index.
FileRow and FileCard were wrapped in memo, but every handler passed to
them was re-created on each render, so a keystroke or a selection
re-rendered every row of a large directory. useStableHandler gives the
rows fixed handler identities that still run the latest code.
The picker hardcoded ids like sp-hour, so two on one page (one per
schedule card) produced duplicate ids and every label pointed at the
first picker's field.
The pickers dropped an id, so the five labels above them named
nothing. They now put it on the trigger button; clicking the label
opens the picker. Ratchet 46 -> 41.
Three hand-rolled copies printed untranslated "3m 0s" and never
reached hours ("75m 0s"). They now use the intl formatter ("1h 15m",
in the panel language), keeping each caller's placeholder. The cron
and deploy-console formats with tenths of a second stay as they are.
156 labels named no field: no htmlFor and no control inside, so
clicking one did not focus the input and screen readers announced the
input without a name. Each now points at its field through a useId()
id. The change is additive only (ids and htmlFor), checked by comparing
tokens with the previous version.
A row with onRowClick could only be opened with a mouse or the j/k
cursor: it took no Tab focus and ignored Enter. Clickable rows in the
tables, the grid and the card view are now focusable and open on Enter
or Space, with a focus ring. Keys on a button inside the row still
reach the button, and the cursor listener skips a key a row handled.
The vault secret and variable-group columns were memoized without the
state their delete handlers read. Deleting a secret then refreshed a
null vault and reported failure; deleting a group variable sent group
null; deleting a group after a workspace switch reloaded the old
workspace's groups.
The lookup's answer checked the name as it was when the code was
typed, so a name entered while it was in flight was overwritten with
the agent's hostname.
The listing effect watched only the path. Switching to a remote agent
that advertises no allowed paths keeps the path, so the panel host's
files stayed on screen under the agent's header, and edits went to
the agent against the wrong host's entries.
Both used psutil without importing it, so every call has been a 500
since they were written. Nothing calls them: the process list and
service status come from /processes and /processes/services.
The Coexistence page and the extension crash card were written with
their own stylesheets, but neither file was ever imported, so both have
always rendered without their layout. A new lint step,
check-orphan-files, fails on any src file nothing imports (SCSS
included) unless it is kept with a reason; it is what found these two.
An app-detail SettingsTab and its shared helper left behind when the
page merged into service detail, a re-export shim nobody imports, and
an unused utility; with their 13 strings in every locale.
420 lines styled a query runner component removed long ago. One of its
unscoped rules, .sidebar-section, was still sizing the File Manager
rail by accident; that rule moves into the File Manager stylesheet so
the compiled CSS for it is unchanged (compared before and after).
Picking a priority in the Terminal's journal view highlighted the level
but never sent it, so the list was unfiltered. The API already filtered
on ?priority=; the client now passes it, with the fresh value rather
than the previous render's.
Volumes, Networks and Compose had the same two bugs fixed earlier in
Containers and Images: a late answer from the previously selected
server replaced the current list, and a failed load showed an empty
list (or the old one) instead of the error.
Four inline dialogs kept their open flags, targets and input values as
ten separate useState calls on the page. One dialog state now says which
is open, and NamePromptModal / PermissionsModal own their inputs; the
browser test drives all three flows and passes on the old code too.
The create-file dialog had no way to open it and is removed with its
strings.
Comments cited plan sections as "(§G3)" or "(§8 unification)", which
point into the same git-ignored plans the plan-number citations did.
References next to a real document (docs/REDESIGN_MAP.md §3) stay. Code
and runtime strings are unchanged (AST and token comparison).
The worst cases the audit named: docstrings and header comments that
told how three old copies drifted, or quoted subprocess counts that
were stale the day they were written, instead of stating the contract.
Each now says what the function does and keeps one line of why. Also
drops the always-zero n_cloud counter that existed only to keep a boot
log line's or-chain intact.
107 direct toLocaleString/DateString/TimeString calls followed the
browser's locale (or a hard-coded en-US/en-GB) instead of the language
the panel is set to, and built a formatter per call. They now go
through utils/intl (formatDate/Time/DateTime/Number), keeping each
site's components via parts. A missing date now renders the fallback
dash instead of "Invalid Date". Ratchet ceiling 115 -> 4.