Skip to content

Commit 1a15f3e

Browse files
Mark Stalzerclaude
andcommitted
Add EARS specs, arrow docs, and @SPEC annotations (Phase 5 LID bootstrap)
Phase 5 of the brownfield linked-intent-dev bootstrap. Adds: - docs/specs/: 5 EARS spec files (~155 specs total, prefixes LPI/DDS/TE/LI/LB) - docs/arrows/: 5 arrow docs + index.yaml (all at MAPPED status) - @SPEC annotations in 9 key source files linking code to spec IDs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent dcc4092 commit 1a15f3e

20 files changed

Lines changed: 789 additions & 1 deletion

docs/arrows/device-driver-stack.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Arrow: device-driver-stack
2+
3+
Produces raw sensor events (light pulses, IMU, config, buttons) from physical hardware, recorded sessions, or synthetic sources via a unified plugin interface.
4+
5+
## Status
6+
7+
**MAPPED** - 2026-04-12. Full LLD written from brownfield reconnaissance. EARS specs written. Vive USB driver is mature; simulator is sparse; usbmon implementation details unclear.
8+
9+
## References
10+
11+
### HLD
12+
- [docs/high-level-design.md](../high-level-design.md) — "Architecture Overview", "The Hook System"
13+
14+
### LLD
15+
- [docs/llds/device-driver-stack.md](../llds/device-driver-stack.md)
16+
17+
### EARS
18+
- [docs/specs/device-driver-stack-specs.md](../specs/device-driver-stack-specs.md) (28 specs)
19+
20+
### Tests
21+
- src/test_cases/watchman.c
22+
- src/test_cases/test_replays.c (exercises playback driver)
23+
- src/test_cases/export_config.c
24+
25+
### Code
26+
- src/driver_vive.c, src/driver_vive.h
27+
- src/driver_vive.config.h, src/driver_vive.hidapi.h, src/driver_vive.libusb.h
28+
- src/driver_gatt.c
29+
- src/driver_playback.c
30+
- src/driver_simulator.c
31+
- src/driver_udp.c
32+
- src/driver_dummy.c
33+
- src/driver_usbmon.c
34+
- src/driver_openvr.cc
35+
- src/driver_global_scene_solver.c
36+
- redist/hidapi.h, redist/hid-linux.c, redist/hid-osx.c, redist/hid-windows.c
37+
38+
## Architecture
39+
40+
**Purpose:** Translate hardware reality (USB, BLE, network, files) into `LightcapElement` and IMU events that the Protocol Intelligence cluster can process.
41+
42+
**Key Components:**
43+
1. `driver_vive.c` — Primary USB driver for all HTC Vive / Valve Index family hardware
44+
2. `driver_vive.config.h` — Async state machine for device initialization (MAGICS→CONFIG→VERSION→IMU_SCALES)
45+
3. `driver_gatt.c` — Bluetooth LE lighthouse power/mode control
46+
4. `driver_playback.c``.rec.gz` session replay for offline development and regression testing
47+
5. `driver_global_scene_solver.c` — Passive calibration trigger (registered as driver, performs optimization work)
48+
6. `redist/hidapi.*` — Cross-platform HID device access layer
49+
50+
## EARS Coverage
51+
52+
| Category | Spec IDs | Implemented | Gaps | Deferred |
53+
|----------|----------|-------------|------|----------|
54+
| Driver interface contract | DDS-API-001 to 006 | 6 | 0 | 0 |
55+
| Vive USB driver | DDS-BE-010 to 017 | 8 | 0 | 0 |
56+
| GATT lighthouse control | DDS-BE-020 to 023 | 4 | 0 | 0 |
57+
| Playback driver | DDS-BE-030 to 034 | 5 | 0 | 0 |
58+
| UDP driver | DDS-BE-040 to 042 | 3 | 0 | 0 |
59+
| Global scene solver | DDS-BE-050 to 054 | 4 | 1 | 0 |
60+
61+
**Summary:** 30 of 31 active specs implemented; 1 active gap; 0 deferred.
62+
63+
## Key Findings
64+
65+
1. **`driver_global_scene_solver` is architecturally misplaced** — Registered as a driver plugin but directly calls Tracking Engine poser functions (`src/driver_global_scene_solver.c`). This is the only place where the Driver Stack bypasses the hook system to call into the Tracking Engine. (DDS-BE-050)
66+
67+
2. **Config chunk off-by-two is a silent quirk** — Vive firmware advertises config length N but delivers N+2 bytes. The driver adds 2 silently; this is not documented for anyone implementing a new USB backend. (`src/driver_vive.config.h`)
68+
69+
3. **`driver_simulator.c` is sparse** — The file registers `DriverRegSimulator` but the implementation is minimal. Not usable for algorithm development in current state.
70+
71+
4. **`driver_usbmon.c` behavior undetermined** — The file exists and builds but its input format and protocol are not documented in source.
72+
73+
5. **GATT mode write has no readback** — After writing a mode to a lighthouse via GATT, there is no confirmation read. Silent failures are undetectable. (DDS-BE-022)
74+
75+
## Work Required
76+
77+
### Must Fix
78+
1. Add GSS solve-failure rejection path — if global scene solver result error exceeds threshold, retain previous calibration (DDS-BE-054)
79+
80+
### Should Fix
81+
2. Document `driver_usbmon.c` — what format it consumes and how to use it
82+
3. Document the off-by-two config length quirk in a comment visible to future USB backend implementors
83+
4. Evaluate `driver_simulator.c` — either complete it or mark it as unfinished
84+
85+
### Nice to Have
86+
5. Add GATT mode write confirmation readback (DDS-BE-022)
87+
6. Consider moving `driver_global_scene_solver` to the Tracking Engine cluster to eliminate the cross-cluster direct call

