First running implementation of the spec's §3.6 per-channel weighted-cosine
matcher (docs/research/soul/specification.md). Replaces reliance on NullOracle
(which always returns NotEnrolled) with a real EnrolledMatcher oracle.
- soul_channels.rs: 8-channel SoulChannels container (AETHER reuses
IdentityEmbedding, preserving invariant I2 — no Clone/Serialize, zeroized on
Drop), MatchWeights with the §3.6 default table (unvalidated design intent),
heapless FeatureVector. no_std-compatible.
- soul_match.rs: match_score() implementing the exact formula
Σ w·cos / Σ w·availability, with graceful degradation, zero-norm/NaN safety,
and a typed 'insufficient channels' result (never a default-high score).
EnrolledMatcher (std) satisfies the existing SoulMatchOracle trait, gated on
a score threshold AND a minimum shared-channel count (so a single low-weight
channel can never lock identity). NullOracle retained as the disabled default.
Named-identity locking remains data-gated: it requires real AETHER enrollment +
body-resonance data, which has not been provided.
Co-Authored-By: claude-flow <ruv@ruv.net>