Repository navigation
fix(sync): preserve distinct WAL audio with equal VAD start times - #20688
chinokikiss wants to merge 3 commits into
Conversation
|
Verified the bug and the fix in I checked the invariants the PR description claims, and they hold:
Ran the tests in a worktree at this head: One minor non-blocking note: the deprecated v1 lane ( The Solid fix and reproduction — thank you. This review was produced by AI automation on behalf of the maintainers. by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with |
Keep the shared namespace root, retry a writer once if cleanup removes its empty directory, and preserve nonempty and unrelated directories.
|
Thanks for this fix and the exceptionally clear write-up — the root-cause analysis and disclosure of deployment effects are exactly what makes a data-loss bug reviewable. I verified the core claim and the surrounding pipeline behavior at the current head:
One thing for maintainers to weigh at mark-ready time (also flagged in the description): the path-checkpoint invalidation means legacy in-flight jobs lacking the content-ID ledger may replay STT once after deployment. The transcript-assignment dedupe limits the impact, but that deployment window deserves a maintainer look alongside CI results. No blocking concerns from me. Leaving for human maintainer review before merge. by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with |
|
@chinokikiss this conflicts with |
|
Hey @chinokikiss 👋 Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request. After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:
Before your next PR, please skim:
If this was declined for direction or taste, maintainers should cite an invariant ID or open a proposed one — ask if that citation is missing. Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out. Thank you for being part of the Omi community! |
Problem and fix
Fixes #20686.
Two distinct uploaded WALs can have VAD slices with the same absolute speech start.
retrieve_vad_segments()previously exported both to<job>/<timestamp>.wav.The later write overwrote the earlier recording,
segmented_pathscollapsed to oneentry, and the source-frame map became unavailable.
_run_sync_vad_phase()thendeleted both original WAVs and advanced toward STT with only one surviving file.
Reproduction uses two real PCM16 WAVs with distinct sample values and durations:
one starts at T with speech [1, 3], the other at T+1 with speech [0, 4]. Both exports
have absolute start T+1. This fails in either sequential order and through the real
concurrent VAD phase, without a provider or network call. Production incidence is
not measured; the demonstrated impact is loss of an affected shard before STT.
Namespace the outputs under
<job>/.vad/<SHA256(source basename)>/, keeping thenumeric segment basename. Each source retains its bytes and mapping; timestamp
parsing and basename-plus-content durable segment identities remain unchanged.
This changes the existing shared VAD export primitive, without adding a new guard
or independent policy. The pipeline documentation describes cleanup and retry effects.
The legacy v1 endpoint uses the same primitive but retains its per-user directory.
Its file cleanup now removes an empty
.vad/<hash>directory after the last segment,without recursively deleting any files or removing the shared
.vadroot. If cleanupremoves an empty namespace between mkdir and opening a WAV, the writer recreates it
and retries once; persistent export failures still propagate.
Verification
Python 3.11.15, real Pydub PCM WAV read/slice/export, external providers stubbed:
python -m pytest tests/unit/test_sync_opus_decode.py -q: 45 passed.python -m pytest tests/unit/test_sync_v2.py -q: 182 passed.test_sync_silent_failure.py: 46 passed;test_sync_capture_pipeline.py:28 passed;
test_wal_audio_coverage.py: 47 passed;test_wal_audio_coverage_pipeline.py: 60 passed. 408 tests passed across these six files,with each file in a separate process to respect the existing stub harness.
4bdcc56d0dd4701af04cc423a310eb7445810708, also rantest_sync_phase_metrics.py: 15 passed andtest_sync_cloud_tasks.py:103 passed, covering the upstream instrumentation that now wraps this module.
526 tests passed total across eight isolated suites.
6 failed, 4 passed; after the follow-up 10 passed. They cover last-segment
cleanup, retained sibling audio and unrelated directories, repeated cleanup,
a deterministic cleanup/write interleaving with exact PCM verification, and
propagation of a persistent output failure after one retry.
cleanup after the actual concurrent VAD phase, and durable content IDs across job directories.
Pathobjects, preserving its containmentassertion on Windows as well as POSIX.
No live user audio, production writes, or hosted STT calls were used.
Draft: full repository validation is not green. After merging current main,
all 31 selected local manifest checks were attempted with keep-going. Two checks
initially could not initialize the Windows default uv cache. Re-running those
with the existing workspace cache restored the route-policy check (zero new
missing entries), leaving 30 reported pass and the Firestore index guard failed.
The guard's Windows-generated CRLF test list still sends
*.py\rpaths toBash/pytest. The failure-class history ratchet reported a shallow-history skip;
it is not full-history proof. Metadata validation against current main accepts
Failure-Class: nonein the PR body, as required. Diff hygiene, pinned Black,import purity, async-blocker scanning, module isolation and runtime source closure
passed.
The original submission's full Pyright lane reported 27 optional-package
missing-import errors, identical to its unchanged
ffeb8a13baseline, with nonein the changed pipeline. That comparison is historical; the full type lane was
not rerun against the newly merged main and is not claimed green. The original
separate Firestore guard attempt using an LF list also encountered missing IANA
timezone data and Windows asyncio loopback-block failures; its long-running
query-shapes file was interrupted. No passing guard proof is claimed.
The original standard Git pre-push launcher could not start its Bash child on this host
(
NtCreateDirectoryObjectaccess denied). The branch was published through GitHub'sGit data API, verifying the exact tested trees and commit SHAs. No hook script or
upstream source was changed to suppress these failures. Complete canonical checks
on the normal CI host and review the rollout note before marking this ready.
The upstream workflow runs currently report
action_requiredwith no jobs started;this contributor account cannot approve upstream runs. CI approval remains with
the maintainers.
Retry / rollout consideration
New full paths are deterministic within a job. Pre-change Redis full-path checkpoints
will not match them. Durable content checkpoints retain the old identity for identical
audio; legacy jobs without a content ledger can replay STT once at deployment and
retain existing assignment dedupe. This patch prevents the pre-STT file overwrite;
it does not redefine downstream transcript deduplication or promise distinct rows
for simultaneous sources.
Overlap review
Reviewed 91 distinct open PRs returned by scoped VAD, WAL, timestamp/sync,
overwrite, collision and sync-title queries on 2026-10-05. Examined patches for
the 10 touching sync production modules. No existing repair of this collision was
found. #20659's timing instrumentation is now on main and has been merged into
this branch and tested. #20662 adds resource bounds and export error handling but
retains the timestamp-only output path. Upload filename containment is already
covered by #19483 and is excluded. The later 660-open-PR file inventory and the
current VAD/cleanup query found no equivalent per-source directory cleanup patch.
Recheck current main and these PRs before merge because concurrent changes may land.
Product invariants affected
none — the path-based invariant suggestion for this diff reports no locked matches.
Failure class (fixes)
Failure-Class: none
Line-Count-Exception: backend/utils/sync/pipeline.py | 3026 -> 3052 | namespace the existing VAD exporter by source and remove only empty per-source directories while preserving timestamps and retrying a cleanup/write interleaving once
Bounty proposal
Proposed bounty: US$100, subject to explicit maintainer approval and merge.
This is a demonstrated core capture data-loss repair with concurrent byte-level
regression evidence, rather than an export-recipe robustness change. It is not an
existing funded bounty, fixed program rate, or payment entitlement. Eligibility and
amount remain at the maintainers' discretion under the
contribution guide; payment details
would be supplied privately through its documented PayPal process.
Disclosure: investigation, code and tests were prepared with an AI assistant for
@chinokikiss; this does not represent independent human review.