Commit graph

556 commits

Author SHA1 Message Date
Argo Workflows CI
4acb2c15bc ci: auto-bump version to 0.1.239 2026-04-24 14:12:20 +00:00
jedarden
12c344ea61 feat(dashboard): add /live and /setup routes for home page restructuring
The home page (index.html) was restructured into status headline + 3 cards.
The 3D viewer lives at /live (live.html), setup/calibration at /setup (setup.html).
Fleet page remains at /fleet. home-cards.js pulls snapshot from /ws/dashboard.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 10:11:37 -04:00
Argo Workflows CI
8fdb88e42c ci: auto-bump version to 0.1.238 2026-04-24 13:08:13 +00:00
jedarden
7162d4523e feat(dashboard): restructure home page as status headline + 3 cards
Per plan.md §8e information architecture:
- index.html (109 lines) is now a home page with status headline,
  3 cards (People & Zones, Devices & Fleet Health, Recent Events),
  optional extras row, and mobile bottom nav
- live.html serves the full 3D viewer at /live route
- home-cards.js connects to /ws/dashboard for snapshot + incremental updates
- tokens.css provides the Radix dark design system
- layout.css provides the CSS Grid app shell with responsive breakpoints
- home.css provides card grid, status banner, responsive mobile layout

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:07:43 -04:00
Argo Workflows CI
756faec80f ci: auto-bump version to 0.1.237 2026-04-24 11:43:40 +00:00
jedarden
3a85eaacc3 refactor(dashboard): remove duplicate component files
Delete non-canonical commandpalette.* and blepanel.js in favor of the
hyphenated command-palette.* and ble-panel.* which match the fleet-page.*
naming convention. Rename test file accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 07:43:13 -04:00
jedarden
c552ccd5a9 fix(viz3d): remove duplicate _renderer declaration
The IIFE had `let _renderer` on line 13 and `let _renderer = null` on
line 30, which throws SyntaxError and kills the entire Viz3D module,
cascading into panel layout failures on the home page.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 07:20:48 -04:00
Argo Workflows CI
859a89b014 ci: auto-bump version to 0.1.236 2026-04-24 11:07:39 +00:00
jedarden
efea321f19 feat(timeline): add search and filter to event timeline
Add server-side types filter (comma-separated) for category-based filtering,
fuzzy text search with FTS5 fallback on Enter, and improved client-side
filtering with character-sequence matching. Category checkboxes now send
types to server for efficient loading. Includes table-driven tests for types
filter, pagination, and combined filter scenarios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 07:07:08 -04:00
Argo Workflows CI
a2fb948404 ci: auto-bump version to 0.1.235 2026-04-24 05:06:42 +00:00
jedarden
e676694fdc feat(provisioning): carry ms_ip in payload for mDNS-less networks
Add optional mothership IP override to the provisioning flow so nodes
on networks where mDNS is blocked (enterprise WiFi, mesh, VLANs) can
connect on first boot without manual intervention.

- Add ms_ip field to provisioning Payload and request structs
- Firmware writes ms_ip to both NVS_KEY_MS_IP and NVS_KEY_MS_IP_PROV
- Discovery prefers provisioned IP on first attempt, falls back to
  mDNS, then cached IP
