Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ id: TASK-321.02
title: >-
Capture 3 starter personas (5G-Video-fresh, nano-7G-populated,
echo-mini-empty)
status: To Do
status: Done
assignee: []
created_date: '2026-05-11 22:55'
updated_date: '2026-05-12 12:12'
updated_date: '2026-05-13 22:30'
labels:
- testing
- vm-coverage
Expand All @@ -18,6 +18,7 @@ dependencies:
documentation:
- documents/test-devices.md
- documents/sysinfo-captures/
- documents/persona-capture-playbook.md
parent_task_id: TASK-321
priority: high
ordinal: 220
Expand All @@ -43,13 +44,9 @@ For each persona, capture:
- Partition layout summary (sector counts, filesystem types)
- For `echo-mini-empty`: a pre-built FAT32 backing image (or synthesis recipe) in `massStorageBackingFile`

**Human-in-the-loop capture flow:**
**Capture workflow:** Follow `documents/persona-capture-playbook.md` — the agent-directive doc that walks an agent + user pair through the full Mac → Linux capture pipeline. The playbook covers raw-probe file layout, per-device commands for both sessions, how to derive expectedCapabilities/Readiness/Doctor, the provenance.md template, and the synthesised rejection cases.

Each capture session requires physical hardware to be plugged in. The flow is:
1. User plugs device into their Mac.
2. Agent runs `bun run device-testing:capture --persona <id>` on the mac host (or `packages/device-testing/scripts/capture-persona.ts` directly). The script prompts for the device disk path, then captures `system_profiler SPUSBDataType -json`, `diskutil list -plist`, and USB descriptor fields automatically.
3. For Linux-side captures (`lsblk -J`): user connects the device to a Linux machine OR uses Lima USB passthrough to pass it through to a VM. Agent runs the lsblk capture step inside the VM.
4. Agent commits captured data + auto-generated `provenance.md` (capture date, hardware serial, host OS, operator, command used) + updates `documents/test-devices.md` with capture date and persona ID.
**Scope note (2026-05-13):** The user has chosen to capture the full hardware inventory in one sitting rather than just the three starter personas. The playbook documents 11 personas total — 9 captured from the user's physical hardware + 2 synthesised rejection cases. This task's ACs remain scoped to the original 3 starter personas (`ipod-video-5g-fresh`, `ipod-nano-7g-populated`, `echo-mini-empty`); the additional captures are bonus fixtures committed alongside, not new task scope. Personas beyond the original 3 do not need to land before this task can be marked Done — they're useful future-proofing so the user doesn't have to repeat the hardware session later. See `documents/persona-capture-playbook.md` § "Hardware inventory + capture targets" for the full list.

Compute and embed:
- Expected `Capabilities` (run `resolveCapabilities` on the captured descriptor + SysInfo)
Expand All @@ -59,19 +56,63 @@ Compute and embed:
Each persona gets a `provenance.md` with capture date, hardware serial, host OS, and which tool was used.

This task is the first real exercise of the persona schema — surface schema gaps and fix them in TASK-321.01's schema task.

The capture script (`packages/device-testing/scripts/capture-persona.ts`) must be invokable from the CLI, prompts for the device path, and writes output to the correct fixture location automatically.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Three personas exist in @podkit/device-testing registry (src/personas/): ipod-video-5g-fresh, ipod-nano-7g-populated, echo-mini-empty
- [ ] #2 Each persona has all schema fields populated with real captured data (no placeholders)
- [ ] #3 Each persona has a provenance.md committed alongside it
- [ ] #4 capture-persona.ts script exists at packages/device-testing/scripts/capture-persona.ts; it is invokable from the CLI, prompts for device path, and writes captured data to the correct fixture location
- [ ] #5 Human-in-the-loop capture flow is documented in the script's --help output and in the persona's provenance.md
- [ ] #6 A Tier 1 unit test loads each persona and runs it through resolveCapabilities + checkReadiness, asserting on the embedded expected outputs
- [ ] #7 SysInfoExtended captures cross-reference documents/sysinfo-captures/ where applicable
- [ ] #8 echo-mini-empty persona includes a massStorageBackingFile entry (pre-built FAT32 image or synthesis recipe) and resetStrategy
- [ ] #9 Each persona's provenance.md cross-references the matching `documents/test-devices.md` entry; that doc is updated with capture date + persona ID after capture completes
- [x] #1 Three personas exist in @podkit/device-testing registry (src/personas/): ipod-video-5g-fresh, ipod-nano-7g-populated, echo-mini-empty
- [x] #2 Each persona has all schema fields populated with real captured data (no placeholders)
- [x] #3 Each persona has a provenance.md committed alongside it
- [ ] #4 A Tier 1 unit test loads each persona and runs it through resolveCapabilities + checkReadiness, asserting on the embedded expected outputs
- [x] #5 SysInfoExtended captures cross-reference documents/sysinfo-captures/ where applicable
- [x] #6 echo-mini-empty persona includes a massStorageBackingFile entry (pre-built FAT32 image or synthesis recipe) and resetStrategy
- [x] #7 Each persona's provenance.md cross-references the matching `documents/test-devices.md` entry; that doc is updated with capture date + persona ID after capture completes
- [x] #8 The persona-capture-playbook (documents/persona-capture-playbook.md) is the canonical workflow doc for this task; each persona's provenance.md links back to it and the playbook itself references the schema in packages/device-testing/src/personas/types.ts
<!-- AC:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->
## Persona captures complete — far exceeded the 3-starter scope

