Auth seeding (last-resort guard)
- `_seed_builtin_admin()` in get_db() now skips when
VACUUM_WALL_SEED_BUILTIN_ADMIN=0 or when the users table already
contains any user — previously a fresh service start after a non-default
bootstrap (e.g. --mgmt-user alice) seeded a hard-coded `admin` with an
unrecoverable random password, shadowing the operator's account
- bootstrap_auth.py sets VACUUM_WALL_SEED_BUILTIN_ADMIN=0: bootstrap
creates the operator user itself on a fresh install, so exactly one
account exists and no seeded admin can appear
Frontend (session recovery)
- on page load/restore the in-memory TTL timer is gone, so a valid
7-day refresh token could sit in sessionStorage while the access token
is already expired server-side: the session `check` now attempts
exactly one refresh (POST /api/auth/refresh with the stored refresh
token) on 401 before treating the session as dead
- extract shared `_doRefresh()` used by both the `check` 401 fallback and
the `refresh` action (removes the duplicated rotation logic)
Tests
- update seeding tests to the new any-user-present check; add
test_seed_skipped_when_users_exist, test_seed_skipped_via_env,
test_bootstrap_flow_creates_exactly_one_user, and the auth-model JS
test suite (tests/test-auth-model.js)
Docs
- AGENTS.md: document VACUUM_WALL_SEED_BUILTIN_ADMIN
- architecture.md / hoover.md / security.md: describe the bootstrap
check 401 → one-refresh fallback path