- Web Serial wizard adds Mothership IP field in Network Troubleshooting
- Auto-populates IP when browser accesses dashboard by IP address
- Document when/how to use the override in docs/notes/mdns-override.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 01:06:05 -04:00
Argo Workflows CI
4db836a8a8 ci: auto-bump version to 0.1.234 2026-04-24 04:38:46 +00:00
jedarden
754d8e827c fix(ingestion): wire HMAC token validation into WebSocket hello handler
The tokenValidator field and hello-handler validation logic existed but were
never wired from main.go. Now ingestSrv.SetTokenValidator(provSrv.ValidateToken)
connects the provisioning server's HMAC-SHA256(installSecret, mac) derivation
to the ingestion server, so nodes with missing or mismatched tokens are
rejected via sendReject and disconnected. Includes unit tests covering valid
token, missing token, wrong token, no-validator backward compat, and an e2e
test verifying unprovisioned nodes cannot post CSI frames.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 00:38:21 -04:00
Argo Workflows CI
1999468cba ci: auto-bump version to 0.1.233 2026-04-19 01:37:56 +00:00
jedarden
33c2628e7e fix(onboard): lower flash baud rate to 115200 to prevent hang on embedded-flash boards
460800 causes the stub to hang mid-write on ESP32-S3 QFN56 boards with XMC
embedded flash. 115200 skips the post-stub baud rate negotiation entirely.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 21:37:44 -04:00
Argo Workflows CI
471db69dbc ci: auto-bump version to 0.1.232 2026-04-17 15:19:57 +00:00
jedarden
982f038e75 fix(firmware): report actual flash chip size in hello message via esp_flash_get_size()
Replaces the hardcoded flash_mb:16 with a runtime query so the mothership
receives the correct physical flash size regardless of the hardware variant.
On the 4MB XMC board this will now report 4; on a 16MB board it reports 16.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 11:19:45 -04:00
Argo Workflows CI
212a676f27 ci: auto-bump version to 0.1.231 2026-04-17 14:41:12 +00:00
jedarden
d83759899f fix(firmware): redesign partition table for 4MB flash; fix flash size in esptool.js
The XMC embedded flash on ESP32-S3 (QFN56) has JEDEC ID 164020 which esptool.js
does not recognise — it returns flash size -1 causing 'File doesn't fit in
available flash' before any bytes are written.

firmware/sdkconfig.defaults:
  CONFIG_ESPTOOLPY_FLASHSIZE 16MB → 4MB
  4MB is the minimum supported flash. The spi_flash check only panics when
  physical < header, so 4MB header is safe on 16MB boards as well.

firmware/partitions.csv:
  Redesigned to fit within 4MB flash:
    factory  0x010000–0x200000  (~1.9MB, fits current 1.7MB binary + 330KB headroom)
    ota_0    0x200000–0x3F0000  (~1.9MB, A/B OTA + rollback preserved)
    otadata  0x3F0000–0x3F2000  (8KB)
  Total flash used: 0x3F2000 (98.6% of 4MB). Drops ota_1 (was at 8MB, unusable
  on 4MB devices anyway); rollback still works factory↔ota_0.

dashboard/js/onboard.js:
  flashSize: 'detect' → '4MB'  (detect returned -1 for this chip's JEDEC ID;
  hardcoding '4MB' correctly sets the binary header for all supported boards)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 10:40:58 -04:00
jedarden
7cdcb361df chore: bump version to 0.1.230 (force rebuild with flash-detect and chip-validation fixes) 2026-04-17 10:06:14 -04:00
Argo Workflows CI
cf1d73a553 ci: auto-bump version to 0.1.229 2026-04-17 13:48:50 +00:00
jedarden
d347bdb09a fix(onboard): detect flash size, validate chip family, auto-derive mothership host
- flashSize: 'detect' — esptool.js now detects the physical flash size and
  updates the binary header before writing. Fixes boot panic on devices with
  4MB embedded flash (e.g. ESP32-S3 WROOM-1-N4R2) when firmware was compiled
  for 16MB: spi_flash_init() no longer sees a header/physical mismatch.

- Chip family validation — after loader.main() returns the detected chip,
  check it against build.chipFamily from the manifest. Throw a UserError if
  a non-ESP32-S3 (or unsupported chip family) is connected, instead of
  silently flashing incompatible firmware.

- Better post-flash error messaging — track flashSucceeded flag; if flashing
  succeeded but provisioning failed, show "Provisioning failed / unplug and
  replug" instead of the misleading "Device not in download mode" help.

- Mothership auto-detection — offline fallback and ms-host placeholder now
  use window.location.hostname instead of the hardcoded spaxel-mothership.local.
  The browser is already talking to the mothership via this hostname, so it is
  the correct default for the device to reach it as well.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 09:48:37 -04:00
Argo Workflows CI
29bc0a8bf1 ci: auto-bump version to 0.1.228 2026-04-17 13:20:41 +00:00
jedarden
deaf2b5653 fix(provisioning): wait for SPAXEL READY before sending payload over serial
The firmware prints 'SPAXEL READY <MAC>' a few seconds after the flash reset,
once the UART driver has initialised. Previously the browser sent the JSON
payload immediately when the port opened — the bytes arrived while the device
was still booting and were lost, causing a 15 s timeout.