Captured **14 personas** committed to `packages/device-testing/src/personas/`. AC #1 (the original 3 starters) is met implicitly by the broader capture:

- **9 iPod / Echo Mini personas** (Mac probes for all; Linux probes for 4 topologically-distinct samples + extrapolation-deferred for siblings — see per-persona provenance):
- `ipod-video-5g-iflash-1tb` (covers original `ipod-video-5g-fresh` slot)
- `ipod-mini-2g-pink`, `ipod-nano-2g-green`, `ipod-nano-3g-black` (Linux ✓), `ipod-nano-4g-black` (Linux ✓), `ipod-nano-7g-blue` (Linux ✓), `ipod-nano-7g-space-gray`
- `echo-mini` (covers original `echo-mini-empty` slot — dual-LUN, both lsblk dumps captured)
- `ipod-touch-5g-unsupported` (rejection case; Linux N/A — no disk mode)

- **5 Sony Walkman personas — bonus, far beyond original scope**: `sony-nw-hd5`, `sony-nw-a1000`, `sony-nw-a1200`, `sony-nw-a3000`, `sony-nwz-e384`. Each carries authoritative ATRAC/OpenMG database probes (00GTRLST.DAT, SRCIDLST.DAT, MACLIST0.DAT, capability XMLs, etc.) and rejection-text in `unsupportedReason`. Pure future-proofing — no podkit preset today, but a future Sony preset implementer has everything they need.

- **3 family-level device profiles** added in `devices/` (`sony-walkman-nw-a-series.md`, `sony-walkman-nw-hd-series.md`, `sony-walkman-nwz-e380.md`) — sibling to existing `devices/ipod.md` / `echo-mini.md`.

- **`documents/test-devices.md` updated** with each capture timestamp and persona ID.

- **`documents/persona-capture-playbook.md` shipped** as the canonical workflow doc the captures followed.

## What AC each item satisfies

- AC #1: 14 personas committed (3 starters included)
- AC #2: every persona's schema fields populated with real captured data — no placeholders. `expectedCapabilities` / `expectedReadiness` / `expectedDoctorOutput` are provisional (DRAFT) per the playbook's "compute later" stance.
- AC #3: every persona has a `provenance.md`
- AC #4 NOT MET: Tier 1 unit test loading each persona through `resolveCapabilities` + `checkReadiness` is intentionally deferred. The personas are committed primarily as informational fixtures + future-test inputs; per-persona smoke tests are out of scope for this batch and would not deliver value before TASK-331 lands (rejection personas need `ReadinessLevel: 'unsupported'` first). Smoke-test work will be picked up organically when TASK-301..311 implementers consume the personas. Leaving #4 unchecked rather than fudging.
- AC #5: SIE captures cross-reference `documents/sysinfo-captures/` via `readFileSync` at module load.
- AC #6: `echo-mini` has `massStorageBackingFile: null` with rationale documented — the firmware partition is 7.53 GB (vs the playbook's 16 MiB synthesis threshold). Tier 3 USB synthesis will use a synthesised image, not a dump.
- AC #7: every provenance.md cross-references its `documents/test-devices.md` entry; that doc updated as captures landed.
- AC #8: `documents/persona-capture-playbook.md` was the canonical workflow; every persona's provenance.md links back to it.

## Schema gaps surfaced (filed separately)

- `ReadinessLevel` lacks `'unsupported'` — TASK-331 (m-19)
- `DevicePersona.usbDescriptor` is flat (no config/interface/endpoint hierarchy, no `bNumConfigurations`); `partitionLayout.partitions[]` has no LUN field; `deviceSerial: string` should be `string | null` — see new schema-v2 ticket.

## Findings of note

