Phase-locked capture had no client half on Apple — the host's v3 controller
(grid-locked submits, coherence-gated engage) shipped with only the Android
reporter feeding it. Now the stage-4 link thread flushes the same v2
circular arrival-phase statistic at ~1 Hz:
- PhaseReporter (Stage2Pipeline): the decode callback deposits per-AU
reassembly-completion stamps, the CAMetalDisplayLink update deposits the
latch grid (period = window-min of update spacing), and the flush ports
punktfunk_core::phase::circular_latch verbatim — a period-smeared Wi-Fi
link reads coherence ≈ 0 and the host correctly never engages; a wired
link opens the gate. Binds/unbinds per session like DecodeReport.
- PunktfunkConnection.reportPhase wraps the existing ABI entry point.
- Hello honesty: iOS/tvOS advertise CLIENT_CAP_PHASE_LOCK (macOS stays
without — the stage-2 arrival presenter has no latch grid), Android now
sets the bit its reporter already earned, and the ABI grows the
PUNKTFUNK_CLIENT_CAP_PHASE_LOCK mirror const (header regenerated).
Advisory in v1: the host arms on report receipt.
- Stage-3 doc comment no longer calls itself the tvOS default (stage-4 took
that over in the 2026-07 rebuild).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>