cc-handguard: Shared Latent Stream Architecture
**Issues**: - ❌ Double battery drain on watch - ❌ Two separate upload streams - ❌ Two device IDs in backend - ❌ Two latent computations for same physical motion - ❌ Wasteful and redundant
Full Public Reader
cc-handguard: Shared Latent Stream Architecture
Date: 2025-12-15
Status: 🎯 RECOMMENDED APPROACH
---
The Problem: Redundant Sensor Streams
Current Implementation
Apple Watch (100Hz sensors)
↓
├─→ EchelonCapture → Upload → CC-MCS device_1 → Latent stream 1
└─→ HandGuard → Upload → CC-MCS device_2 → Latent stream 2Issues:
- ❌ Double battery drain on watch
- ❌ Two separate upload streams
- ❌ Two device IDs in backend
- ❌ Two latent computations for same physical motion
- ❌ Wasteful and redundant
---
The Solution: Single Upload, Multiple Policies
Shared Latent Architecture
┌────────────────────────────────────────────────────────────┐
│ Apple Watch │
│ Single 100Hz sensor stream │
└───────────────────────────┬────────────────────────────────┘
│
↓
┌────────────────────────────────────────────────────────────┐
│ iPhone Gateway │
│ (EchelonCapture OR HandGuard OR Shared) │
│ │
│ Option A: EchelonCapture handles upload │
│ Option B: HandGuard handles upload │
│ Option C: Shared "Sensor Gateway" app │
└───────────────────────────┬────────────────────────────────┘
│ Single upload stream
↓
┌────────────────────────────────────────────────────────────┐
│ CC-MCS-Headless (Cloud Backend) │
│ │
│ Input: Single device_id stream │
│ Process: LIM-RPS solver → z(t) latent state │
│ Output: Broadcast z(t) to ALL WebSocket subscribers │
└───────────────────────────┬────────────────────────────────┘
│
┌───────────┴───────────┐
↓ ↓
┌────────────────────┐ ┌────────────────────┐
│ EchelonCapture │ │ HandGuard │
│ (Policy Client) │ │ (Policy Client) │
│ │ │ │
│ Receives z(t) │ │ Receives z(t) │
│ Applies Echelon │ │ Applies nail- │
│ policy │ │ biting policy │
│ Controls music │ │ Fires haptics │
└────────────────────┘ └────────────────────┘Benefits:
- ✅ Single sensor stream (50
- ✅ Single upload stream (50
- ✅ One device_id in backend
- ✅ Same z(t) latent state for all policies
- ✅ True "latent-first" philosophy
- ✅ Can run multiple policy apps simultaneously
---
Implementation Options
Option A: EchelonCapture as Gateway (Easiest)
Concept: EchelonCapture already uploads sensors. Add a local broadcast so HandGuard can subscribe.
Apple Watch
↓ (WatchConnectivity)
iPhone: EchelonCapture
├─→ Upload to CC-MCS (existing code)
└─→ Local broadcast on [ip]:9001 (NEW)
↓
iPhone: HandGuard
├─→ Subscribe to local latent stream ws://[ip]:9001
└─→ Apply nail-biting policy
└─→ Send interventions to watchChanges Required:
EchelonCapture (minimal):
1. Add local WebSocket server on port 9001
2. Broadcast latent states locally
3. ~50 lines of code
HandGuard:
1. Change `CCLatentSubscriber` to connect to `ws://[ip]:9001` instead of cloud
2. Remove `CCBridgeManager` (no upload needed)
3. Keep `HandGuardPolicy` and intervention logic
4. ~30 lines changed
Pros:
- ✅ Minimal changes
- ✅ EchelonCapture proven stable
- ✅ HandGuard becomes lightweight policy-only app
Cons:
- ❌ Requires EchelonCapture to be running
- ❌ HandGuard can't work standalone
---
Option B: HandGuard as Gateway (Current)
Concept: HandGuard uploads sensors (as currently built). EchelonCapture subscribes to same device_id.
Apple Watch
↓ (WatchConnectivity)
iPhone: HandGuard
├─→ Upload to CC-MCS (current code)
└─→ Subscribe to cloud latent stream
└─→ Apply nail-biting policy
iPhone: EchelonCapture (MODIFIED)
└─→ Subscribe to same device_id latent stream
└─→ Apply Echelon policy
└─→ Control musicChanges Required:
HandGuard: No changes (current implementation)
EchelonCapture:
1. Remove sensor upload code
2. Subscribe to HandGuard's device_id WebSocket stream
3. ~50 lines changed
Pros:
- ✅ Current HandGuard code works as-is
- ✅ HandGuard works standalone
Cons:
- ❌ Requires modifying EchelonCapture
- ❌ EchelonCapture becomes dependent on HandGuard
---
Option C: Shared Sensor Gateway App (Best Long-Term)
Concept: Create a lightweight "CC Sensor Gateway" app that ONLY handles upload. Both EchelonCapture and HandGuard become pure policy clients.
Apple Watch
↓ (WatchConnectivity)
iPhone: CC Sensor Gateway (NEW APP)
└─→ Upload to CC-MCS only
└─→ No policy logic
└─→ Minimal UI (connection status)
CC-MCS broadcasts z(t)
↓
┌──────────┴──────────┐
↓ ↓
iPhone: EchelonCapture iPhone: HandGuard
(Policy only) (Policy only)Changes Required:
New App: CC Sensor Gateway (~500 lines)
1. WatchConnectivityManager
2. CCBridgeManager (upload only)
3. Simple status UI
EchelonCapture:
1. Remove upload code
2. Pure policy client
HandGuard:
1. Remove CCBridgeManager
2. Pure policy client
Pros:
- ✅ Clean separation of concerns
- ✅ Both policy apps lightweight
- ✅ Easy to add new policy apps
- ✅ Gateway can run in background
Cons:
- ❌ Requires building new app
- ❌ More initial work
---
Recommended Approach
Phase 1: Current (Keep As-Is for Now) ✅
Status: What we've built
- HandGuard works standalone
- Upload + policy in same app
- Can test and validate immediately
- Deploy this first, get it working
Phase 2: Shared Device ID (Quick Win)
After HandGuard is deployed and working:
1. Deploy HandGuard with fixed device_id:
// In CCBridgeManager.swift
let deviceID = "watch-primary" // Hardcoded2. Modify EchelonCapture to subscribe to same device_id:
// In EchelonCapture latent subscriber
let wsURL = "wss://cc-mcs-headless.../latent?device_id=watch-primary"3. Result: Both apps receive same latent state, different policies
- EchelonCapture still uploads (redundant but harmless)
- Both subscribe to same stream
- ~10 minute change
Phase 3: Gateway App (Future)
After validating shared latent works:
1. Build CC Sensor Gateway app
2. Migrate both apps to pure policy clients
3. Proper architecture
---
Implementation: Phase 2 (Recommended Next)
Let me modify the current HandGuard code to use a shared device_id:
Change 1: Fixed Device ID
File: `cc-handguard/Services/CloudBridge/CCBridgeManager.swift`
// Line ~30
private let deviceID = "watch-primary" // Changed from UUID
// Remove this:
// private let deviceID = UUID().uuidStringChange 2: Document Device ID
File: `cc-handguard/Services/CloudBridge/CCLatentSubscriber.swift`
// Line ~25
private let deviceID = "watch-primary" // Must match CCBridgeManager
init() {
// Connect to shared device stream
let urlString = "\(baseURL)/latent?device_id=\(deviceID)"
// ...
}Change 3: Update EchelonCapture
In EchelonCapture codebase (separate change):
# In latent_subscriber.py or equivalent
DEVICE_ID = "watch-primary" # Match HandGuard
ws_url = f"wss://cc-mcs-headless.../latent?device_id={DEVICE_ID}"Result
Apple Watch → HandGuard uploads as "watch-primary"
↓
CC-MCS processes stream
↓
Broadcasts z(t) for "watch-primary"
↓
┌───────────┴───────────┐
↓ ↓
HandGuard EchelonCapture
(subscribed to (subscribed to
watch-primary) watch-primary)Both receive same z(t), apply different policies.
---
Code Changes for Shared Device ID
Want me to implement Phase 2 now? I can:
1. ✅ Update CCBridgeManager with fixed device_id
2. ✅ Update CCLatentSubscriber with same device_id
3. ✅ Add configuration file for device_id
4. ✅ Document how to configure EchelonCapture to use same device_id
This is a 10-minute change that eliminates the redundancy concern while keeping HandGuard functional.
---
Summary
Current: HandGuard uploads + subscribes (works standalone) ✅
Phase 2 (Recommended): Shared device_id
- HandGuard uploads as "watch-primary"
- EchelonCapture subscribes to "watch-primary"
- Both receive same z(t)
- 10-minute change
Phase 3 (Future): Gateway app
- Separate upload from policy
- Clean architecture
- Easy to add new apps
---
Decision Point
Question: Do you want to:
A) Keep current architecture (deploy HandGuard standalone) - READY NOW
B) Switch to shared device_id (10-minute change) - ELIMINATES REDUNDANCY
C) Build gateway app first (1-2 hours) - BEST LONG-TERM
I recommend A first (deploy and test), then B after verification.
What do you prefer?
Promotion Decision
Promote into a technical note or architecture paper with implementation anchors.
Source Anchor
Comp-Core/apps/ios/cc-handguard/SHARED_LATENT_ARCHITECTURE.md
Detected Structure
Method · Evaluation · Figures · Code Anchors · Architecture