Bug bash 6: the phone fits ZFS, Usage and journal lines; a snapshot's default name is local time; twelve smaller faults

Found by a headless pass over every page on every machine at desktop and phone widths, then
every interaction on the hub. BUGS.md has the list, what was checked and found fine, and the
quality-of-life notes to discuss.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-10-03 11:28:44 -07:00
co-authored by Claude Fable 5.1
parent 3a58e265c6
commit e0e2562f0a
10 changed files with 160 additions and 14 deletions
+120
View File
@@ -608,3 +608,123 @@ swallows a failed WebSocket where Firefox writes it to the console. One thing it
hands logs "can't establish a connection". Sitting still on a page produces none, the address
is right, and the terminal belongs to the machine asked; `sockets.cjs` checks that ownership
rather than the noise.
# Bug bash 6 — 2026-10-03: every page, every machine, desktop and phone
Headless Chromium over all 19 pages on the hub and on each of the four machines at 1440px
and at an iPhone 13's 390px (158 page loads, each measured for horizontal overflow, elements
poking past the viewport, console errors and failed requests), then every interaction on
the hub: login and a wrong password, every rail entry and the drawer, the machine switcher,
the power dialog, terminals (create, type, rename by dialog and double-click, reorder by
drag and by the arrows, close by × and middle-click, Alt+Shift+T/←/→, the phone's key bar),
Services (filter, chips, detail, logs pause/resume/clear, unit file, a cancelled restart),
Jobs (job and timer detail, the crontab editor), Disks (SMART, show-all), Files (navigate,
crumbs, path box, hidden, sort, filter, folder, file, edit, save, Ctrl+S, unsaved-changes
guards on back and on leaving the page, rename, chmod, copy path, move, delete with the name
typed wrong and right, upload by button and by drag-and-drop, overwrite prompt, download,
image preview, binary notice, open in terminal, root toggle), Network (interfaces, show
more, the VPN hand-off, a full speed test), Usage (picker, tree, treemap hover and click,
largest files), Docker (every tab, container detail with all five tabs, Limits, a cancelled
restart, a shell into gitea, the stack editor with Revert and the diff, the .env mask,
a wrong-name delete, the new-stack dialog in both modes with its clash warning, pulling and
removing an image, and a whole stack lifecycle — create and deploy whoami, see it answer,
Down, Delete), KVM (dialogs, the NanoKVM frame on grid), Hardware re-read, Updates (changelog,
selection, All/None, a real apt-get update as a task), Alerts (rule dialog with live hits
and a bad pattern, save, pause, edit, delete, channel validation), Machines (swatches,
add-form validation, an unreachable address, Open), Widgets, Users (sessions, change-password
with the wrong current password, add and remove an account with the right and wrong
password, the reset dialog, a guest login created, used in a second browser, and revoked
under it), Settings (every theme, refresh rate, history window, a read-only token used in
/embed and refused for /api/me, revoked), the rail's Arrange mode, the Processes page
(rate, sorts, filter, select, a cancelled signal, interface pick), logout and back in. Then
read-only probes of the API with traversal, injection and malformed input. Firefox could
not run here (the box lacks its GTK libraries).
## Bugs — all ✅ fixed and verified by the script that found them
1. ✅ **The ZFS tab was wider than a phone.** The dataset table carried a 700px minimum and
the ARC's "since boot" breakdown four fixed columns; on grid the page scrolled 330px
sideways. Both drop to three columns and the ellipsis below 800px.
2. ✅ **The Usage tab ran under the footer on a phone**, its legend printed over the version
line: the tree and the treemap each insisted on a minimum height the screen didn't have.
Below 800px the page scrolls, the tree 40vh and the map 60vh.
3. ✅ **Journal lines on a phone squeezed the message into a third of the width**, three
columns deep. Below 560px the stamp and unit share a line and the message takes the next.
4. ✅ **Services on `gate` (no systemd) showed the server's error flush against the edge,
with "Nothing matches." under it** as if a filter had hidden them. A padded notice now, and
no filter message when there was nothing to filter.
5. ✅ **ZFS "Snapshot now" offered a name seven hours wrong.** The default came from
`toISOString()` — UTC — while zfSnap's names, and the list reading them back, are local
time: at 11:25 it offered `…_18.25.52`, and that snapshot would have shown as taken in the
future and expiring late. Built from local fields now.
6. ✅ **"Adopt as a schedule" always ticked Recursive** — `/\s-\w*r/.test(cmd) || true`.
7. ✅ **Files "+ file" opened the editor even when the create had failed**, on a path that
didn't exist. It opens only after the create succeeds.
8. ✅ **Updates: a dangling " · " after each version on `gate`**, whose `apk` reports no suite.
9. ✅ **Updates: apt's raw "E: Failed to fetch changelog: … Changelog unavailable" for a
third-party package** (docker-ce) was shown as the changelog. Said plainly now.
10. ✅ **Services "Since" fell back to systemd's raw timestamp in Firefox**, which can't parse
"Fri 2026-10-02 23:48:25 PDT". The fields are read directly now.
11. ✅ **Hardware on `gate` led with a separator** — "· 4 threads · up to 2.70 GHz" — when the
core count is unknown. The parts are joined, not concatenated.
12. ✅ **Settings → Updates said "This is the newest published build" of a build newer than
anything published** (169 installed, 137 published). It says so instead.
13. ✅ **Escape did not close the phone's drawer**, alone among the overlays.
14. ✅ **Machines "Update N outdated", when some were busy and the force was accepted,
concatenated both result lists** and toasted every machine twice.
## Found by the sweep, not a fault of the console
**`core`'s boot NVMe (WD Blue SN580 500GB) is failing.** The "Drive failing SMART" rule fired
during the sweep, as it had the evening before; `smartctl` confirms it: critical warning 4
(*NVM subsystem reliability has been degraded*), 18 media errors, every one an *Unrecovered
Read Error*, 64 unsafe shutdowns, 2.5 years powered on. The console did its job; the drive is
a `hamlet` matter (`docs/pending.md`).
## Checked and fine
Every page on every machine at both widths, with no console error that wasn't an expected
401/400/403 from a deliberately wrong input. Login lockout messages, the password eye. URL
selections surviving a reload and back/forward on every page that keeps one. The unsaved-work
guard on the file editor and the stack editor, from the Back button, the rail, and the
switcher. Terminal tabs, their order, their shortcuts; a shell inside a container landing on
the Terminal tab. The whole stack lifecycle, image pull and prune, container Limits. A guest
login kicked out at the moment of revocation. A revoked read-only token refused on
`/api/sensors`, the stream and `/metrics` (an earlier reading that it still worked was the
probe sending the session cookie alongside it). Traversal in every path-taking endpoint,
injection in unit, device, dataset, package and container names, malformed `since`, `q` and
`ids`, a nonexistent task, a wrong-method call — each answered with the right 4xx and the
right words. No session, no cookie: 401 on every API, locally and through NPM. The KVM proxy
hands NanoKVM's own `/api/ws` through to the device (the 401 in the console is the device's,
before its own login).
## Quality of life — to discuss, not built
1. **Treemap blank space.** Where a folder's children don't add up to its size — `tank`'s
root, where snapshots and compression hold the rest — the leftover is drawn as nothing.
An "unaccounted" tile would say what it is.
2. **Sessions pile up.** Every script, curl and headless browser that logs in leaves a row;
the hub had thirteen. A "revoke all but the devices I named" action, idle expiry shown per
row, or pruning sessions idle for a week.
3. **The Mac's GPU box takes half the Processes page** to say Asahi exposes no counters; a
GPU with nothing measurable could be one line.
4. **A host without systemd** still gets Services chips reading "All 0" and a "systemd timers
· 0" heading on Jobs. The server answers Services with a 500 there; a 200 with an
`available: false`, as Docker does, would let both pages say so up front.
5. **An alert whose sensor vanishes resolves silently.** If `smartctl` errors out, the
`smart.*.passed` sensor is omitted and a firing "Drive failing SMART" clears. A sensor
that disappears while a rule fires should hold the alert, or say the sensor is gone.
6. **Network "Past tests" rows are clipped** on desktop ("↓ 302 · ↑ 300 Mbps · 7.5 …") by the
four-column props grid.
7. **Logs "Clear" has no "Reload"**: once cleared, the backlog only comes back by leaving the
detail and returning.
8. **NanoKVM asks for its own login every time** inside the frame. Ham Lab could remember the
device's cookie per browser, or the hub could hold its credentials — a trade worth stating.
9. **Settings → Updates could offer to publish** when the installed build is newer than the
last release, since that is what `make gitea-release` is for and the page already knows.
10. **The compose editor is a plain textarea**: no line numbers, no YAML highlighting, and a
phone keyboard's autocorrect is off but its indentation is a fight.
11. **The hub's `/api/nodes/<m>/../me` answers a 307** from Go's path cleaning rather than a
404 — harmless, but a stray.
12. **Guest logins can open Users and Settings** — by design ("a guest can do everything you
can"), but worth a second look now that Users includes removing accounts.