Commit graph

2 commits

Author SHA1 Message Date
screentinker 12c0004245
test(ci): OS-assigned ephemeral ports for subprocess suites — kill the port-collision flake (#176)
The subprocess-booting test suites hand-picked fixed ports in a cramped ~3955-4021 range, and
156-schedule-read-path deviated to a RANDOM port (3900 + rand%90) that overlapped those fixed
ports. Under CI load two servers could race on the same port, surfacing as flaky "no such table:
devices" / "FOREIGN KEY constraint failed" (a server answering a request against a half-migrated
or wrong DB). It's environmental — the suites pass locally and in isolation.

Fix: a shared test/helpers/free-port.js (bind :0 on loopback, read the OS-assigned port, release)
called in before() so every suite gets a guaranteed-unique ephemeral port — concurrent suites can
no longer collide, and no one has to hand-assign ports.

- Codemod converted 30 suites: const PORT = <fixed|random> -> let PORT (+ BASE) assigned via
  `PORT = await freePort()` at the top of before().
- 3 hand-fixed (different structure): 148-eviction-storm (lowercase `base`), boot-health (no
  before() — allocates PORT + a throwaway SEED_PORT inside the test, replacing the hardcoded
  3894), totp-keyrotation (no before() — allocates at the test start before bootServer()).

No fixed 39xx/40xx ports remain. Full server suite 435/435; the 4 hand-touched suites pass in
isolation. Pure test-infra change — no app code touched.
2026-07-13 09:51:40 -05:00
ScreenTinker 9418582de5 feat(#146): always-on devices_connected + admin-toggleable /api/status debug block
1. devices_connected (always on, never gated): a top-level /api/status field next to
   loop_lag = LIVE WS socket count from the heartbeat connection map (getConnectedCount),
   NOT devices.status='online' (which lags by the offline-timeout). The single
   most-glanced operational number, so it can't disappear when debug is off. Also dropped
   4 dead per-poll COUNT(*) queries the route computed but never returned.

2. debug block behind an admin flag: new minimal app_settings KV table (none existed;
   ai_settings is per-workspace, white_labels is branding) + lib/app-settings.js (cached,
   refresh-on-write so status polls read a cached boolean, not a DB row).
   routes/status.js includes `debug` ONLY when status_debug_enabled is on (persisted value
   overrides the STATUS_DEBUG_ENABLED env default); when off the key is omitted entirely.

3. Admin toggle: GET/PUT /api/admin/status-debug (requirePlatformAdmin, mirrors the
   branding endpoints) + a checkbox in the Admin tab "Status endpoint" section
   (mirrors the branding checkbox). Takes effect on the next poll, no restart.

Tests: devices_connected always present+numeric and rises with a live socket (booted +
socket.io-client); debug present by default, admin flips OFF -> key omitted (loop_lag +
devices_connected remain) -> ON again, no restart; non-admin 403, anon 401; unit coverage
for getConnectedCount + app-settings default/override. Suite 289/289.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 18:45:40 -05:00