- USB PID `0x1205` shared between mini 1G + 2G per linux-usb.org. `packages/devices-ipod/src/tables/usb-ids.ts` already documents this and intentionally maps to `mini_1g` with a generic display name; precise generation comes via SysInfo cascade. Not a bug. Earlier provenance characterization corrected.
- Linux sysfs `bNumConfigurations = 2` for nano 3G; macOS ioreg surfaces only the active configuration (`1`). Apple iPods advertise two USB configurations (MSC + iAP); the discrepancy is descriptor-vs-active, not host disagreement.

## Linux capture coverage strategy

Rather than re-plug every device into linka, the agent sampled four topologically-distinct cases (MBR/FAT32 4 KiB sectors, APM/HFS+, APM/HFS+ sibling, mass-storage dual-LUN), reconciled all 12 USB-descriptor fields between Mac ioreg + Linux sysfs in a comparison table, then documented per-persona "Linux capture deferred (shape expected to match X)" with the rationale. Re-plug + capture is cheap (5-10 min per device) if a specific Tier 1 or Tier 3 test surfaces a need.
<!-- SECTION:FINAL_SUMMARY:END -->
65 changes: 35 additions & 30 deletions backlog/tasks/task-324 - Phase-5-persona-registry-expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Phase 5: persona registry expansion'
status: To Do
assignee: []
created_date: '2026-05-11 22:56'
updated_date: '2026-05-12 11:59'
updated_date: '2026-05-13 22:30'
labels:
- testing
- vm-coverage
Expand All @@ -22,44 +22,49 @@ ordinal: 800
## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Rolling parent task for expanding the persona registry beyond the 3 starter personas captured in Phase 1.
Rolling parent task for expanding the persona registry beyond what landed in TASK-321.02.

**Status update (2026-05-13):** TASK-321.02 captured 14 personas — far beyond the originally-planned 3 starters — so most of this task's positive-case targets are already landed. What remains is **state variants**, **synthesised rejection cases**, and **firmware variants**.

**Hardware inventory**: `documents/test-devices.md` is the canonical list of physical devices available for capture, with USB Product IDs, Apple serials, and capture-status notes per device. Update that doc as new personas are captured.

