The updater endpoint pointed at mca/parking_solution's own Gitea "latest
release" redirect, but that repo is private and field appliances have no
Gitea credentials — every update check was silently failing. release.yml
now mirrors signed installers to mca/public_releases (public, installers
only) under a fixed desktop-latest tag; tauri.conf.json points there.
Rejected embedding a read token in the app instead, given the booth-operator
threat model.
Also: make the appliance-provisioning root_directory gotcha impossible to
skim past (boxed callout + explicit next-step pointers), after it caused a
second missed step on the park-2 install.
park-lab-old referenced a server removed from Komodo, breaking the resource
sync. Also documents two Periphery incidents from this session: a Core-UI
rename doesn't touch the agent's own connect_as, and upgrading Periphery is
a config-preserving re-run of the installer.
Lab box (park-test) crash-looped: panic writing the agent key to
/etc/komodo/keys/periphery.key (Permission denied). Gotcha #9 was framed
as a hand-config hazard; v2.2.0's installer now writes the system-style
default even with --user. §7a: verify root_directory after every
install + sed fix + reset-failed/restart; user-unit vs sudo note; the
onboarding key survives a pre-connect crash.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
Demoting the operator on park-buzi failed with "sanitize_string: invalid
characters in 'park-operator'" — Ubuntu's perl adduser/deluser tooling
rejects the hyphenated username. §5c now prescribes gpasswd -d for
sudo/lxd/lpadmin (shadow-suite, no perl sanitize) and documents that
group removal lands at NEXT login: the auto-login operator session keeps
its old memberships until reboot/relog, so verify `groups` from inside
the session afterwards.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
Field failure on park-buzi: reset-db --users wipes the roles table and
points to seed-admin — which inserted the user with roleId "admin"
without recreating the role row (migration 0007 never re-runs), dying on
the role_id FOREIGN KEY. The script now upserts the built-in admin role
first (the row alone suffices — admin permissions resolve in code).
It also appends a SIGNED config_change (admin.passwordReset /
admin.seeded, operator console:seed-admin) via the server's compiled
EventLog + signer: a console seed/reset by the Linux admin can't be
gated by the app, but it stays attributable in the chain. Best-effort —
no build/signing key warns loudly and proceeds (locking an admin out to
protect an audit line would invert the priority). Both paths verified
against a scratch DB reproducing the post-reset state.
Runbook: appliance-provisioning §7e — lost app-admin password reset via
FORCE=1 (interactive preferred; sessions not revoked → rotate JWT_SECRET
if theft suspected); §7d notes the FK failure + self-heal.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
- entry-exit-points.md: the snapshot content-type bug + serve-side cleanType
fix (Hikvision image/jpeg; charset="UTF-8" broke every legacy render).
- booth-exit-flow.md: the Active-Sessions/modal rework — inline barrier button
removed -> modal; closed-within-grace view; live grace countdown; actual paid
amount; read-only snapshot review in the closed-session view.
- local-dev-workflow.md: the gated `pnpm db:reset` training tool + flag table +
the booth (docker exec, no pnpm) note.
- appliance-provisioning.md: new §7d — reset on the booth via docker exec into
the server container (script ships in the deploy bundle; DATABASE_URL=
/data/parking.sqlite), ledger-truncation warning + the two safety gates.
- index.md catalog line; log.md entries.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
New wiki/decisions/appliance-provisioning.md: the hardware-verified step-by-step for
provisioning a booth PC (Dell OptiPlex 7070, i5-8500, discrete Nuvoton TPM 2.0) from
factory Windows to a hardened Ubuntu 26.04 LTS appliance. Every command was run on the
first real unit (2026-06-23). Captures the firmware-specific gotchas: Ventoy → 0x1A under
Secure Boot (flash ISO directly); the 7070 BIOS can't view db (verify via live USB); the
installer's hardware-backed encryption fails with PCR_UNUSABLE/dbt (use passphrase LUKS +
manual systemd-cryptenroll PCR-7 seal); GRUB password must be edit-only (--unrestricted)
to keep unattended boot.
OS hardening on unit 1 is COMPLETE + verified: LUKS FDE + TPM auto-unlock (PCR 7,
unattended) + Secure Boot (Deployed) + GRUB edit-lock (closes the init=/bin/bash root-shell
hole that PCR-7 sealing does not cover). Resolves the implementation half of
open-questions #12 for unit 1.
Cross-linked from disk-os-hardening; index + log updated. Still TODO on the box: Docker +
run the stack.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V