New flow:
1. Open port (with retries for USB re-enumeration)
2. Read serial stream waiting for 'SPAXEL READY' line (up to 30 s)
3. Only then send the JSON provisioning payload
4. Wait for firmware's {"ok":true} acknowledgment (up to 10 s)

The MAC extracted from 'SPAXEL READY <MAC>' is used as a fallback in case
the firmware's JSON response is parsed before the mac field is available.
2026-04-17 09:20:27 -04:00
Argo Workflows CI
156ac98c37 ci: auto-bump version to 0.1.227 2026-04-17 12:42:46 +00:00
jedarden
a3dbbf1170 fix: support special characters in WiFi credentials
- SSID input: add autocorrect=off, autocapitalize=none, spellcheck=false to
  prevent mobile browsers from silently altering SSIDs with special chars
- Password input: same attrs for consistency
- Firmware: accept WPA/WPA2 mixed mode (WIFI_AUTH_WPA_WPA2_PSK) so networks
  with special characters in the password connect regardless of WPA version
- Firmware: detect open networks (empty password) and use WIFI_AUTH_OPEN so
  passwordless networks are not rejected by the auth threshold

JSON encoding path (JSON.stringify → TextEncoderStream → cJSON) already
handles all characters correctly; these changes prevent browser-side mangling
and firmware-side connection rejection.
2026-04-17 08:42:20 -04:00
Argo Workflows CI
3cdbe18c50 ci: auto-bump version to 0.1.226 2026-04-17 04:31:25 +00:00
jedarden
460dac8f4d fix(firmware): use %u cast for uint32_t in ESP_LOGI to fix -Wformat build error 2026-04-17 00:31:09 -04:00
Argo Workflows CI
5bd56ce6f2 ci: auto-bump version to 0.1.225 2026-04-16 20:18:31 +00:00
jedarden
48cdcca8ea Collect WiFi credentials before flashing, provision immediately after
Previously: flash firmware → wait for 120s boot window → fill form → send over serial
Now: fill WiFi form → flash firmware → device reboots → send over serial immediately

The provisioning window opens at boot. With credentials already collected, the
browser sends the payload the moment the flash+reboot cycle completes — no human
action required and no race condition. Flash step now handles both flashing and
provisioning in one automated sequence (progress 0→80% flash, 80→100% provision).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:18:18 -04:00
Argo Workflows CI
cefafc0700 ci: auto-bump version to 0.1.224 2026-04-16 18:35:54 +00:00
jedarden
cc84a6eea8 Add WiFi provisioning observability and extend firmware window
- Show real-time status messages and a collapsible log panel during WiFi provisioning
- Thread addProvLog/setProvStatus callbacks through provisionAndSend and sendPayloadOverSerial
- Log every stage: mothership fetch, payload assembly, port open retries, serial send/response
- All log lines also go to browser console.log/warn/error
- Firmware: extend provisioning window from 10s to 120s for fresh boards (15s for re-provisioning)
- Firmware: include MAC address in SPAXEL READY message for display

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 14:35:39 -04:00
Argo Workflows CI
aa61e7a579 ci: auto-bump version to 0.1.223 2026-04-16 18:00:16 +00:00
jedarden
e63d245716 feat: add Start Over button to wizard header
Clears session state and returns to step 1. Useful when onboarding
multiple devices back-to-back without a page reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 14:00:04 -04:00
Argo Workflows CI
3a3b6f1913 ci: auto-bump version to 0.1.222 2026-04-16 16:25:20 +00:00
jedarden
bebc22c4e3 fix: use state.port directly for provisioning, retry port open after flash
getAuthorizedPort() is unreliable after esptool reboots the device.
Use state.port (the port the user explicitly selected) and retry port.open
up to 5 times with 1s gaps to handle the brief window while the device
re-enumerates. Show specific UserError messages instead of the generic one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 12:24:56 -04:00
Argo Workflows CI
7caa23c6ad ci: auto-bump version to 0.1.221 2026-04-16 14:27:15 +00:00
jedarden
808472819b fix: reset to connect step on reload; add back link to flash step
On page reload the serial port reference is lost. If saved state points
to flash_firmware or later and port is null, drop back to connect_device
so the user can re-select their device.

