Commit graph

953 commits

Author SHA1 Message Date
jedarden
ca7a0f21f3 fix(bf-4qto): propagate canonical identity fields through all blob projections
The three canonical identity fields (PersonName, AssignedColor,
IdentityResolved) had been added to every identity-bearing blob type
(bf-5151/bf-2ibc/bf-5v3q/bf-3wkz) but three projection sites in the
fusion loop were silently dropping them when converting the source
sigproc.TrackedBlob:

  - explainability.BlobSnapshot  (cmd/mothership/main.go)
  - automation.TrackedBlob       (cmd/mothership/main.go)
  - volume.BlobPos               (cmd/mothership/main.go)

The api.Track (tracks.go) and dashboard.blobJSON (hub.go) projections
already propagated them, so this left default-handling inconsistent
across projection contexts. Propagate the three fields from the source
blob at all three sites so the canonical fields flow through every
projection instead of being zeroed.

The fields stay at their Go zero values for existing blobs (identity is
not yet resolved at the signal layer): empty strings and a nil *bool all
carry omitempty, so they serialize as omitted (undefined in JS), which is
the consistent default the acceptance criteria require. The BLE identity
sidecar that actually populates them is a separate follow-up bead.

Also add the companion serialization-consistency suites that were missing
for the four types whose fields landed across the split beads:
tracker.Blob, tracking.Blob, volume.BlobPos, explainability.BlobSnapshot.
Each asserts the three task-required properties: zero-value blobs omit
all three fields (undefined), a resolved identity emits the camelCase
keys matching dashboard/types/spaxel.d.ts, and the *bool tri-state
(nil=omitted, &true=emitted, &false still emits identityResolved:false).

