Fresh re-dispatch against the running strict-window mothership
(SPAXEL_MIGRATION_WINDOW_HOURS=0). Rebuilt sim from repo-root go.work,
ran the exact documented command for 30 s: 4 nodes connected, 0 REJECT,
Average FPS 240.0, /healthz nodes_online:4 with all rows online. All four
bf-3hji acceptance criteria met. Records the exact run command.
Co-Authored-By: Claude <noreply@anthropic.com>
Independently re-ran the exact documented command against a fresh strict-window
mothership (SPAXEL_MIGRATION_WINDOW_HOURS=0, clean mktemp data dir) with both
binaries built from source (repo-root cmd/sim, not the stale in-module sim):
/tmp/spaxel-sim --mothership ws://localhost:8080/ws/node \
--nodes 4 --walkers 1 --rate 20 --duration 30 --ble --seed 42
All 4 acceptance criteria hold: 4 nodes connect (4x [SIM] connected + 4x
mothership [INFO] Node connected, sim exits 0); 0 REJECT/401/403/invalid_token in
either log; frames/s=240.0 (Frames sent 7200 = 12 node-pairs x 20 Hz); /api/nodes
returns 4 rows all online (zero went_offline_at) at real perimeter positions,
/healthz nodes_online:4. Exact command + evidence recorded in the bead body
(comment) and PROGRESS.md.
go vet ./... clean; all non-e2e unit tests pass. blobs=0 is correctly out of scope
(next chain link, fusion SetNodePosition wiring bf-4q5w / IO-6 hard-gate); the
pre-existing tests/e2e sim-binary-trap RED state is also out of scope (bf-4q5w).
Co-Authored-By: Claude <noreply@anthropic.com>
Independently re-verified the last acceptance gate for the chain and parent
bf-3hji. Against a fresh strict-window mothership (SPAXEL_MIGRATION_WINDOW_HOURS=0,
clean mktemp data dir) with spaxel-sim --nodes 4 --walkers 1 --rate 20
--duration 30 --ble --seed 42 (both binaries built from source):
- GET /api/nodes mid-run returns 4 rows (4 sim MACs), each with a zero
went_offline_at (online); /healthz reports nodes_online:4.
- All 4 last_seen_at within ~9s of the probe-time now (<30s => online per the
e2e GetNodes definition, e2e_test.go:241).
- Provisioning path live: 4x POST /api/provision -> 200, 4x Node connected,
0 reject/invalid_token/401/403 in either log, Frames sent: 7200.
go vet ./... clean; go build ./... clean; all non-e2e unit tests pass.
mothership/tests/e2e remains RED at HEAD from a pre-existing sim-binary
mismatch (documented in PROGRESS.md), not introduced by this bead.
Co-Authored-By: Claude <noreply@anthropic.com>
Independently re-ran the documented command against a fresh bf-3zll healthy
mothership: 4 nodes connect (mothership nodes_online=4), 0 REJECT in both logs,
Frames sent 7200 / Average FPS 240.0 over 30s. Reproduces bf-3hji's result; the
exact command and evidence are recorded under the existing "Hardware-Free
Simulator → CSI Streaming" PROGRESS.md section. blobs=0 stays out of scope
(next chain link, bf-4q5w / IO-6).
Co-Authored-By: Claude <noreply@anthropic.com>
Records the bf-4iewr verification of the hardware-free mothership's token
path. The fixes are already at HEAD (bf-1o7qi header bridge + bf-4mle6 real
token provisioning); this commit documents the definitive runtime proof:
- Positive (default --provision, SPAXEL_MIGRATION_WINDOW_HOURS=0): 2 nodes
provision real HMAC tokens, connect, stream CSI at ~40 fps; ZERO
reject/invalid_token/401/403 in mothership stderr.
- Negative control (--token bogus): the strict-window mothership rejects the
bogus-token node ("invalid token") and the sim exits on reject — proving the
validator is live and enforcing, so legitimate nodes connect on real tokens,
not because auth was disabled.
Both acceptance criteria of bf-4iewr hold. Doc-only; go vet ./... clean and
go test ./internal/... green (e2e package is the unrelated bf-4q5w blob gate,
out of scope here).
Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-4iewr
spaxel-sim now mints a real per-node HMAC token via POST /api/provision
(--provision, default true), presented as X-Spaxel-Token and validated
server-side regardless of the migration window. This makes the
hardware-free build's acceptance durable and window-independent: the sim
connects and streams identically under SPAXEL_MIGRATION_WINDOW_HOURS=0,
24, or larger.
- cmd/sim/main.go: --provision (default) / --provision=false (legacy
window-dependent dummy) / --token <t> (verbatim override);
resolveTokens() + provisionNodeToken().
- PROGRESS.md: document the window-independent auth policy with the exact
human-run command (window=0 + --provision), and supersede the bf-2hdbg
"24h-window mask, not a fix" conclusion (RESOLVED by the bf-1o7qi
header bridge + this provisioning change; historical text preserved).
Verified: go build/vet ./cmd/sim clean. Window-independent acceptance is
proven by the e2e harness under SPAXEL_MIGRATION_WINDOW_HOURS=0
(bf-qzrmq, 250056c) and the hello.Token validation bridge (bf-1o7qi,
9c38cbb) — both already committed.
The bf-4q5w IO-6 hard-gate harness code in
mothership/tests/e2e/e2e_test.go is intentionally NOT included here; it
belongs to the still-open bf-4q5w.
Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-42cao
Third link of the bf-34lwt split. Pins down that the bf-3hji 'no REJECT,
sim nodes accepted' state is a side effect of the default 24h migration
window a fresh boot opens — not a token/auth fix. Tokens never enter the
admission decision: sim nodes are tokenless where checked (hello.Token
body field is empty; the X-Spaxel-Token header they set is unread per
bf-29wyl). The sole acceptor is the migration deadline.
Verified against current source:
- config.go:139 MigrationWindowHours defaults to 24 (config.go:43 field
comment '0 = disabled'); main.go:4495-4497 installs deadline=now+24h
only when >0, so a fresh boot opens the window.
- server.go:510-518 acceptance branch gates on server.go:515
!deadline.IsZero() && time.Now().Before(deadline) — tokenOK is
irrelevant here; tokenless node admitted as Unpaired.
- server.go:519-526 reject branch (else of 515) hits server.go:525
sendReject(conn,"invalid_token") + conn.Close(); sendReject writes
{"type":"reject","reason":"invalid_token"} (server.go:841-845).
Conclusion: 'no reject' is a 24h-window MASK. REJECT returns when
SPAXEL_MIGRATION_WINDOW_HOURS=0 (deadline never set -> IsZero() ->
reject) or uptime > 24h (Before(deadline) false -> reject). Real fix is
on the token/supply side, not the window.
Carries the adjacent bf-3hji section it builds on ('the bf-3hji no-reject
finding above'), also uncommitted docs. No Go code touched; build + unit
tests + go vet clean.
Co-Authored-By: Claude <noreply@anthropic.com>
Verified the mothership builds from a clean checkout (mothership/ module root,
plain 'go build', no -tags=embed needed locally) and boots to /healthz with
no ESP32 hardware, reaching status=ok in ~230ms with no panic/crash in stderr.
Records the exact commands for the next child in the bf-40hc chain; canonical
path is TestHarness.Start in mothership/tests/e2e/e2e_test.go.
Co-Authored-By: Claude <noreply@anthropic.com>
Both are implemented (mothership/internal/recording/buffer.go and
mothership/internal/ingestion/ratecontrol.go). Phase 2 is now complete.
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 2 table showed "Dashboard presence indicator" as Pending, but it
is implemented in dashboard/live.html and dashboard/js/app.js
(updatePresenceIndicator, #presence-indicator styling). Update the
table row to Done and drop it from the "Remaining for Phase 2" list.
Co-Authored-By: Claude <noreply@anthropic.com>
Document the complete presence prediction system implementation
for Home Assistant integration with:
- Per-person transition probability tracking with Laplace smoothing
- Per-zone occupancy patterns from historical data
- Time-slot based predictions via Monte Carlo simulation
- HA sensor exposure with auto-discovery (3 sensors per person)
- Accuracy tracking targeting >75% at 15-minute horizon
All acceptance criteria for presence prediction have been met.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Static HTML/JS dashboard served by mothership at /
- Three.js 3D scene with ground grid, OrbitControls (pan/zoom/rotate)
- WebSocket connection at /ws/dashboard for real-time CSI streaming
- Binary CSI frame parsing (24-byte header + I/Q payload)
- Amplitude bar chart (64 subcarriers) as 2D Canvas overlay
- Node/link panels with live status and click-to-select
- Dashboard Go package with Hub for client broadcasting
- Ingestion server broadcasts CSI frames and node events to dashboard
- 5 new tests for dashboard hub operations
Complete: 3D scene, WebSocket, amplitude chart, node/link panels
Remaining: Docker packaging (Phase 1 final item)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>