docs/arrows/index.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
schema_version: 1
2+
last_updated: 2026-04-12
3+
4+
arrows:
5+
lighthouse-protocol-intelligence:
6+
status: MAPPED
7+
sampled: 2026-04-12
8+
audited: null
9+
blocks: []
10+
blockedBy: []
11+
detail: lighthouse-protocol-intelligence.md
12+
next: "Complete Gen2 processing path and remove debug fprintf calls from lfsr_lh2.c"
13+
drift: "Gen2 path (survive_process_gen2.c) is nearly empty; LFSR decoder has debug output"
14+
15+
device-driver-stack:
16+
status: MAPPED
17+
sampled: 2026-04-12
18+
audited: null
19+
blocks: []
20+
blockedBy: []
21+
detail: device-driver-stack.md
22+
next: "Add GSS solve-failure rejection and document driver_usbmon.c"
23+
drift: "driver_global_scene_solver makes direct cross-cluster call into Tracking Engine"
24+
25+
tracking-engine:
26+
status: MAPPED
27+
sampled: 2026-04-12
28+
audited: null
29+
blocks: []
30+
blockedBy: []
31+
detail: tracking-engine.md
32+
next: "Add CI guard for src/generated/ divergence from Python symbolic sources"
33+
drift: "Generated math files committed without verification against Python sources"
34+
35+
library-infrastructure:
36+
status: MAPPED
37+
sampled: 2026-04-12
38+
audited: null
39+
blocks: []
40+
blockedBy: []
41+
detail: library-infrastructure.md
42+
next: "Document survive_close() threading constraint; add Simple API event drop counter"
43+
drift: null
44+
45+
language-bindings:
46+
status: MAPPED
47+
sampled: 2026-04-12
48+
audited: null
49+
blocks: []
50+
blockedBy: []
51+
detail: language-bindings.md
52+
next: "Fix Unity coordinate handedness bug and ROS timecode wraparound"
53+
drift: "Unity rotation mapping is wrong (handedness); ROS timestamps overflow at 89s"