Verified: gofmt clean, go vet ./... clean, go test ./... passes
(incl. the four new suites and the existing api/automation/signal ones).

Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-4qto
2026-07-06 19:12:57 -04:00
jedarden
d0ac1b27b0 test(bf-5151): guard canonical identity-field serialization on blob types
Add table-driven serialization tests for the three bf-5151 canonical
identity fields (PersonName/AssignedColor/IdentityResolved) on the
tracked-blob types whose fields were added in a612584 + 01a415d and
propagated through the JSON projections:

  - internal/signal/identity_fields_test.go      -> signal.TrackedBlob
    (the canonical type /api/blobs serializes; api.TrackedBlob aliases it)
  - internal/automation/identity_fields_test.go  -> automation.TrackedBlob
    (Tier-1 #1 type that previously carried NO identity fields)
  - internal/api/tracks_identity_test.go         -> api.Track via the real
    GET /api/tracks handler, asserting propagation from signal.TrackedBlob

Each suite asserts the three task-required properties:
  1. zero-value blobs omit all three fields (omitempty -> undefined in JS),
     satisfying "fields set to undefined for existing blobs";
  2. a resolved identity emits the camelCase keys matching
     dashboard/types/spaxel.d.ts;
  3. the *bool tri-state: nil=omitted, &true=emitted, &false still emits
     "identityResolved":false (resolution attempted, failed).

Verified: gofmt clean, go vet ./... clean, go test ./... passes
(50 packages ok, including the 3 new suites).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 18:44:12 -04:00
jedarden
1871a8a42c docs(bf-1mwy): correct coverage-gate HEAD ref to real ancestor 908adf2
The committed bf-1mwy coverage gate (7f697a3) cited HEAD `37d628e`, a
pre-rebase dangling SHA not in history (the same class of stale-hash error
the doc's own §6 warns about for 1446ccf/248d0e0). Re-verified at the real
code HEAD `908adf2` (confirmed ancestor of HEAD): both inventory greps
return the documented 5 + 15 hits, all 8 in-scope blob types carry the
three canonical identity fields, and gofmt/vet/test are green.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 18:24:50 -04:00
jedarden
7f697a388d docs(bf-1mwy): coverage gate proving every blob-creation site accounted for
Re-run the bf-1q3m §1.1 inventory greps at HEAD 37d628e and map every
production blob-creation site (5 primary + 16 projection = 21) to either
"has the 3 canonical identity fields" or "out-of-scope with explicit
reason" in notes/bf-5151-coverage.md. This is the coverage gate closing
bf-5151's "No blob creation code is missed" acceptance criterion.

All 8 in-scope types confirmed carrying PersonName/AssignedColor/
IdentityResolved at zero values: signal.TrackedBlob, tracker.Blob,
tracking.Blob, automation.TrackedBlob, api.Track, dashboard.blobJSON,
explainability.BlobSnapshot, volume.BlobPos. All 15 out-of-scope sites
enumerated by reason (pre-identity peak C1; synthetic replay/sim P8-P10;
anon falldetect input P3; lifecycle events P11/P12; trigger-state
volume.BlobState P13-P16; rendering fallbacks P4-P6; distinct-name
falldetect.BlobSnapshot P7; dead api.BlobPos) -- none silently dropped.

Also notes the task-cited SHAs 1446ccf/248d0e0 are pre-rebase dangling
commits superseded by a612584/01a415d in HEAD.

gofmt/vet/test gate: 7 files carried pre-existing gofmt drift unrelated
to the identity work (verified unmodified by this bead before the format
pass); fixed mechanically with gofmt -w to satisfy the clean-gate
requirement. gofmt -l empty, go vet ./... exit 0, go test ./... all ok.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 18:15:22 -04:00
jedarden
908adf2049 docs(bf-3wkz): record independent re-verification of dashboard identity surface
Second pass (retry) re-confirmed all 8 Go types emit the canonical camelCase trio
(personName/assignedColor/identityResolved), state.js:288-294 surfaces server identity
via Object.assign, websocket.js dead-reckoning cache is identity-free by design.
go vet + go test green. No source change needed.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 17:58:29 -04:00
jedarden
730956411c fix(bf-3wkz): align volume.BlobPos identity JSON tags with dashboard camelCase
volume.BlobPos was the sole outlier carrying the canonical identity trio
(personName/assignedColor/identityResolved) under snake_case JSON tags
(person_name/assigned_color/identity_resolved); the other 7 blob-shaped
types and dashboard/types/spaxel.d.ts all use camelCase (bf-5151).

The tags were inert today (volume.BlobPos is consumed in Go by
Store.Evaluate, which returns fired-trigger IDs; it is never
JSON-marshalled to the dashboard), but would leak snake_case keys
inconsistent with the TS interface the moment it is ever surfaced.
Aligning removes the latent drift.

Verified (Tier-4 dashboard track of notes/bf-1q3m-consolidated.md §6):
- spaxel.d.ts Blob interface declares personName/assignedColor/
  identityResolved (+ deprecated personLabel/personColor aliases)
- dashboard.blobJSON, api.Track, explainability.BlobSnapshot already match
- state.js:290 surfaces server identity via Object.assign (no change needed)
- websocket.js:167 dead-reckoning cache is intentionally identity-free
Cross-check documented in notes/bf-3wkz-dashboard-identity-surface.md.
go vet ./... and go test ./... both pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 17:52:34 -04:00
jedarden
29a114c961 feat(bf-5v3q): add identity fields to volume.BlobPos type
Add the three canonical identity fields — PersonName, AssignedColor,
IdentityResolved — to volume.BlobPos (the Tier-1 #3 type gap from the
bf-1q3m/bf-5cgc handoff). BlobPos is the trigger-evaluation blob type
constructed at cmd/mothership/main.go:2326; it carried only PersonID.

Mirrors commit 1446ccf (bf-5151), which added the same three fields to
the four dashboard-facing tracked-blob types — but here the JSON tags
are snake_case (person_name, assigned_color, identity_resolved) matching
the volume package's internal convention, versus 1446ccf's camelCase
keys that mirror the dashboard Blob TS interface.

Per the task scope, the fields are DECLARATIONS ONLY: left at zero values
(empty strings, nil *bool) with omitempty, so they serialize as omitted
(undefined in JS). The production literal at main.go:2326 needs no change
— Go zero values handle it. A separate downstream bead populates them
from identityMatcher.GetMatch(blob.ID); that one-line populate is out of
scope here.

Verified: gofmt clean, go vet ./... clean, go test ./... passes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 17:42:33 -04:00
jedarden
c3f4b0dd4a feat(bf-2ibc): add identity fields to explainability.BlobSnapshot
Add the three canonical identity fields — PersonName, AssignedColor,
IdentityResolved — to explainability.BlobSnapshot (handler.go), the only
tracked-blob view that still lacked them (Tier-1 #2 type gap from the
bf-1q3m/bf-5cgc handoff).

The camelCase JSON keys (personName, assignedColor, identityResolved) and the
*bool tri-state choice mirror exactly how commit 1446ccf added them to
signal.TrackedBlob / tracker.Blob / tracking.Blob / automation.TrackedBlob, and
match the dashboard Blob type in dashboard/types/spaxel.d.ts.

Per scope, the fields are DECLARATIONS ONLY: the production creation literal at
mothership/cmd/mothership/main.go:2206 (and the handler_test.go literals) set
only {ID,X,Y,Z,Confidence}, so the new fields stay at zero values — empty
strings and a nil *bool all carry omitempty and serialize as omitted (undefined
in JS). Populating them from the ble.IdentityMatcher sidecar and folding in the
parallel identityMap (main.go:2216) is a separate downstream bead.

Verified: gofmt clean, go vet ./... clean, go build ./... clean,
go test ./... passes.

Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-2ibc
2026-07-06 17:37:06 -04:00
jedarden
01a415dd5c feat(bf-5151): propagate canonical identity fields to blob JSON projections
Complete the identity-field surface started by 1446ccf (which added
PersonName/AssignedColor/IdentityResolved to the four primary tracked-blob
structs). Add the same three canonical fields to the two struct types that
serialize tracked blobs for external consumers, and propagate them from the
source structs:

  - api.Track (internal/api/tracks.go)        -> /api/tracks JSON; sourced
                                                 from signal.TrackedBlob in
                                                 listTracks
  - dashboard.blobJSON (internal/dashboard/hub.go) -> /ws/dashboard feed;
                                                 sourced from tracking.Blob in
                                                 BroadcastLocUpdate

/api/blobs needs no change: it serializes signal.TrackedBlob directly
(pm.GetTrackedBlobs), which gained the fields in 1446ccf.

Per the task scope the fields are left at their zero values for existing
blobs (empty strings + nil *bool, all omitempty -> undefined in JS). A
follow-up bead wires the BLE identity sidecar to populate them. The
camelCase keys match the dashboard Blob interface in
dashboard/types/spaxel.d.ts.

The Tier-1 leak-fix targets from bf-1q3m (explainability.BlobSnapshot,
volume.BlobPos) are intentionally untouched: their identity flows via a
separate mechanism (the identityMap BLEMatch side-channel / PersonID), and
adding blob-struct identity fields there is step (a) of a cohesive
add+populate+fold fix that belongs to the follow-up bead (bf-1q3m §6),
not this fields-as-undefined bead.

Verified: gofmt clean, go vet ./... clean, go test ./... passes (api,
dashboard, signal, tracker, tracking, automation re-run with -count=1).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 17:37:06 -04:00
jedarden
a612584841 feat(bf-5151): add canonical identity fields to blob creation types
Add the three new canonical identity fields — PersonName, AssignedColor,
IdentityResolved — to the four primary tracked-blob struct types that are
constructed at the blob-creation sites catalogued in bf-1q3m:

  - signal.TrackedBlob   (internal/signal/processor.go)   — canonical type;
                                                            api.TrackedBlob is
                                                            a type alias of it
  - tracker.Blob (3D)    (internal/tracker/tracker.go)
  - tracking.Blob (2D)   (internal/tracking/tracker.go)
  - automation.TrackedBlob (internal/automation/engine.go)

The camelCase JSON keys (personName, assignedColor, identityResolved) match
the dashboard Blob interface in dashboard/types/spaxel.d.ts, which viz3d.js
reads directly. The legacy snake_case PersonLabel/PersonColor fields are
retained as deprecated aliases for backward compatibility.

Per the task, the fields are left at their zero values for existing blobs:
empty strings and a nil *bool all carry omitempty, so they serialize as
omitted (undefined in JS). A follow-up bead populates them from the BLE
identity sidecar. IdentityResolved is *bool to faithfully represent the
tri-state semantics (nil=unattempted, &true=resolved, &false=failed).

fusion.Blob is intentionally untouched: it is the pre-identity Fresnel peak
type ({X,Y,Z,Confidence} only) and is out of scope for identity per bf-1q3m.

Verified: gofmt clean, go vet ./... clean, go test ./... passes; marshaling
check confirms zero-value blobs omit the fields (undefined) while set blobs
emit the camelCase keys.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 17:37:06 -04:00
jedarden
a1e76e0c8d docs(bf-4bhd): re-verify blob-creation inventory current at HEAD 63f0c87
bf-4bhd ("Find all blob creation code paths") was auto-re-dispatched after
the task was already fully delivered by the closed chain
(bf-1q3m -> bf-1m2x -> bf-5cgc). This re-dispatch confirms currency rather
than re-doing discovery (the documented anti-pattern).

Empirical greps at HEAD 63f0c87 match the consolidated report exactly:
5 primary literals, 15 non-test projection literals, 15 blob types
(14 structs + 1 alias), 2 JS production sites. Zero Go/JS/firmware source
drift across f144aad..HEAD (every commit since is docs/.beads only).

New finding: SHA provenance correction. The prior notes cite unreachable
dangling SHAs (1a26c12 is actually bf-1bmg, not bf-1q3m; 0ae0c03 is an
amended-away copy of the bf-1q3m commit, real one is f144aad) because
history was rewritten after those notes were written. Inventory is
unaffected; mapped to real reachable SHAs so a future agent doesn't trust
dead citations.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:50:22 -04:00
jedarden
21c702f461 docs(bf-5c): checkpoint closed state of bf-5cgc in issues.jsonl
Re-flush after br close: bf-5cgc is now closed, summary recorded as
comment 91. No source change.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:42:14 -04:00
jedarden
e27fafe320 docs(bf-5cgc): hand off blob-creation inventory to identity-field beads
Formalize notes/bf-1q3m-consolidated.md §6 (tiered fix-target list) into a
tracked site→fix→bead deliverable (notes/bf-5cgc-handoff.md):

- automation  main.go:2303 + engine.go:1337  → bf-5151 / bf-64h5
- explainability main.go:2206 + handler.go:95 (fold identityMap :2216) → bf-5151
- volume      main.go:2326 + shape.go:1080    → bf-5151 (one-line PersonID)

All three mirror the reference population pattern analytics.TrackUpdate
(main.go:2267-2271): pull PersonID via identityMatcher.GetMatch(b.ID).
Sites re-verified exact at HEAD 1ecc999. Includes Tier-2/3/out-of-scope
(tracker wiring decision, E1 no-op, dead api.BlobPos) and a scope note
flagging the Go-backend vs TS-framing mismatch on the sibling beads.

Comments posted on bf-5151, bf-64h5, bf-1wvm, bf-iner, bf-4bhd. Closes
bf-4bhd's "Report is ready for the next bead to use" criterion.

Docs/.beads only — zero Go/JS source changed; go vet ./... passes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:40:27 -04:00
jedarden
1ecc9992d1 docs(bf-5ywk): banner superseded blob-inventory notes, confirm bf-1q3m as sole source
bf-4bhd failed repeatedly because re-dispatched agents trust its stale
"Analysis Report" framing (no supersession marker on the file). Per
notes/bf-1q3m-consolidated.md §4.1, add a visible SUPERSEDED banner to the
top of notes/bf-4bhd.md and notes/bf-3ldj-findings.md naming
notes/bf-1q3m-consolidated.md as the sole trusted blob inventory, stating the
material reasons:
  - bf-4bhd: 2D field-list drift (claims tracking.Blob has PersonName/
    AssignedColor/IdentityResolved — those fields no longer exist) + line
    drift (E2/E3/volume +90, E1 +110) vs HEAD.
  - bf-3ldj: same line drift + a fundamentally wrong "IDENTITY ATTACHED"
    data-flow claim (tracker.TrackManager.UpdateWithIdentity is not wired
    into main.go at HEAD; identity is sidecar-based via ble.IdentityMatcher).

Add proportionate "secondary - see consolidated" banners to the bf-3ldj-input
notes (bf-26ta, bf-67ao, bf-5kns) and bf-26ta's JS/TS result dumps, so no
inventory-titled note remains that a future agent could mistake for
authoritative. notes/bf-1q3m-consolidated.md already declares itself the
single source of truth (header banner + §9 provenance) - confirmed unchanged.

All stale files retained for provenance; none deleted. Docs-only change, no
Go/JS source modified (go vet + go test ./... clean).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:28:50 -04:00
jedarden
64a2202ac9 docs(bf-1m2x): verify blob-creation inventory is current at HEAD
Re-ran the two completeness greps from notes/bf-1q3m-consolidated.md §1
against current HEAD 0ae0c03. Confirmed 5 primary / 15 non-test named
projection / 2 JS production sites — zero deltas vs the report's
verification commit 1a26c12 (no Go/JS source changed in the interval;
only notes/ + .beads/). Closes the inventory-currency loop without
re-doing discovery. Notes-only; no source modified.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:18:25 -04:00
jedarden
f144aad1f8 docs(bf-1q3m): consolidate & re-verify all blob-creation findings into single report
Merges the four child inventory beads (bf-55rp primary types, bf-5uzm
conversions, bf-4wwt projections, bf-1bmg JS/TS) into one re-verified
source-of-truth report for the upcoming identity-leak implementation bead.

- Re-verified every file:line against HEAD 1a26c12 by running the greps
  (15 type defs, 5 primary + 16 projection production sites, 4 named
  conversion boundaries, 2 JS production sites — all exact)
- Flagged stale entries: supersedes bf-3ldj-findings.md & bf-4bhd.md
  (line drift + 2D field-list drift + wrong data-flow); minor off-by-one
  drifts in child secondary citations noted
- Confirmed the material claim: tracker.TrackManager/applyIdentity is NOT
  wired into main.go; live identity lives in the ble.IdentityMatcher sidecar,
  never written onto the blob struct
- Produced the tiered fix-target list (Tier 1 = main.go:2303 automation +
  :2206 explainability + :2326 volume) and the corrected blob data-flow
  diagram showing where identity enters and leaks

Documentation only — no Go/JS source modified.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:03:28 -04:00
jedarden
2b44ff633d docs(bf-1bmg): inventory JS/TS dashboard blob-creation sites
Catalogue every blob-creation site on the dashboard JS/TS side, re-verified
against HEAD 68bd308:
- 2 production domain-blob sites: state.js:290 ({id:id} + Object.assign of
  server payload) and websocket.js:167 (dead-reckoning _blobStates cache).
- spaxel.d.ts:10-91 Blob interface documented as the single canonical JS
  identity-field declaration (personName/personId/assignedColor/identityResolved
  + deprecated personLabel/personColor), with Go<->JS field name map.
- 4 new Blob() file-download sites (static/js/fleet.js:457, fleet-page.js:1034
  & :1369, js/fleet.js:1997) explicitly flagged OUT OF SCOPE (browser Blob API).
- 12 test fixtures across ambient/quick-actions/replay .test.js listed for
  completeness.
- Corrects two drifts vs bf-3ldj: the :457 CSV site is in static/js/fleet.js
  (a different file from js/fleet.js), and ambient.test.js literal openings are
  124/273/636/653/688/702 (not the :276/:642/etc cited).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 15:46:02 -04:00
jedarden
68bd308c3c docs(bf-4wwt): inventory blob projection/derived types & construction sites
Re-verify the 9 blob-shaped projection types and their 15 non-test
construction sites against HEAD 3591865. Only the two cmd/mothership/main.go
sites moved (+90 lines); all others unchanged.

Corrections/additions over bf-4bhd:
- api.BlobPos is test-only (TriggersHandler.EvaluateTriggers is not wired
  in main.go; production uses volumeTriggersHandler + volume.BlobPos).
- falldetect enters via an anonymous struct; the real boundary is
  main.go:2288, not enumerated in bf-4bhd.
- replay.BlobUpdate and simulator.BlobResult are synthetic, not blob copies.
- Of volume.BlobState's 4 sites, only shape.go:575 is blob-derived.
- volume.BlobPos.PersonID is not populated at main.go:2326.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 15:36:14 -04:00
jedarden
585532f5b2 docs(bf-5uzm): map cross-package blob conversion boundaries in main.go
Re-verified all four named conversion sites against HEAD 7846408 and found the
task's line numbers had drifted (+90..+110). Recorded the corrected locations:
  E1 fusion.Blob peak -> sigproc.TrackedBlob       :5384 -> :5494
  E2 sigproc.TrackedBlob -> automation.TrackedBlob  :2213 -> :2303  (identity dropped)
  E3 sigproc.TrackedBlob -> explainability.BlobSnap :2116 -> :2206  (identity dropped)
  volume sigproc.TrackedBlob -> volume.BlobPos      :2236 -> :2326  (PersonID field exists, unpopulated)

Enumerated all 9 blob-projection loops in the live 10 Hz fusion loop with source/
target types and copied fields, flagged the two identity-leak boundaries (E2/E3)
as the umbrella goal's fix targets, and noted per-target whether the type even
carries identity fields. Includes a corrected live data-flow diagram: the live
loop runs blobTracker (greedy associator), not tracker.TrackManager/applyIdentity;
resolved identity lives in the ble.IdentityMatcher sidecar and is never written
onto the blob struct.

go vet ./... and go test ./... clean.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 15:21:10 -04:00
jedarden
d99f42d3bf docs(bf-55rp): re-verify primary tracked-blob Go types & construction sites
Inventory of the 5 primary tracked-blob Go types + the api.TrackedBlob
alias, re-verified against HEAD c4d42e8. Corrects two stale line numbers
(automation.TrackedBlob :2213->:2303, signal.TrackedBlob :5384->:5494)
and one stale field list (tracking.Blob 2D no longer carries PersonName/
AssignedColor/IdentityResolved — identity fields now match tracker.Blob).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 14:56:35 -04:00
jedarden
c4d42e8c30 test(bf-4b1c): differential lock-in for geometry placement and fusion peaks
bf-4b1c wants test coverage proving geometry placement drives fusion peaks,
with the explicit "would fail with old co-located placement but passes with
new geometry" property. The prior children (bf-18yn -> bf-3y9r) cover each
half separately — TestEngine_DefaultPlacementProducesPeaks (spread alone,
geometry-dependent synthetic links) and TestEngine_CoLocatedOriginYields
NoPeaks (co-located alone). What was missing was a single run that isolates
placement as the SOLE variable and demonstrates the non-zero-peak condition
flipping with geometry, proving the test is genuinely regression-sensitive.

Add TestEngine_GeometryPlacementDrivesFusionPeaks: a fuseWithPlacement helper
builds an engine sized to DefaultSpace, seeds N nodes at a given placement,
and fires an explicit geometry-independent motion link for EVERY node pair
(DeltaRMS=1.0, Motion=true) — the link set, grid, and room are identical
across both legs, so only where nodes sit differs. For default (spread)
placement the grid accumulates a non-zero max (gridMax>0); for the old
co-located (0,0,1) collapse every link is degenerate (<0.1 m), AddLink
Influence early-returns, and the grid stays at zero (gridMax==0). The
differential asserts spread>0 && colocated==0. For count>=4 the crossing
links additionally extract >=1 blob, confirming the non-zero grid localizes.

The trace under `go test -v` shows the flip:
  [spread] nodes=4 gridMax=1.0000 blobs=2 top=(2.90,2.50,1.30) conf=0.768 activeLinks=6
  [colocated] nodes=4 gridMax=0.0000 blobs=0 activeLinks=6 — degenerate links, no accumulation

go test ./... , go vet ./... , and go build ./... (all three modules) pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 13:49:20 -04:00
jedarden
747638ed1d test(bf-3y9r): verify simulator positions reach fusion accumulation grid
bf-3y9r (verify position propagation). The wiring from prior children
(bf-5lii -> bf-69ym -> bf-u7ds -> bf-95tx) already traces a posted node
position through simulator VirtualNodeStore -> fleet.Registry (SQLite) ->
fusion.Engine.nodePos mirror, and bf-95tx's TestPositionPropagation_
FullPipeline logs the value agreeing at all three stages. What was missing
was a single end-to-end assertion that those positions reach the engine's
*accumulation grid* and actually drive localization -- the last inch the
bead's acceptance criterion ("Verify positions reach the fusion engine
accumulation grid") asks for.

Add TestPositionPropagation_ReachesAccumulationGrid: posts two
explicitly-positioned nodes through the simulator REST API, runs one Fuse
step with a link between the two MACs the engine now holds, and asserts a
blob localizes near the link midpoint (confidence 1.0, 1 active link). A
blob there is only reachable if both endpoints' positions are in the grid
lookup -- AddLinkInfluence reads nodePos[mac] for both endpoints, and a
missing/co-located position yields no peak
(cf. TestEngine_CoLocatedOriginYieldsNoPeaks). The grid trace logs the
value's path under `go test -v`:

  [grid] position propagation  midpoint=(3.00,1.00)  peak=(2.90,0.90,0.90) conf=1.000 activeLinks=1

No production wiring change was needed -- prior children completed it; this
bead is verification, with this test as its lock-in.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 13:30:19 -04:00
jedarden
c69b0f7ca1 test(bf-95tx): integration test tracing positions through simulator→registry→fusion
bf-95tx wants a single demonstrable verification that node positions flow
through every runtime stage the position-propagation work touched. bf-69ym
locked in simulator→fleet-registry; bf-u7ds locked in simulator→fusion. This
adds the missing end-to-end lock-in that ties both together in one run.

TestPositionPropagation_FullPipeline wires the production chain behind the
SimulatorHandler (handler → bridge.SyncToRegistry → adapter → fleet.Registry
SQLite, with adapter forwardPos → fleet.Manager.ForwardNodePosition → sink →
fusion.Engine.SetNodePosition), posts one node with an explicit position,
then reads that SAME position back from all three stages and asserts they
agree — at both AddNode and UpdateNode. A pipelineStages helper logs each
stage's value so `go test -v` visibly traces the value's path:

  [create] position propagation  simulator={1.5 2.5 1}  registry={1.5 2.5 1}  fusion={1.5 2.5 1}
  [update] position propagation  simulator={3.5 4.5 2}  registry={3.5 4.5 2}  fusion={3.5 4.5 2}

The update leg also asserts no stage still holds the stale pre-update value
and that a single node stays a single node at every stage (no orphan/dup).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 13:13:28 -04:00
jedarden
dbb5cd0cc4 fix(bf-u7ds): forward simulator registry positions to fusion engine
The simulator→fleet-registry path landed node positions in SQLite but never
reached the blob-producing 3D fusion engine at runtime — SyncToRegistry wrote
through fleetRegistryAdapter, which had no forwarding hook, so the engine's
nodePos mirror stayed stale and Fuse localized against wrong/missing geometry
(seeded correctly only at startup).

Add a forwardPos callback to fleetRegistryAdapter (AddVirtualNode /
SetNodePosition) and wire it to fleetMgr.ForwardNodePosition in main, which
already routes through the nodePositionSink → fusion.Engine.SetNodePosition.
This converges all three registry-write paths (PATCH /position, OnNodeConnected,
simulator sync) on the single ForwardNodePosition accessor.

Lock-in: TestSimulatorHandlerToRegistry_PositionsReachFusionEngine recreates
the full chain behind the SimulatorHandler (real Registry + Manager sink →
fusion.Engine) and asserts the engine mirror updates on both AddNode and
UpdateNode — mirroring the two bf-3p6g lock-ins for the simulator path.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 12:43:46 -04:00
jedarden
fd7918f7fc docs(bf-4oiz): mark registry-bridge position audit resolved, close out
The bf-4pqj audit flagged a compile blocker (cmd/mothership did not build:
*fleet.Registry didn't satisfy simulator.RegistryNodeAdapter) and recorded
"go vet/test fail pre-close". bf-5lii since fixed it (fleetRegistryAdapter +
immediate SyncToRegistry on node create/update) and bf-69ym added two
end-to-end simulator→fleet.Registry tests.

Re-verified the full position flow for this umbrella bead's close-out:
- go build ./cmd/mothership — OK
- go vet ./... — clean
- go test ./... — all green (simulator + api fresh)

Update bf-4oiz-findings.md so its "fails" claims no longer mislead: add a
RESOLVED header summarizing the fixes, and correct the conclusion table's
"go vet green" row to . Verification-only; no production code changes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 12:22:25 -04:00
jedarden
14565743c5 test(bf-69ym): end-to-end simulator→fleet-registry position flow
The only coverage of the simulator→registry position path was either
bridge-level unit tests (registry_bridge_test.go against a fake adapter) or
handler-level immediate-sync tests (TestImmediateSyncOnAddAndUpdate against a
recording fake with explicit positions). Nothing proved a position travels
from the simulator handler all the way into the live fleet.Registry — and
specifically that an origin-default node is written to the registry at the
spread geometry DefaultNodePositions assigns, not co-located at (0,0,0).

Add two end-to-end tests that wire a real SQLite-backed *fleet.Registry
behind the SimulatorHandler (the same wiring cmd/mothership/main.go uses,
via a test-local fleetRegistryTestAdapter that mirrors the production
fleetRegistryAdapter since the latter lives in package main and isn't
importable):

- TestSimulatorHandlerToRegistry_CreateAndUpdate: AddNode (no position) →
  CreateVirtualNode → SyncToRegistry → AddVirtualNode into the live registry,
  asserting the node lands at exactly DefaultNodePositions(space,1) (never
  (0,0,0)); then UpdateNode → SetNodePosition, asserting the new position
  flows through to the same registry row without duplicating it.

- TestSimulatorHandlerToRegistry_OriginNodesGetSpreadGeometry: 4 nodes
  posted at the DB default origin {0,0,1} must land in the registry at the
  distinct, spread-out DefaultNodePositions(space,4) set — never co-located
  at the origin (the failure mode in bf-18yn / bf-4q5w).

Split from bf-4oiz. go test ./internal/simulator/... ./internal/api/... and
full go test/vet ./... all green.

Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-69ym
2026-07-06 12:08:27 -04:00
jedarden
41e8233011 feat(bf-5lii): wire immediate registry sync on simulator node create/update
The simulator API handlers AddNode and UpdateNode only logged that a node
"will be synced to registry on next periodic sync" — they held a
registryBridge field but had no RegistryNodeAdapter to pass to
SyncToRegistry, so new nodes waited up to 30s for the periodic ticker
before reaching the fleet registry.

Wire the missing half:
- SimulatorHandler gains a registryAdapter (simulator.RegistryNodeAdapter)
  field threaded into NewSimulatorHandler.
- AddNode calls registryBridge.SyncToRegistry(adapter) right after
  CreateVirtualNode succeeds; UpdateNode does the same after
  UpdateNodePosition succeeds. Both run outside the handler lock.
- main.go adds fleetRegistryAdapter (adapts *fleet.Registry to the
  simulator interface, converting fleet.NodeRecord <-> simulator.NodeRecord),
  shared by the immediate syncs and the 30s periodic ticker (which stays
  as a safety net).

New table-driven TestImmediateSyncOnAddAndUpdate covers both the wired and
nil-adapter no-op paths.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 11:46:43 -04:00
jedarden
4705c9f432 docs(bf-4pqj): audit registry_bridge position wiring — flag compile blocker
Re-verified the registry_bridge position data flow (split from bf-4oiz).
The stale 'wiring missing' claim is corrected: the 30s periodic
SyncToRegistry IS wired in source (main.go:4195-4226), and the bridge
logic + float64 XYZ formatting are confirmed correct and backed by
registry_bridge_test.go.

However the audit found cmd/mothership does NOT build: main.go:4217
passes *fleet.Registry to SyncToRegistry, but *fleet.Registry does not
satisfy simulator.RegistryNodeAdapter (GetAllNodes/GetNode return
[]fleet.NodeRecord vs []simulator.NodeRecord). A second failure,
internal/api/simulator_test.go:19, passes no args to the now-2-arg
NewSimulatorHandler. Both introduced by e92d5bc (bf-5dpu). The
internal/simulator package itself builds and tests green.

Verification-only bead: no production code changes. go vet/test fail
pre-close, so the blocker is documented for a wiring-owner fix.
2026-07-06 11:46:43 -04:00
jedarden
d43b0095e6 docs(bf-4bhd): enumerate projection blob construction sites in report
Verified every line number in the blob-creation report against current main
(5 primary types, 8 primary sites, 2 identity-mutation funcs, 9 projection
types — all accurate). Added an enumerated table of the 15 projection
construction sites across 7 files so the next bead needs no further searching.
Completeness sweep confirmed no new(Blob), no missed factories, no uncatalogued
make([]Blob) allocators.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 11:46:43 -04:00
jedarden
e3bd5ee685 docs(bf-3ldj): consolidate blob creation site findings into single report
Aggregates bf-5kns (new Blob constructors), bf-26ta (struct/object
literals), and bf-67ao (factory functions) into notes/bf-3ldj-findings.md.
Re-verified every production file:line against HEAD; corrected two stale
entries (state.js:290 now {id} only; tracking.Blob field names) and
reconciled the Go-vs-JS identity-field naming. Key deliverable for the
next bead: identity is dropped at two main.go conversion boundaries
(:2213 automation, :2116 explainability) — the leak this work closes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 10:22:55 -04:00
jedarden
7e89b31922 docs(bf-67ao): add completeness sweep — 10th blob type + missed explainability site
Extend the blob-factory catalogue with findings from a verification sweep of
all documented file:line references (all 15 original entries confirmed exact):

- Add the 10th blob type, explainability.BlobSnapshot (handler.go:95), a distinct
  type from the already-listed falldetect.BlobSnapshot — note their shared name.
- Add entry E3: the production conversion loop at main.go:2116 (inside main()'s
  fusion loop) that builds []explainability.BlobSnapshot to feed computeExplanation
  (F1). Sibling inline-conversion to E2; the only site constructing this type.
- Add a 'test-only factories' caveat listing the *_test.go helpers the sweep found
  (makeBlobAt, processFramesDirectly/WithThreshold, mock providers) and documenting
  why they are scoped out, plus the newBlobTracker struct constructor (not a blob).

Catalogue now: 16 documented creation sites (14 dedicated functions/methods +
2 inline conversion loops) across 10 blob types.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 10:14:03 -04:00
jedarden
43d3a710e7 docs(bf-67ao): document blob factory functions across codebase
Catalogue the 15 functions/methods that construct and return blob objects,
covering 9 blob types (tracker.Blob, tracking.Blob, fusion.Blob,
signal.TrackedBlob, automation.TrackedBlob, replay.BlobUpdate,
simulator.BlobResult, explainability.BlobExplanation, falldetect.BlobSnapshot).

Each entry records the function signature, file:line of both the function
definition and the struct-literal creation site, and the construction idiom
(pointer/value literal, slice copy, delegation, or record append). Includes a
summary table and the end-to-end data flow (Fuse -> track -> Update ->
GetBlob). Complements the earlier bf-4bhd literal-site survey with a
function-level (factory) view.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 10:04:07 -04:00
jedarden
c595d13208 docs(bf-26ta): correct blob literal counts, add missing ambient.test.js sites
Re-verified all blob-shaped object literals against current code. The prior
docs drifted: quick-actions.test.js was mis-counted as 16 literals (actual 5)
and only 4 of 6 ambient.test.js blob-array sites were documented.

Corrections (notes/bf-26ta-findings.md, bf-26ta-javascript-results.md):
- Add missing ambient.test.js sites at lines 694 (lerp source) and 708 (lerp target)
- Fix quick-actions.test.js count: 16 -> 5 literals (lines 208, 316, 470, 513, 678)
- Fix JS totals: 25 across 7 files -> 14 across 5 files
- state.js:290, websocket.js:167, replay.test.js:101 unchanged (still accurate)
- TypeScript: still 0 literals (only spaxel.d.ts type defs)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 09:30:26 -04:00
jedarden
756cc03a00 docs(bf-5613): analyze multi-person bedroom sleep monitoring edge case
- Created comprehensive findings document at notes/bf-5613-findings.md
- Added TestTwoPersonBedroomScenario to integration_test.go
- Verified that multi-person bedroom edge case is NOT implemented:
  * No detection of multiple blobs in bedroom zones
  * No BLE-first assignment logic
  * No zone-based fallback records
  * No lowest-deltaRMS blob selection for breathing analysis
- Test documents expected behavior per plan.md specification

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 02:47:37 -04:00
jedarden
36886ab60c docs(bf-3f16): document API path verification - all endpoints match plan spec
Verified all REST API endpoints against plan.md specification:
- GET /api/analytics/flow - matches exactly
- GET /api/localization/weights - matches exactly
- POST /api/localization/weights/reset - alias route added for plan spec compliance

No deviations found. API_IMPLEMENTATION_STATUS.md already documents
the canonical path decisions with backward compatibility maintained.
2026-07-06 02:40:53 -04:00
jedarden
60bc74580f feat(bf-2y6u): implement coverage degradation overlay for self-healing events
- Add showCoverageDegradation() to display before/after GDOP comparison
- Add dismissCoverageDegradation() to clear overlay on node recovery
- Create ground plane cells colored by degradation severity (red/amber/yellow)
- Add legend with before/after statistics and coverage delta
- Export functions to public API for WebSocket integration

Implements plan.md Component 12: before/after coverage overlay
when fleet self-healing fires due to node loss.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 02:29:06 -04:00
jedarden
925140c687 docs(bf-3tlw): compile comprehensive blob literal locations documentation
- Merged TypeScript and JavaScript search results
- Combined Go backend blob creation sites
- Documented 25 JavaScript instances across 7 files
- Documented 10+ Go blob types across 8 files
- Included TypeScript type definitions
- Each location includes file path, line number, and blob structure pattern
- Organized by language with detailed pattern analysis

Bead-Id: bf-3tlw
2026-07-06 02:20:42 -04:00
jedarden
382b150116 docs(bf-4ly4): document JavaScript blob literal search results
- Found 25 blob-shaped object literals across 7 files
- Identified canonical creation pattern in state.js:290
- Documented field usage patterns and test fixtures
- Compared blob, zone, node, and event structures
2026-07-06 02:18:46 -04:00
jedarden
75806ae8f0 docs(bf-26ta): document TypeScript blob literal search results
- Searched all .ts and .tsx files for blob-shaped object literals
- Found 3 TypeScript files total (excluding node_modules)
- No blob object literals found in TypeScript files
- Only type definitions exist in spaxel.d.ts
- Actual blob creation happens in JavaScript files
2026-07-06 02:08:41 -04:00
jedarden
079c631134 docs(bf-3aij): define blob object literal search pattern
- Document blob object structure in JavaScript and Go
- Create grep/ripgrep patterns for finding blob literals
- Provide example matches from codebase
- Document key characteristics: id, position, confidence fields
- Add search patterns for both JS dashboard and Go backend

This provides the foundation for identifying blob-shaped object
literals across the spaxel codebase for future search/refactoring work.
2026-07-06 02:05:49 -04:00
jedarden
111eb2719b docs(bf-5kns): document Blob constructor search results
Found 4 direct Blob() constructor calls across 3 JavaScript files:
- 2 for CSV export (text/csv)
- 2 for JSON config export (application/json)

All calls follow consistent pattern with array-wrapped content
and explicit MIME type specification.
2026-07-06 01:52:54 -04:00
jedarden
e92d5bc325 feat(simulator): wire registry bridge position data flow (bf-5dpu)
Complete the wiring between simulator API and registry_bridge.go to ensure
positions flow correctly through the complete data path:

1. Simulator API receives node positions via POST /api/simulator/nodes
2. Positions persisted to VirtualNodeStore
3. Periodic 30s sync reads positions from store
4. Registry bridge processes positions (spread geometry for default origin)
5. Positions written to Fleet Registry database

Changes in main.go:
- Create VirtualNodeStore with persistence
- Create FleetRegistryBridge wrapping the store
- Add periodic sync goroutine (every 30s) calling SyncToRegistry
- Wire simulatorHandler with both store and bridge

Changes in simulator.go:
- Update SimulatorHandler to accept virtualStore and registryBridge
- Load existing virtual nodes from store on startup
- Persist node operations (Create, Update, Delete) to store
- Add logging for position flow traceability

Acceptance criteria met:
✓ Positions flow from simulator to registry_bridge.go
✓ Positions correctly formatted for registry
✓ All wiring issues resolved
✓ Data path complete and functional

Resolves bf-5dpu
2026-07-06 01:51:16 -04:00
jedarden
c94bccec1c docs(bf-5occ): document position format mismatch between simulator and registry
- Registry coordinate system: X=width, Y=height, Z=depth
- Simulator coordinate system: X=width, Y=depth, Z=height
- Y and Z axes are swapped between systems
- registry_bridge.go passes positions without coordinate transformation
- Required fix: swap Y and Z when calling registry methods
- Affects fusion engine, coverage optimization, and position-based tracking

Acceptance criteria:
- Registry's expected position format is documented 
- Actual format from simulator is documented 
- Format differences are identified 
- Required transformations are documented 
2026-07-06 01:48:06 -04:00
jedarden
5445d765bc docs(bf-5occ): document position format mismatch between simulator and registry
- Registry expects: pos_x=width, pos_y=height, pos_z=depth
- Simulator provides: Point.X=width, Point.Y=depth, Point.Z=height
- Current implementation passes Y/Z directly without swapping
- This causes registry to misinterpret depth as height and height as depth
- Requires coordinate transformation in registry_bridge.go

Acceptance criteria met:
✓ Registry's expected position format documented
✓ Actual format from simulator documented
✓ Format differences identified
✓ Required transformations documented
2026-07-06 01:41:17 -04:00
jedarden
abf272a781 docs(bf-2irz): verify registry bridge receives simulator positions
Add logging to trace position data flow from simulator to registry bridge.
Verify that positions are correctly received and processed through the
complete data path:

1. Simulator API receives node positions via POST /api/simulator/nodes
2. Positions persisted to VirtualNodeStore
3. Periodic 30s sync reads positions from store
4. Registry bridge processes positions (spread geometry for default origin)
5. Positions written to Fleet Registry database

Enhanced logging at each step shows:
- Sync start with node count
- Per-node position processing (default origin vs explicit)
- Per-node sync to registry with position values
- Registry operations (create/update with positions)

Data flow confirmed working. Positions DO flow from simulator to
registry_bridge.go to fleet registry.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 01:37:40 -04:00
jedarden
39b5755d5c docs(bf-2r5o): document simulator position data structure
- Document core position structures (Point, VirtualNode, Walker, Space)
- Document position fields in hello messages and database schema
- Map position data flow from simulator through mothership to fusion engine
- Document node positioning strategies and walker movement behavior
- Include file locations and coordinate system definitions

Acceptance criteria met:
- Position data structure documented
- Source of position data identified (generateNodePositions, createWalkers)
- Field names and types known (Point struct, hello message fields, database schema)
2026-07-06 01:35:06 -04:00
jedarden
ac806a7753 docs(bf-4bhd): document all blob creation code paths
- Identified 4 distinct Blob types across codebase
- Documented 8 primary blob creation sites with line numbers
- Categorized by construction pattern (&Blob{}, Blob{}, slice copy)
- Listed all files requiring updates for structure changes
- Included field mutation sites for identity assignment

This analysis provides a complete inventory for any future blob
structure modifications.
2026-07-06 01:35:06 -04:00
jedarden
76cb540776 docs(bf-3ifj): document simulator-to-registry position wiring trace
Complete analysis of two position data flow paths:
1. CSI Simulator (cmd/sim) → hello message → fleet manager → registry
2. Virtual Node Planning (simulator/) → registry bridge → adapter → registry

Both paths verified as complete and functional. No breaks or missing connections found.
2026-07-06 01:14:12 -04:00
jedarden
4c5b75322b Merge branch 'main' of https://git.ardenone.com/jedarden/spaxel 2026-07-06 01:03:33 -04:00
jedarden
08ae674967 Add TypeScript type definitions for blob identity fields
Add TypeScript interface definitions for blob and related data structures,
including new identity resolution fields (personName, assignedColor, identityResolved).

Reference: bf-2186

- Created types/spaxel.d.ts with comprehensive type definitions
- Added Blob interface with identity fields (personName, assignedColor, identityResolved)
- All new fields typed as optional for backward compatibility
- Added JSDoc comments explaining each field
- Includes type definitions for all major dashboard data structures (Node, Zone, Alert, etc.)
- Maintained legacy fields (personLabel, personColor) with @deprecated tags

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 01:03:27 -04:00