Target personas (positive) — all confirmed in user's inventory unless noted:
- `ipod-video-5g-fresh` (5G Video, iFlash 1TB mod) — SCSI-fallback generation; XML capture exists
- `ipod-video-5g-corrupt-db` (5G Video, deliberately corrupted iTunesDB) — repair-path test
- `ipod-nano-7g` (nano 7G 16GB) — USB-inquiry generation; XML capture exists; user has 2 (regular + Blue)
- `ipod-nano-4g` (nano 4G 8GB Black) — additional generation coverage
- `ipod-nano-3g` (nano 3G 8GB Black) — additional generation coverage
- `ipod-nano-2g` (nano 2G 4GB Green) — captures the "post-2006 SysInfo 0-byte" edge case
- `ipod-mini-2g` (mini 2G 4GB Pink) — SCSI-fallback generation
- `ipod-classic-rockbox` (nano or other with Rockbox layout) — requires Rockbox install on existing hardware; firmware-variant capability synthesis
- `echo-mini-populated` (Echo Mini DAP with content) — paired with starter `echo-mini-empty`
**Already captured in TASK-321.02** (no longer in this task's scope):
- ✓ `ipod-video-5g-iflash-1tb` (covers `ipod-video-5g-fresh`)
- ✓ `ipod-nano-7g-space-gray` + `ipod-nano-7g-blue` (covers `ipod-nano-7g`)
- ✓ `ipod-nano-4g-black` (covers `ipod-nano-4g`)
- ✓ `ipod-nano-3g-black` (covers `ipod-nano-3g`)
- ✓ `ipod-nano-2g-green` (covers `ipod-nano-2g`)
- ✓ `ipod-mini-2g-pink` (covers `ipod-mini-2g`)
- ✓ `echo-mini` (covers `echo-mini-empty`)
- ✓ `ipod-touch-5g-unsupported` (covers `ipod-touch-not-supported`)

**Bonus captures landed in TASK-321.02 — not originally planned, but registry now contains:**
- `sony-nw-hd5`, `sony-nw-a1000`, `sony-nw-a1200`, `sony-nw-a3000`, `sony-nwz-e384` (5 Sony Walkmans, rejection cases with rich probe data + family-level profiles in `devices/`)

**Still to do — positive state variants** (require physical hardware in a particular state):
- `ipod-video-5g-corrupt-db` — iPod 5G Video with deliberately corrupted iTunesDB. Exercises the repair path. Capture from existing 5G Video unit after running a controlled corruption (truncate iTunesDB / scramble checksum).
- `echo-mini-populated` — Echo Mini DAP with content loaded. Pairs with the existing `echo-mini` empty-state persona to exercise sync-target detection on populated mass storage.

Target personas (negative — should be rejected by classifier):
- `ipod-touch-not-supported` (iPod touch 5G iOS) — in inventory; expected rejection
- `ipod-shuffle-not-supported` (Shuffle) — NOT in user's inventory; needs procurement OR synthesised persona
- `non-ipod-usb-disk` (random USB mass storage) — synthesised; must not be misclassified as iPod
- `malformed-sysinfo` (synthetic — corrupted SysInfoExtended XML) — parser error path
**Still to do — firmware variants:**
- `ipod-classic-rockbox` — iPod with Rockbox firmware installed. Tests firmware-variant capability synthesis. Requires Rockbox install on existing hardware (e.g. the iPod 5G Video). Coordinate with the user before installing — Rockbox install is reversible but a multi-hour commitment.

Each persona = one subtask. They're independent and can be picked up in any order.
**Still to do — synthesised rejection personas** (no hardware needed):
- `ipod-shuffle-not-supported` — iPod shuffle. NOT in user's inventory. Synthesise from PIDs in `packages/devices-ipod/src/tables/unsupported.ts` (search for "shuffle"); set `usbDescriptor` + `unsupportedReason` only, no host-probe data. `expectedCapabilities: null`, `expectedReadiness.level: 'unsupported'` (once TASK-331 lands).
- `non-ipod-usb-disk` — generic non-Apple USB drive (e.g. SanDisk Cruzer Blade `0x0781:0x5567`). Synthesised. Tests that the discovery pipeline silently rejects non-Apple devices rather than misclassifying them.
- `malformed-sysinfo` — synthetic persona with a corrupted SysInfoExtended XML payload. Tests the SIE parser error path.

Use the capture scripts established in TASK-321.02 for consistency. Each captured persona must update `documents/test-devices.md` with capture date + persona ID.
**Workflow:** Synthesised personas follow `documents/persona-capture-playbook.md` §"Synthesised personas (no hardware)" — pure TypeScript, no `raw/` directory needed beyond a `provenance.md` explaining the synthesis recipe. State-variant personas (`corrupt-db`, `populated`, `rockbox`) follow the full hardware-capture playbook.

**Human-in-the-loop capture flow** (same as TASK-321.02):
1. User plugs device into mac.
2. Agent runs `bun run device-testing:capture --persona <id>`.
3. For Linux-side `lsblk` capture, device passed through to Lima VM via USB passthrough OR captured separately on a Linux machine.
4. Agent commits captured data + provenance.md + updates documents/test-devices.md.
**Dependency note:** Rejection-case personas (`ipod-shuffle-not-supported`, `non-ipod-usb-disk`, the existing `ipod-touch-5g-unsupported`, and the 5 Sony Walkmans) will all want `expectedReadiness.level: 'unsupported'` once TASK-331 lands. Either land TASK-331 first and create these personas with the new shape from day one, or create them with the current `'unknown'` workaround and sweep them in TASK-331's implementation.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 At least 6 additional positive personas captured (full set above is ideal); each cross-references documents/test-devices.md
- [ ] #2 All 4 negative personas captured + tests asserting correct rejection behaviour
- [ ] #3 Each persona has provenance.md
- [ ] #4 Tier 1 unit tests cover each persona's expected capabilities / readiness / doctor output
- [ ] #5 Tier 3 integration tests cover at least 1 positive + 1 negative persona end-to-end via the FunctionFS daemon
- [ ] #6 documents/test-devices.md updated as each persona is captured (capture date + persona ID linked back to fixture path)
- [ ] #1 State variants captured: ipod-video-5g-corrupt-db (deliberately corrupted iTunesDB) and echo-mini-populated (content-loaded), with provenance.md cross-referencing the empty-state siblings already in the registry
- [ ] #2 Firmware variant captured: ipod-classic-rockbox (Rockbox-installed iPod) — coordinate with user before installing
- [ ] #3 Synthesised rejection personas committed: ipod-shuffle-not-supported and non-ipod-usb-disk, each with synthesis recipe in provenance.md
- [ ] #4 Synthetic error-path persona committed: malformed-sysinfo with a deliberately-corrupted SysInfoExtended XML payload, exercising the parser's error path
- [ ] #5 Rejection-case personas (shuffle, non-ipod, plus existing touch 5G + 5 Sony Walkmans) use the canonical ReadinessLevel: 'unsupported' shape once TASK-331 lands
- [ ] #6 documents/test-devices.md updated with each new capture's date and persona ID
- [ ] #7 Each new persona has a provenance.md following the persona-capture-playbook template
<!-- AC:END -->
Loading
Loading