Skip to content

Keep reconstructed timestamps monotone across segment joins - #21

Merged
cboulay merged 1 commit into
devfrom
fix/monotone-joins-and-rescue-floor
Aug 22, 2026
Merged

Keep reconstructed timestamps monotone across segment joins#21
cboulay merged 1 commit into
devfrom
fix/monotone-joins-and-rescue-floor

Conversation

@cboulay

@cboulay cboulay commented Aug 20, 2026

Copy link
Copy Markdown
Member

Two defects in the real-gap / shared-model reconstruction

1. Segment joins can run backwards

Real-gap handling fits each inter-gap segment independently so the true jump survives, which leaves the joins unconstrained: a segment's smoothed first sample is an estimate, and reconstruct_shared re-anchors every segment on its own median. Segment k+1 could therefore begin before segment k ended.

Found on a real recording — a hub whose stamps were written at the wrong intra-chunk rate (32063.6 Hz against 30000.4 delivered), rescued via its PTP sibling. The reconstruction emitted two backward steps of 33 sample periods (1.1 ms) in a vector that find_gaps and chunk anchoring both read as monotone, and that the module docstring promises is "smoothed, strictly monotone".

The repair re-cuts a broken join to the jump the raw timestamps show across it, floored at one sample period, shifting the whole following segment to match and carrying the shift cumulatively. Using the raw jump is what keeps a real gap intact — shifting by just enough to restore order would collapse it to a single period, and the raw stamps are the only evidence left of how long the recording actually stopped. Healthy joins are untouched. Shifting rather than clamping preserves each segment's internal shape; np.maximum.accumulate would leave plateaus of duplicate stamps.

2. clean_resid > 0.0 inverts the gate's intent at the limit

A perfect reference — stamps regenerated as i / fs self-fit to ~1e-14 s, or exactly 0 — made the ratio test rescue nothing, precisely when the reference is most worth borrowing.

SHARED_MODEL_JITTER_FLOOR_PERIODS (1.0) now sits alongside the ratio, and the threshold is max(RATIO * clean_resid, FLOOR * period), which subsumes the special case: a perfect source gives a ratio term of zero and the floor decides. A target must clear both bars, so two already-clean streams never trigger each other however far apart their ratio falls.

One period separates the observed populations comfortably: clean recordings self-fit to 0.3–0.5 periods, the wrong-rate stream lands at ~37.

Validation

On the file that surfaced it: backward steps 2 → 0, and the clean session's two hubs are unchanged (0 gaps, 0 backsteps, 30000.105 / 30000.093 Hz). The new shared-path test is not vacuous — replaying the previous segment loop on the same input gives a −4.0 ms step.

8 new tests; 213 pass.

🤖 Generated with Claude Code

Real-gap handling fits each inter-gap segment independently so the true jump
survives, which leaves the joins unconstrained: a segment's smoothed first
sample is an estimate, and the shared path re-anchors every segment on its own
median. Segment k+1 could therefore begin before segment k ended. On a real
recording (a hub whose stamps were written at the wrong intra-chunk rate,
rescued via its PTP sibling) the reconstruction emitted two backward steps of 33
sample periods -- 1.1 ms of time running backwards in a vector the gap-splitter
and chunk anchoring both read as monotone.

Re-cut a broken join to the jump the raw timestamps show across it, floored at
one sample period, shifting the whole following segment to match and carrying
the shift cumulatively. Using the raw jump is what keeps a real gap intact:
shifting by just enough to restore order would collapse it to a single period,
and the raw stamps are the only evidence left of how long the recording actually
stopped. Healthy joins are untouched.

Also give the shared-model gate an absolute floor (SHARED_MODEL_JITTER_FLOOR_
PERIODS) alongside the ratio, which removes the clean_resid > 0 special case:
a perfect reference (regenerated stamps self-fit to ~1e-14 s, or exactly 0) made
the ratio test rescue nothing precisely when the reference was most worth
borrowing. A target must now clear both bars, so two already-clean streams never
trigger each other however far apart their ratio falls.

Validated on the file that surfaced it: backward steps 2 -> 0, and the clean
session's two hubs are unchanged (0 gaps, 0 backsteps, 30000.10/30000.09 Hz).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cboulay
cboulay merged commit 7d789a5 into dev Aug 22, 2026
14 checks passed
@cboulay
cboulay deleted the fix/monotone-joins-and-rescue-floor branch August 22, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant