The runtime `lca()` helper used a `heapless::Vec<u16,32>` ancestry-set
with a linear `contains()` per node — O(H²) and capped at H ≤ 32. The
codegened `__DEPTH` table already had everything needed for an O(H)
depth-walk with no allocation and no hierarchy ceiling. Switch to that.
Also adds an iai-callgrind dispatch bench harness (Linux-only dev-dep)
so future optimizations can be measured deterministically by instruction
count. Seven benches cover: cold start, lateral H=2/4/8, up, self, and a
self-emit chain. Baseline numbers checked in at `hsmc/benches/baseline.txt`.
The latency analysis (`docs/003. latency-analysis.md`) is rounded out
with event-entry-point and cooperative-driving audits — three new
sections documenting the four event injection paths, the run-loop's
cooperative shape, and three correctness invariants (sticky overflow
flag, biased-select trap, cancel-safety on durings).
Bench deltas (cargo bench --bench dispatch -- --baseline=pre_lca_fix):
h2_cold_start -1.9% / -0.3% (priming step, no lca() — noise)
h2_warm_lateral -22.8% / -22.1%
h4_cross_tree -25.9% / -10.6%
h4_up +1.0% / +0.4% (up-transition, no lca() — noise)
h4_self -21.5% / -11.7%
h8_cross_tree -46.2% / -41.0% ← headline: deepest LCA stress
chain_self_emit -15.4% / -10.4%
Improvement scales with hierarchy depth, exactly as the O(H²) → O(H)
algorithmic change would predict.
All tests pass under --no-default-features, --features tokio, and
--features embassy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>