Anticipation
**Version**: 1.1.0 **Last Updated**: 2025-01-01 **Status**: Production **Parent**: [03-ECHELON.md](03-ECHELON.md) **Previous**: [05-SENSOR_FUSION.md](05-SENSOR_FUSION.md) **Next**: [07-GESTURE_RECOGNITION.md](07-GESTURE_RECOGNITION.md) **Crate**: `core/cc-anticipation/` **Tests**: 50 passing
Full Public Reader
Anticipation
Layer 2: Anticipatory Signal Extraction
Version: 1.1.0
Last Updated: 2025-01-01
Status: Production
Parent: [03-ECHELON.md](03-ECHELON.md)
Previous: [05-SENSOR_FUSION.md](05-SENSOR_FUSION.md)
Next: [07-GESTURE_RECOGNITION.md](07-GESTURE_RECOGNITION.md)
Crate: `core/cc-anticipation/`
Tests: 50 passing
---
Overview
The `cc-anticipation` crate converts stabilized motion windows into anticipatory signals. Unlike reactive systems that trigger on gesture completion, anticipation operates on the pre-completion phase of motion.
Core Concept
This is the key insight of Computational Choreography: we don't wait for motion to complete. We detect when motion becomes irreversible and act on intention rather than completion.
See: [01-COMPUTATIONAL_CHOREOGRAPHY.md](01-COMPUTATIONAL_CHOREOGRAPHY.md) for the philosophical foundation.
---
Core Insight
The key insight of anticipation is that commitment and uncertainty provide a two-dimensional space for proactive decision-making:
| Commitment | Uncertainty | State | System Response |
|---|---|---|---|
| Low | High | Waiting | Many options, observe |
| Medium | Medium | Preparing | Narrowing, prepare response |
| High | Low | Committed | Motion locked, execute |
| High | High | Surprising | Unexpected, adapt quickly |
---
Architecture
flowchart TB
subgraph Input [Input]
MW[MotionWindow]
end
subgraph Features [Feature Extraction]
KF[Kinematic Features]
LF[Latent Features]
Fuse[Feature Fusion]
end
subgraph Scalars [Scalar Computation]
C[Commitment]
U[Uncertainty]
TP[Transition Pressure]
RM[Recovery Margin]
PS[Phase Stiffness]
N[Novelty]
S[Stability]
end
subgraph Vectors [Vector Outputs]
RE[Regime Embedding]
CV[Constraint Vector]
DS[Derivative Summary]
end
subgraph Output [Output]
AP[AnticipationPacket]
end
MW --> KF
MW --> LF
KF --> Fuse
LF --> Fuse
Fuse --> C
Fuse --> U
C --> TP
U --> TP
Fuse --> RM
KF --> PS
Fuse --> RE
RE --> N
LF --> S
KF --> CV
Fuse --> DS
C --> AP
U --> AP
TP --> AP
RM --> AP
PS --> AP
N --> AP
S --> AP
RE --> AP
CV --> AP
DS --> AP---
Input Contract: MotionWindow
pub struct MotionWindow {
pub window_id: String, // Deterministic hash
pub t_start: f64, // Start time (server canonical)
pub t_end: f64, // End time
pub fps: f32, // Frame rate (50 Hz typical)
pub skeleton_frames: Vec<SkeletonFrame>,
pub latent_frames: Vec<LatentFrame>,
pub coverage: f32, // Fraction valid [0, 1]
pub device_offsets: HashMap<String, f64>,
pub dropped_reason: Option<String>,
}SkeletonFrame
pub struct SkeletonFrame {
pub timestamp: f64,
pub root_position: Vec3,
pub root_rotation: Quat,
pub bone_rotations: [Quat; 27], // MOCOPI_BONE_COUNT
pub valid: bool,
pub source_seq: Option<u64>,
}---
Output Contract: AnticipationPacket
pub struct AnticipationPacket {
// === Scalars (control-ready) ===
/// How irreversible the current motion has become [0-1]
pub commitment: f32,
/// How many plausible futures remain [0-1]
pub uncertainty: f32,
/// Rate at which futures are collapsing [-∞, +∞]
pub transition_pressure: f32,
/// Distance to balance/attractor loss [0-1]
pub recovery_margin: f32,
/// How locked to internal metronome [0-1]
pub phase_stiffness: f32,
/// Distance from recent regimes [0-1]
pub novelty: f32,
/// Local stationarity of dynamics [0-1]
pub stability: f32,
// === Vectors (query/conditioning) ===
/// Regime embedding (64-256 dims)
pub regime_embedding: Vec<f32>,
/// Constraint vector (~8 dims)
pub constraint_vector: Vec<f32>,
/// Derivative summary (~8 dims)
pub derivative_summary: Vec<f32>,
// === Provenance ===
pub window_id: String,
pub timestamp: f64,
pub schema_version: String, // "0.1.0"
// === Debug ===
pub debug: Option<DebugTrace>,
}---
Scalar Computations
Commitment
Commitment measures how irreversible the current motion has become.
Inputs: Uncertainty, constraint vector, fused features
Algorithm:
commitment = 1.0 - uncertainty * (1.0 - constraint_saturation)Where `constraint_saturation` measures how close to physical limits the body is.
Uncertainty
Uncertainty measures how many plausible continuations remain.
Without neighbors (heuristic):
uncertainty = regime_embedding.variance() * (1.0 - directional_persistence)With neighbors (MotionPhraseIndex):
dispersion = continuation_dispersion(neighbors)
neighbor_uncertainty = dispersion_to_uncertainty(dispersion)
uncertainty = 0.7 * neighbor_uncertainty + 0.3 * heuristic_uncertaintyTransition Pressure
Rate of uncertainty collapse:
dC = (commitment - prev_commitment) / dt
dU = (uncertainty - prev_uncertainty) / dt
transition_pressure = alpha * dC + (1 - alpha) * (-dU)Recovery Margin
Distance to instability:
recovery_margin = 1.0 - max(
balance_violation,
joint_limit_violation,
speed_saturation
)Phase Stiffness
Rhythmic lock:
phase_stiffness = periodicity * (1.0 - angular_jerk)Novelty
Distance from recent history:
centroid = mean(regime_history)
novelty = clamp(distance(embedding, centroid) / 2.0, 0, 1)Stability
Local stationarity:
stability = 1.0 - latent_velocity_norm / max_expected_velocity---
Neighbor-Based Uncertainty (v1)
When a `MotionPhraseIndex` is set, uncertainty uses continuation dispersion:
#[cfg(feature = "neighbors")]
fn compute_uncertainty_with_neighbors(&self, embedding: &[f32]) -> (f32, Option<Vec<String>>) {
let index = self.phrase_index.as_ref()?;
// Query k nearest neighbors
let dispersion = compute_continuation_dispersion(index, embedding, self.k_neighbors);
if dispersion.neighbor_count == 0 {
return (heuristic_uncertainty(embedding), None);
}
// Convert dispersion to uncertainty
let neighbor_uncertainty = dispersion_to_uncertainty(&dispersion);
// Blend with heuristic for stability
let blend = 0.7 * neighbor_uncertainty + 0.3 * heuristic_uncertainty;
(blend, Some(neighbor_ids))
}---
Invariants
| ID | Invariant | Enforcement |
|---|---|---|
| INV-001 | Deterministic replay | No random seeds |
| INV-003 | Coverage threshold | Reject if coverage < 0.9 |
| INV-004 | Scalar bounds | All scalars validated |
| INV-006 | No hot-path allocation | Pre-allocated buffers |
| INV-007 | Schema version | Must match "0.1.0" |
---
Validation
The kernel validates windows before processing:
pub fn validate_window(&self, window: &MotionWindow) -> Result<(), KernelError> {
// Check skeleton frames for NaN/Inf
for frame in &window.skeleton_frames {
if !frame.root_position.is_finite() {
return Err(KernelError::InvalidSkeletonFrame(...));
}
for quat in &frame.bone_rotations {
if !quat.is_finite() {
return Err(KernelError::InvalidSkeletonFrame(...));
}
}
}
// Check latent frames for NaN/Inf
for frame in &window.latent_frames {
for &v in &frame.z {
if !v.is_finite() {
return Err(KernelError::InvalidLatentFrame(...));
}
}
}
// Check time bounds
if window.t_end <= window.t_start {
return Err(KernelError::InvalidConfig(...));
}
Ok(())
}---
Configuration
pub struct AnticipationConfig {
/// Minimum coverage to process [0, 1]
pub min_coverage: f32, // 0.9
/// Regime embedding dimension
pub regime_embedding_dim: usize, // 64
/// Constraint vector dimension
pub constraint_vector_dim: usize, // 8
/// Derivative summary dimension
pub derivative_summary_dim: usize, // 8
/// Transition pressure smoothing
pub transition_pressure_alpha: f32, // 0.3
/// Emit debug traces
pub emit_debug: bool, // false
}---
Performance
| Metric | Target | Enforcement |
|---|---|---|
| Latency | < 2ms | Pre-allocated buffers |
| Allocations | 0 | Ring buffer history |
| Memory | < 1MB | Fixed-size structures |
---
AUDIT FINDINGS
| Finding | Severity | Status | Notes |
|---|---|---|---|
| MOCOPI_BONE_COUNT = 27 | Info | Correct | Bones 0-26 inclusive |
| Quaternion validation | ✓ | Pass | NaN/Inf checked |
| Coverage threshold | ✓ | Pass | Rejects < 0.9 |
| Schema versioning | ✓ | Pass | "0.1.0" enforced |
| Neighbor blending | Note | Consider | 70/30 blend could be tunable |
---
Future Work
1. Learned embeddings: Replace projection with trained encoder
2. Multi-scale windows: Different time horizons
3. Attractor prediction: Predict likely attractors from uncertainty
4. Gesture priming: Use anticipation to prime gesture classifier
---
Further Reading
- [05-SENSOR_FUSION.md](05-SENSOR_FUSION.md) - Input stage
- [07-GESTURE_RECOGNITION.md](07-GESTURE_RECOGNITION.md) - Consumer
- [13-DATA_CONTRACTS.md](13-DATA_CONTRACTS.md) - Frozen schemas
Promotion Decision
Promote into a technical note or architecture paper with implementation anchors.
Source Anchor
Comp-Core/docs/architecture/06-ANTICIPATION.md
Detected Structure
Method · Evaluation · Architecture