festifun/plan/status/lane-A.md
m3ultra 157c783e25 Lane A (M1): ingest + GCC-PHAT audio sync
Fills the foundation stubs in ingest.py and audio_sync.py.

- ingest: ffprobe probe + mono 16 kHz WAV extraction per video (ffmpeg);
  idempotent run_ingest reuses existing rows so synthetic -> ingest -> sync
  works without unique-constraint collisions.
- sync: PHAT-whitened GCC-PHAT pairwise offsets with sub-sample parabolic
  peak refinement, scored by peak-to-second-peak ratio; confidence-weighted
  global least-squares solve with cycle-consistency rejection (>50 ms);
  windowed drift estimation (ppm) with a 5 ppm deadband; disconnected
  sync-graph components -> offset_ms=None (spec pitfall #5).
- Persists offset_ms/drift_ppm/sync_confidence via db.update_video_sync and
  exports data/work/sync.json.

Verified on the synthetic fixture: synthetic -> ingest -> sync recovers the
ground-truth offsets (0 / +1370 / -842 ms) to <0.001 ms and drift 0 ppm,
well inside the spec M1 tolerances (+/-10 ms, +/-3 ppm). pytest: 43 passed
(24 foundation + 19 new in test_ingest.py and test_audio_sync.py).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:13:56 +10:00

22 lines
1.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Status — lane-A
## Round 0 — 2026-07-16 — STATUS: in_progress
**Directives acknowledged:** round 0 of plan/DIRECTIVES.md (run order & protocol; Lane A = spec M1).
**Acceptance checklist** (spec M1 + lane brief):
- [ ] `ingest`: ffprobe each file in `data/raw`, register in `videos`, extract mono 16 kHz WAV per video into `data/work/audio/`.
- [ ] `sync`: GCC-PHAT (PHAT-whitened, not raw xcorr) pairwise offsets, scored by peak-to-second-peak ratio.
- [ ] Global least-squares solve over the offset graph, confidence-weighted, cycle-consistency rejection (>50 ms).
- [ ] Drift: windowed GCC-PHAT, line fit → `drift_ppm`; store 0 if `|drift| < 5 ppm`.
- [ ] Disconnected sync-graph components → `offset_ms = None` (spec pitfall #5).
- [ ] Persist `offset_ms`/`drift_ppm`/`sync_confidence` via `db.update_video_sync`; export `config.SYNC_JSON`.
- [ ] `python -m festival4d ingest && python -m festival4d sync` recovers GT offsets (±10 ms) and drift (±3 ppm).
- [ ] `pytest` green (new `test_ingest.py`, `test_audio_sync.py`); synthetic end-to-end intact.
**Done this round:** branched `lane/a-media` from `main`; baseline `pytest` green (24 passed). Verified env: ffmpeg/ffprobe present, librosa 0.11, scipy 1.18; synthetic fixtures (`data/raw/cam{0,1,2}.mp4`, DB rows GT offsets 0/+1370/842) in place. Implementing `ingest.py` + `audio_sync.py`.
**Blockers / questions for coordinator:** none. `sync.json` schema is unspecified by the spec — designing a self-describing schema (reference id, per-video offset/drift/confidence, raw edges, components); no consumer depends on it (API reads the DB), so no change request needed.
**Next:** implement both modules, validate GCC-PHAT against the real extracted fixture audio, write tests, run acceptance, then update status → ready_to_merge.