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>
This commit is contained in:
parent
c4d42e8c30
commit
d99f42d3bf
1 changed files with 337 additions and 0 deletions
337
notes/bf-55rp-primary-types.md
Normal file
337
notes/bf-55rp-primary-types.md
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
# Primary Tracked-Blob Go Types — Inventory & Construction Sites (bf-55rp)
|
||||
|
||||
> **Scope:** the FIVE primary tracked-blob Go types that make up the tracked-blob
|
||||
> lifecycle, plus the `api.TrackedBlob` alias. Re-verification of
|
||||
> `notes/bf-3ldj-findings.md` (§1–3) and `notes/bf-4bhd.md` (Blob Type Definitions +
|
||||
> Patterns 1–2) against current HEAD.
|
||||
>
|
||||
> **Verified against:** `c4d42e8` (`c4d42e8 test(bf-4b1c): differential lock-in for
|
||||
> geometry placement and fusion peaks`) on **2026-07-06**.
|
||||
>
|
||||
> **This bead is documentation only — no Go source was modified.**
|
||||
|
||||
---
|
||||
|
||||
## 0. TL;DR
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| How many primary tracked-blob Go types? | **5** + the `api.TrackedBlob` alias |
|
||||
| How many DIRECT struct-literal construction sites (production)? | **5** — exactly one per primary type |
|
||||
| Did anything move since bf-3ldj / bf-4bhd? | **Yes — 2 sites.** `automation.TrackedBlob` `:2213 → :2303`; `signal.TrackedBlob` (`sigproc`) `:5384 → :5494` |
|
||||
| Did any type definition move? | **No** — all 6 definitions (5 structs + 1 alias) are at their previously reported `file:line` |
|
||||
| Did any field list drift? | **Yes — `tracking.Blob` (2D).** The 3 identity fields `PersonName`, `AssignedColor`, `IdentityResolved` have been **removed**; the 2D type's identity field set is now identical to the 3D `tracker.Blob`. See §3.1. |
|
||||
| Is the `api.TrackedBlob` alias still pure? | **Yes** — `type TrackedBlob = signal.TrackedBlob` (no separate struct) |
|
||||
|
||||
---
|
||||
|
||||
## 1. The six definitions (file:line, verified against HEAD)
|
||||
|
||||
| # | Type | Package | Definition site | Kind |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `tracking.Blob` (2D, legacy floor tracker) | `mothership/internal/tracking` | `internal/tracking/tracker.go:21` | struct |
|
||||
| 2 | `tracker.Blob` (3D, identity-bearing) | `mothership/internal/tracker` | `internal/tracker/tracker.go:36` | struct |
|
||||
| 3 | `fusion.Blob` (peak) | `mothership/internal/fusion` | `internal/fusion/fusion.go:36` | struct |
|
||||
| 4 | `automation.TrackedBlob` | `mothership/internal/automation` | `internal/automation/engine.go:1337` | struct |
|
||||
| 5 | `signal.TrackedBlob` | `mothership/internal/signal` | `internal/signal/processor.go:587` | struct |
|
||||
| 6 | `api.TrackedBlob` (alias of #5) | `mothership/internal/api` | `internal/api/tracks.go:30` | **type alias** |
|
||||
|
||||
All six `file:line` entries match bf-4bhd.md / bf-3ldj-findings.md exactly — **none of the
|
||||
definitions moved.**
|
||||
|
||||
### 1.1 The `api.TrackedBlob` alias relationship
|
||||
|
||||
```go
|
||||
// internal/api/tracks.go:29-30
|
||||
// TrackedBlob is an alias for signal.TrackedBlob.
|
||||
type TrackedBlob = signal.TrackedBlob
|
||||
```
|
||||
|
||||
This is a **pure Go type alias** (`=`, not a named type wrapping the struct). Consequences:
|
||||
|
||||
- `api.TrackedBlob` and `signal.TrackedBlob` are the **same type** — no conversion needed.
|
||||
- Any field added/removed on `signal.TrackedBlob` (`processor.go:587`) **automatically** surfaces
|
||||
under the `api.TrackedBlob` name. No separate edit at `tracks.go:30`.
|
||||
- The `TracksProvider` interface (`tracks.go:33`) returns `[]signal.TrackedBlob`, which is
|
||||
interchangeable with `[]api.TrackedBlob`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Every DIRECT struct-literal construction site (verified against HEAD)
|
||||
|
||||
> "Direct struct-literal" = a `&Blob{}` / `Blob{}` / `TrackedBlob{}` literal that brings a
|
||||
> new value of one of the five types into existence. Snapshot deep-copies (`out[i] = *b`,
|
||||
> `make`+`copy`) are **dereferences / slice copies, not literals** — out of scope here and
|
||||
> correctly excluded from bf-4bhd's Pattern 3 as separate operations.
|
||||
|
||||
A whole-repo sweep
|
||||
(`grep -rn "Blob{\|TrackedBlob{" mothership/`, test files excluded, projection-type
|
||||
literals filtered out) returns **exactly five** production construction sites — one per
|
||||
primary type:
|
||||
|
||||
| # | Type built | Site (HEAD) | Site in prior reports | Pattern | Built from |
|
||||
|---|---|---|---|---|---|
|
||||
| C1 | `fusion.Blob` | `internal/fusion/fusion.go:260` | `:260` ✓ | `Blob{}` value (single line) | fusion grid peak |
|
||||
| A2 | `tracking.Blob` (2D) | `internal/tracking/tracker.go:160` | `:160` ✓ | `&Blob{}` pointer | unmatched 2D measurement |
|
||||
| A1 | `tracker.Blob` (3D) | `internal/tracker/tracker.go:162` | `:162` ✓ | `&Blob{}` pointer | unmatched 3D measurement |
|
||||
| E2 | `automation.TrackedBlob` | `cmd/mothership/main.go:2303` | **`:2213` → moved +90** | `TrackedBlob{}` value | tracked blob (conversion) |
|
||||
| E1 | `signal.TrackedBlob` (`sigproc`) | `cmd/mothership/main.go:5494` | **`:5384` → moved +110** | `TrackedBlob{}` value | `fusion.Blob` peak (conversion) |
|
||||
|
||||
**No other production direct-literal sites exist** for any of the five types. The two `main.go`
|
||||
sites are the only ones that moved; the two tracker sites and the fusion site are unchanged.
|
||||
|
||||
### 2.1 Literal text (verified, verbatim)
|
||||
|
||||
**C1 — `fusion.Blob` peak emission** (`fusion/fusion.go:260`), inside `(*Engine).Fuse`:
|
||||
```go
|
||||
blobs[i] = Blob{X: p[0], Y: p[1], Z: p[2], Confidence: p[3]}
|
||||
```
|
||||
Value-type per grid peak. **No identity** — peaks are pre-identity. This is the raw
|
||||
measurement that originates every blob downstream.
|
||||
|
||||
**A2 — `tracking.Blob` (2D) track spawn** (`tracking/tracker.go:160`), inside `(*Tracker).Update`:
|
||||
```go
|
||||
b := &Blob{
|
||||
ID: t.nextID,
|
||||
X: meas[0],
|
||||
Z: meas[1],
|
||||
Weight: meas[2],
|
||||
LastSeen: now,
|
||||
Trail: [][2]float64{{meas[0], meas[1]}},
|
||||
ukf: NewUKF(meas[0], meas[1]),
|
||||
}
|
||||
```
|
||||
Identity fields exist on the struct (see §3.1) but are **not set** in the literal — left at
|
||||
Go zero values, populated later by the BLE-matching layer.
|
||||
|
||||
**A1 — `tracker.Blob` (3D) track spawn** (`tracker/tracker.go:162`), inside `(*Tracker).Update`:
|
||||
```go
|
||||
b := &Blob{
|
||||
ID: t.nextID,
|
||||
X: m[0], Y: m[1], Z: m[2],
|
||||
Weight: m[3],
|
||||
LastSeen: now,
|
||||
Trail: [][3]float64{{m[0], m[1], m[2]}},
|
||||
Posture: PostureUnknown,
|
||||
ukf: NewUKF(m[0], m[1], m[2]),
|
||||
}
|
||||
```
|
||||
Identity fields exist on the struct but are **not set** in the literal — populated later by
|
||||
`applyIdentity` (`tracker/identity.go`, the 3D identity-matching layer).
|
||||
|
||||
**E2 — `automation.TrackedBlob` conversion** (`cmd/mothership/main.go:2303`), in the live
|
||||
10 Hz loop, loop over tracked `blobs`:
|
||||
```go
|
||||
autoBlobs[i] = automation.TrackedBlob{
|
||||
ID: b.ID,
|
||||
X: b.X,
|
||||
Y: b.Y,
|
||||
Z: b.Z,
|
||||
VX: b.VX,
|
||||
VY: b.VY,
|
||||
VZ: b.VZ,
|
||||
Confidence: b.Weight,
|
||||
}
|
||||
```
|
||||
The source blob **has identity**, but `automation.TrackedBlob` (see §3.4) has **no identity
|
||||
fields** — identity is **dropped** at this boundary. (This is the long-standing "automation
|
||||
leak" flagged in bf-3ldj §5 Tier 1; re-confirmed unchanged at HEAD.)
|
||||
|
||||
**E1 — `signal.TrackedBlob` (`sigproc`) conversion** (`cmd/mothership/main.go:5494`), inside
|
||||
`(*blobTracker).track`, built from a `fusion.Blob` peak `pk`:
|
||||
```go
|
||||
b := sigproc.TrackedBlob{
|
||||
ID: id,
|
||||
X: pk.X,
|
||||
Y: pk.Y,
|
||||
Z: pk.Z,
|
||||
Weight: pk.Confidence,
|
||||
}
|
||||
// velocity filled in afterward from bt.prev[id]:
|
||||
// b.VX = (pk.X - pb.X) / dt ; b.VY = ... ; b.VZ = ...
|
||||
```
|
||||
Built from a **pre-identity peak**, so the `signal.TrackedBlob` identity fields (which do
|
||||
exist — see §3.5) are left zero here by design.
|
||||
|
||||
---
|
||||
|
||||
## 3. Field lists (verified against HEAD) + the one drift
|
||||
|
||||
### 3.1 `tracking.Blob` (2D) — **field list DRIFTED (correction to bf-4bhd.md)**
|
||||
|
||||
`internal/tracking/tracker.go:21`. **Current** struct:
|
||||
```go
|
||||
type Blob struct {
|
||||
ID int
|
||||
X float64
|
||||
Z float64
|
||||
VX float64
|
||||
VZ float64
|
||||
Weight float64
|
||||
LastSeen time.Time
|
||||
Trail [][2]float64
|
||||
ukf *UKF
|
||||
|
||||
// Identity fields (populated by BLE-to-blob matching)
|
||||
PersonID string `json:"person_id,omitempty"`
|
||||
PersonLabel string `json:"person_label,omitempty"`
|
||||
PersonColor string `json:"person_color,omitempty"`
|
||||
IdentityConfidence float64 `json:"identity_confidence,omitempty"`
|
||||
IdentitySource string `json:"identity_source,omitempty"`
|
||||
IdentityLastSeen time.Time `json:"-"`
|
||||
Posture Posture `json:"posture,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ **Correction to `notes/bf-4bhd.md` §"1. tracking.Blob".** The prior report listed
|
||||
> `PersonName`, `AssignedColor`, `IdentityResolved` as fields of this struct, and the
|
||||
> literal as initializing `PersonName:""`, `AssignedColor:""`, `IdentityResolved:false`.
|
||||
> bf-3ldj §1.2 already half-corrected this ("the literal sets none of them"). As of HEAD,
|
||||
> **those three fields no longer exist on the struct at all** — they have been removed. The
|
||||
> 2D type's identity field set is now **identical** to the 3D `tracker.Blob`:
|
||||
> `PersonID / PersonLabel / PersonColor / IdentityConfidence / IdentitySource / IdentityLastSeen`.
|
||||
> The 2D-vs-3D identity-field divergence noted in bf-4bhd's "Key Findings" has been closed.
|
||||
|
||||
### 3.2 `tracker.Blob` (3D, identity-bearing) — unchanged
|
||||
|
||||
`internal/tracker/tracker.go:36`. **Current** struct (fields match bf-4bhd; json tags added
|
||||
since, immaterial to the field set):
|
||||
```go
|
||||
type Blob struct {
|
||||
ID int
|
||||
X, Y, Z float64
|
||||
VX, VY, VZ float64
|
||||
Weight float64
|
||||
Posture Posture
|
||||
LastSeen time.Time
|
||||
Trail [][3]float64
|
||||
|
||||
// Identity fields
|
||||
PersonID string `json:"person_id,omitempty"`
|
||||
PersonLabel string `json:"person_label,omitempty"`
|
||||
PersonColor string `json:"person_color,omitempty"`
|
||||
IdentityConfidence float64 `json:"identity_confidence,omitempty"`
|
||||
IdentitySource string `json:"identity_source,omitempty"`
|
||||
IdentityLastSeen time.Time `json:"-"`
|
||||
|
||||
ukf *UKF // internal — nil in copies returned to callers
|
||||
}
|
||||
```
|
||||
Identity-matching lives in `tracker/identity.go` (`applyIdentity` / `clearIdentity`),
|
||||
operating on this 3D type only.
|
||||
|
||||
### 3.3 `fusion.Blob` (peak) — unchanged
|
||||
|
||||
`internal/fusion/fusion.go:36`:
|
||||
```go
|
||||
type Blob struct {
|
||||
X, Y, Z float64 // world-space position (metres)
|
||||
Confidence float64 // normalised [0..1]
|
||||
}
|
||||
```
|
||||
**No identity, no velocity, no ID** — the pre-identity raw peak.
|
||||
|
||||
### 3.4 `automation.TrackedBlob` — unchanged
|
||||
|
||||
`internal/automation/engine.go:1337`:
|
||||
```go
|
||||
type TrackedBlob struct {
|
||||
ID int
|
||||
X, Y, Z float64
|
||||
VX, VY, VZ float64
|
||||
Confidence float64
|
||||
}
|
||||
```
|
||||
**No identity fields.** This is why the E2 conversion (`main.go:2303`) drops identity.
|
||||
|
||||
### 3.5 `signal.TrackedBlob` — unchanged
|
||||
|
||||
`internal/signal/processor.go:587`:
|
||||
```go
|
||||
type TrackedBlob struct {
|
||||
ID int
|
||||
X, Y, Z float64
|
||||
VX, VY, VZ float64
|
||||
Weight float64
|
||||
// Identity fields
|
||||
PersonID string `json:"person_id,omitempty"`
|
||||
PersonLabel string `json:"person_label,omitempty"`
|
||||
PersonColor string `json:"person_color,omitempty"`
|
||||
IdentityConfidence float64 `json:"identity_confidence,omitempty"`
|
||||
IdentitySource string `json:"identity_source,omitempty"`
|
||||
Posture string `json:"posture,omitempty"`
|
||||
}
|
||||
```
|
||||
Identity fields **present** (so the type can carry identity), but the E1 conversion builds
|
||||
from a pre-identity peak and leaves them zero. `api.TrackedBlob` (`tracks.go:30`) is this
|
||||
exact type under an alias.
|
||||
|
||||
---
|
||||
|
||||
## 4. Re-location methodology (acceptance criterion)
|
||||
|
||||
Moved sites were re-located, exactly as the task prescribes, with:
|
||||
|
||||
```bash
|
||||
grep -rn "Blob{$\|&Blob{$\|TrackedBlob{$" mothership/
|
||||
```
|
||||
|
||||
Result (test files included this time, for completeness):
|
||||
|
||||
```
|
||||
mothership/internal/tracker/tracker.go:162: b := &Blob{ # A1 (3D, prod)
|
||||
mothership/cmd/mothership/main.go:2303: autoBlobs[i] = automation.TrackedBlob{ # E2 (prod, MOVED)
|
||||
mothership/cmd/mothership/main.go:5494: b := sigproc.TrackedBlob{ # E1 (prod, MOVED)
|
||||
mothership/internal/api/tracks_test.go:49: blobs := []TrackedBlob{ # TEST (out of scope)
|
||||
mothership/internal/tracking/tracker.go:160: b := &Blob{ # A2 (2D, prod)
|
||||
```
|
||||
|
||||
The end-of-line `$` anchor misses the single-line fusion literal, so a second pass with the
|
||||
broader `grep -rn "Blob{\|TrackedBlob{" mothership/` (filtering projection types and tests)
|
||||
catches it:
|
||||
|
||||
```
|
||||
mothership/internal/fusion/fusion.go:260: blobs[i] = Blob{X: p[0], Y: p[1], Z: p[2], Confidence: p[3]} # C1 (prod)
|
||||
```
|
||||
|
||||
**Re-run these two greps before editing any of these sites** — `main.go` is a large,
|
||||
frequently-edited file and the two conversion lines drift by tens of lines between beads.
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance criteria status
|
||||
|
||||
- [x] Each of the 5 primary types has its struct definition recorded with file:line,
|
||||
verified against current HEAD — §1 table + §3 verbatim structs.
|
||||
- [x] Every direct struct-literal construction site listed (file:line + pattern:
|
||||
`&Blob{}` / `Blob{}` / `TrackedBlob{}`) — §2 table + §2.1 verbatim literals;
|
||||
whole-repo sweep confirms exactly five production sites, no others.
|
||||
- [x] The `api.TrackedBlob` alias relationship to `signal.TrackedBlob` is noted — §1.1.
|
||||
- [x] Re-locate moved sites with `grep -rn "Blob{$\|&Blob{$\|TrackedBlob{$" mothership/` —
|
||||
§4; two moved sites identified and corrected (`:2213→:2303`, `:5384→:5494`).
|
||||
- [x] Findings written to `notes/bf-55rp-primary-types.md` — this file.
|
||||
|
||||
---
|
||||
|
||||
## 6. Net changes since the source reports (the delta this re-verification surfaces)
|
||||
|
||||
1. **Two construction sites moved** (no semantic change):
|
||||
- `automation.TrackedBlob`: `main.go:2213 → :2303`
|
||||
- `signal.TrackedBlob` (`sigproc`): `main.go:5384 → :5494`
|
||||
2. **One field-list drift** in `tracking.Blob` (2D): `PersonName`, `AssignedColor`,
|
||||
`IdentityResolved` removed; identity field set now matches `tracker.Blob` (3D) exactly.
|
||||
3. **All six type definitions** (5 structs + 1 alias) are at their previously reported
|
||||
`file:line`; the alias is still a pure `=` alias.
|
||||
4. The **automation identity leak** (E2 drops identity because `automation.TrackedBlob`
|
||||
has no identity fields) and the **peak-origin zero-identity** of E1 are both unchanged
|
||||
and remain the open work items tracked in bf-3ldj §5.
|
||||
|
||||
---
|
||||
|
||||
## 7. Provenance
|
||||
|
||||
| Source report | Used for | Status at HEAD |
|
||||
|---|---|---|
|
||||
| `notes/bf-3ldj-findings.md` §1–3 | Type defs, primary literals, identity-flow context | §1 defs valid; one literal line number stale (E2); field-set note for 2D now fully resolved |
|
||||
| `notes/bf-4bhd.md` (Blob Type Definitions + Patterns 1–2) | Type defs, `&Blob{}`/`Blob{}` patterns, alias note | §1 defs valid; 2D field list stale (§3.1); E2/E1 line numbers stale |
|
||||
| This report (bf-55rp) | Re-verification + corrections + alias documentation | Verified against `c4d42e8`, 2026-07-06 |
|
||||
Loading…
Add table
Reference in a new issue