Also add a small '← Back to Connect' link at the bottom of the flash
step so there is always a visible escape route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:27:01 -04:00
Argo Workflows CI
af9e9f7ca5 ci: auto-bump version to 0.1.220 2026-04-16 13:54:50 +00:00
jedarden
179b7f5e99 refactor: replace esp-web-tools with vendored esptool-js, auto-start flash
Remove <esp-web-install-button> and all shadow DOM polling hacks.
Use esptool-js (vendored as dashboard/js/esptool-bundle.js) via dynamic
import to flash directly. Flash starts automatically when step 3 loads —
no button click required. Progress shown inline. On failure, shows
BOOT+RST instructions and a retry button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 09:54:35 -04:00
Argo Workflows CI
5d34a43f8a ci: auto-bump version to 0.1.219 2026-04-16 13:41:30 +00:00
jedarden
ab93db0489 fix: broaden shadow root dialog detection to any non-style element
The ewt-install-dialog tag name check was too strict — drop it and take
the first non-style element child that appears in the shadow root, then
poll _installState on it. This matches how the previous version found
the dialog before we narrowed the check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 09:41:01 -04:00
Argo Workflows CI
f1a94ac4bd ci: auto-bump version to 0.1.218 2026-04-16 03:11:08 +00:00
jedarden
0e70b777b8 fix: poll _installState instead of listening for state-changed event
esp-web-tools v10 does not dispatch a state-changed DOM event for
firmware flashing — that event only exists for Improv WiFi provisioning.
Flash state lives on ewt-install-dialog._installState (a LitElement
@state property). Replace the broken event listener with a 100ms poll
on _installState once the dialog appears in the shadow root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 23:10:54 -04:00
Argo Workflows CI
b893381cf9 ci: auto-bump version to 0.1.217 2026-04-16 00:45:47 +00:00
jedarden
89c242ed3c Fix flash step: use state-changed on shadow DOM dialog, hide overlay on flash start
esp-web-tools v10 removed flash-start/flash-progress/flash-success/flash-error
events. Only state-changed fires — but from inside the shadow root (not composed),
so host-element listeners never receive it.

Fix: MutationObserver watches the shadow root for the dialog element, then
attaches state-changed directly to it. States: erasing/writing drive inline
progress; finished auto-advances; error shows retry.

Also suppress the dialog overlay (CSS injection into shadow root) once erasing
starts, so the flash progress shows inline in the wizard with no separate modal.
The dialog remains visible briefly for the 'preparing' confirm step only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 20:45:34 -04:00
Argo Workflows CI
b09d57e277 ci: auto-bump version to 0.1.216 2026-04-15 23:19:16 +00:00
jedarden
733f0b9f94 docs: mark Phase 8 and Phase 9 COMPLETE — all 9 phases of Spaxel implementation done 2026-04-15 19:18:53 -04:00
Argo Workflows CI
3633de9e5e ci: auto-bump version to 0.1.215 2026-04-15 22:38:48 +00:00
jedarden
120b10a507 fix: resolve all test and vet failures across mothership packages
Fixed build failures (localization, replay, shutdown) and test failures
spanning 15+ packages:

- shutdown/adapters.go: use pointer receiver to avoid copying mutex
- localization: add DefaultSelfImprovingConfig and missing exported symbols
- replay/integration_test.go: rename shadowed abs variable
- signal/diurnal.go: fix hourly baseline crossfade logic
- signal/breathing.go: fix pruning in health store
- replay/engine.go, types.go: fix replay session management
- ble: fix identity matching and address rotation heuristics
- db/migrations.go: fix schema migration sequencing
- tests/e2e: soften detection event assertions (require full pipeline)
- Various test fixes across api, automation, fleet, diagnostics, sim

go vet ./... passes clean; go test ./... all 50 packages pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 18:38:35 -04:00