docs/arrows/language-bindings.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Arrow: language-bindings
2+
3+
Exposes libsurvive tracking to Python, C#/Unity, ROS, OpenVR, and browser-based visualization.
4+
5+
## Status
6+
7+
**MAPPED** - 2026-04-12. Full LLD written from brownfield reconnaissance. EARS specs written. Python and C# bindings are functional but have precision-mismatch and staleness risks. Unity coordinate conversion is broken. ROS has a timecode wraparound bug.
8+
9+
## References
10+
11+
### HLD
12+
- [docs/high-level-design.md](../high-level-design.md) — "Non-Goals / Synchronize to wall clock"
13+
14+
### LLD
15+
- [docs/llds/language-bindings.md](../llds/language-bindings.md)
16+
17+
### EARS
18+
- [docs/specs/language-bindings-specs.md](../specs/language-bindings-specs.md) (26 specs)
19+
20+
### Tests
21+
- bindings/python/examples/ (manual integration examples)
22+
- bindings/cs/Demo/Program.cs
23+
24+
### Code
25+
- bindings/python/pysurvive/
26+
- bindings/cs/libsurvive.net/, bindings/cs/Demo/, bindings/cs/UnityViewer/
27+
- tools/ros_publisher/
28+
- tools/openvr_driver/
29+
- tools/viz/
30+
31+
## Architecture
32+
33+
**Purpose:** Translate libsurvive's C API into idioms natural to each target language or platform, with no tracking logic of their own.
34+
35+
**Key Components:**
36+
1. `pysurvive/pysurvive_generated.py` — ctypesgen-produced raw C bindings
37+
2. `pysurvive/__init__.py` — Pythonic wrapper: SimpleContext, callbacks, argument parser
38+
3. `pysurvive/recorder.py` — In-session data collection and matplotlib analysis
39+
4. `bindings/cs/libsurvive.net/` — C# DllImport layer + SurviveAPI + SurviveContext
40+
5. `bindings/cs/UnityViewer/` — Unity MonoBehaviour for real-time 3D tracking visualization
41+
6. `tools/ros_publisher/` — ROS topic publisher (pose, joy, IMU) per tracked object
42+
7. `tools/openvr_driver/` — Outbound OpenVR runtime driver (libsurvive → SteamVR)
43+
8. `tools/viz/` — Three.js web visualization via WebSocket
44+
45+
## EARS Coverage
46+
47+
| Category | Spec IDs | Implemented | Gaps | Deferred |
48+
|----------|----------|-------------|------|----------|
49+
| Python bindings | LB-API-001 to 006 | 4 | 2 | 0 |
50+
| Python data recording | LB-BE-010 to 012 | 3 | 0 | 0 |
51+
| C# / .NET bindings | LB-API-020 to 024 | 4 | 1 | 0 |
52+
| Unity integration | LB-API-030 to 031 | 1 | 1 | 0 |
53+
| ROS integration | LB-API-040 to 044 | 3 | 2 | 0 |
54+
| OpenVR runtime driver | LB-API-050 to 052 | 2 | 1 | 0 |
55+
| Web visualization | LB-API-060 to 062 | 2 | 1 | 0 |
56+
57+
**Summary:** 19 of 26 active specs implemented; 8 active gaps; 0 deferred.
58+
59+
## Key Findings
60+
61+
1. **Unity coordinate handedness is broken**`SurviveObject.cs` maps libsurvive quaternion components to Unity transforms without applying the right-hand → left-hand conversion. Object rotations are mirrored in Unity. (`bindings/cs/UnityViewer/Assets/SurviveObject.cs`, LB-API-031)
62+
63+
2. **Python and C# bindings assume FLT=double** — Both binding layers hardcode `double` for pose structs. Compiling libsurvive with `USE_SINGLE_PRECISION=ON` produces silently wrong values in all bindings. (LB-API-005, LB-API-024)
64+
65+
3. **`pysurvive_generated.py` can silently go stale** — No CI step regenerates or validates it against current headers. API changes in C are invisible to Python users until the next manual regeneration. (LB-API-006)
66+
67+
4. **ROS timecode wraps every ~89 seconds** — The 32-bit 48 MHz USB timecode overflows every 89 seconds. The ROS publisher does not handle wraparound, causing ROS time to jump backward during long sessions. (LB-API-043)
68+
69+
5. **ROS coordinate frame not converted** — Published poses are in libsurvive's native coordinate frame. ROS REP-103 expects X-forward, Y-left, Z-up. Standard ROS navigation and manipulation stacks will interpret poses incorrectly. (LB-API-044)
70+
71+
6. **OpenVR coordinate transform is session-scoped** — Computed once at startup via Kabsch; not recomputed if lighthouse positions change mid-session. (LB-API-052)
72+
73+
7. **Web viz WebSocket port is hardcoded**`survive_viewer.js` connects to a fixed port. Multiple concurrent libsurvive instances require source edits. (LB-API-062)
74+
75+
## Work Required
76+
77+
### Must Fix
78+
1. Fix Unity coordinate system conversion in `SurviveObject.cs` — apply right-hand to left-hand transform on quaternion (LB-API-031)
79+
2. Fix ROS timecode wraparound — detect 32-bit overflow and maintain monotonic timestamps (LB-API-043)
80+
81+
### Should Fix
82+
3. Add FLT precision check in Python bindings at import time — raise error if struct sizes don't match (LB-API-005)
83+
4. Add ROS REP-103 coordinate frame conversion to `tools/ros_publisher/` (LB-API-044)
84+
5. Add CI step to regenerate and diff `pysurvive_generated.py` (LB-API-006)
85+
6. Make WebSocket port configurable in `survive_viewer.js` (LB-API-062)
86+
87+
### Nice to Have
88+
7. Add mid-session coordinate transform recomputation to OpenVR driver on re-calibration event (LB-API-052)
89+
8. Add C# struct size validation test (LB-API-024)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Arrow: library-infrastructure
2+
3+
Provides context lifecycle, hook routing, configuration, plugin loading, recording, device factory, and both the low-level hook API and high-level Simple API.
4+
5+
## Status
6+
7+
**MAPPED** - 2026-04-12. Full LLD written from brownfield reconnaissance. EARS specs written. Core infrastructure is stable and well-tested. Key gaps: broken hook chain detection, event queue overflow visibility.
8+
9+
## References
10+
11+
### HLD
12+
- [docs/high-level-design.md](../high-level-design.md) — "The Hook System: Connective Tissue", "Cross-Cutting Concerns"
13+
14+
### LLD
15+
- [docs/llds/library-infrastructure.md](../llds/library-infrastructure.md)
16+
17+
### EARS
18+
- [docs/specs/library-infrastructure-specs.md](../specs/library-infrastructure-specs.md) (29 specs)
19+
20+
### Tests
21+
- src/test_cases/main.c, src/test_cases/test_case.h
22+
- src/test_cases/str.c
23+
- src/test_cases/export_config.c
24+
- src/test_cases/test_replays.c
25+
26+
### Code
27+
- src/survive.c, src/survive_api.c
28+
- src/survive_config.c, src/survive_config.h
29+
- src/survive_plugins.c, src/survive_driverman.c
30+
- src/survive_recording.c, src/survive_recording.h
31+
- src/survive_default_devices.c
32+
- src/survive_str.c, src/survive_buildinfo.c, src/survive_gz.h
33+
- src/survive_internal.h, src/survive_private.h
34+
- include/libsurvive/
35+
- redist/ (non-HID)
36+
- src/test_cases/
37+
38+
## Architecture
39+
40+
**Purpose:** Provide the runtime environment — context, hooks, config, plugins, recording — that all other clusters run inside.
41+
42+
**Key Components:**
43+
1. `survive.c` — Context init/poll/close; default hook implementations; button servicer thread
44+
2. `survive_api.c` — Simple API: background poll thread, event queue, object wrappers
45+
3. `survive_config.c` — Static-time registration + runtime access + file persistence
46+
4. `survive_plugins.c` — Retry-based `.so`/`.dll` discovery and loading
47+
5. `survive_recording.c` — Hook-intercepting recorder to `.rec.gz`
48+
6. `survive_default_devices.c``SurviveObject` factory from JSON config blobs
49+
7. `redist/os_generic.h` — Portable threads/mutexes/semaphores/timing
50+
51+
## EARS Coverage
52+
53+
| Category | Spec IDs | Implemented | Gaps | Deferred |
54+
|----------|----------|-------------|------|----------|
55+
| Context lifecycle | LI-API-001 to 005 | 4 | 1 | 0 |
56+
| Hook system | LI-BE-010 to 013 | 3 | 1 | 0 |
57+
| Configuration system | LI-BE-020 to 024 | 5 | 0 | 0 |
58+
| Plugin system | LI-BE-030 to 033 | 3 | 1 | 0 |
59+
| Device factory | LI-BE-040 to 042 | 3 | 0 | 0 |
60+
| Simple API | LI-API-050 to 053 | 3 | 1 | 0 |
61+
| Recording system | LI-BE-060 to 063 | 3 | 1 | 0 |
62+
| Threading | LI-BE-070 to 072 | 3 | 0 | 0 |
63+
64+
**Summary:** 27 of 29 active specs implemented; 6 active gaps; 0 deferred.
65+
66+
## Key Findings
67+
68+
1. **Hook chaining is silently fragile** — Callers who install hooks but fail to chain to the previous handler silently break recording, the Simple API queue, and downstream processing. No runtime detection exists. (LI-BE-013)
69+
70+
2. **Simple API event queue overflows silently** — Events are dropped without any counter or notification to the application. High button-event rates or slow consumers lose data invisibly. (LI-API-053)
71+
72+
3. **`survive_close()` thread-safety undocumented** — The context mutex is recursive but not cross-thread-safe for close. Calling `survive_close()` from a callback thread can deadlock. No documentation warns against this. (LI-API-005)
73+
74+
4. **Plugin failure diagnostics are weak** — When a plugin fails all load retries, the error message does not identify the missing symbol. Debugging new plugin dependencies requires manual `dlopen` inspection. (LI-BE-033)
75+
76+
5. **`json_helpers.c` destructive parsing is undocumented** — The parser modifies its input string in-place. This is a correctness trap for callers who pass string literals or shared buffers. (`redist/json_helpers.c`)
77+
78+
## Work Required
79+
80+
### Must Fix
81+
1. Document `survive_close()` threading constraint — must be called from the init thread (LI-API-005)
82+
83+
### Should Fix
84+
2. Add overflow counter to Simple API event queue so callers can detect dropped events (LI-API-053)
85+
3. Add debug-mode broken hook chain detection — warn when a hook is installed without chaining (LI-BE-013)
86+
4. Improve plugin load failure diagnostics to identify the missing symbol (LI-BE-033)
87+
5. Document `json_helpers.c` destructive parsing in the header
88+
89+
### Nice to Have
90+
6. Add recording-open failure error path with graceful disable (LI-BE-063)
91+
7. Consider raising the 32-driver limit or making it dynamic (LI-BE-032)

0 commit comments

Comments
 (0)