Skip to content

caption: never derive negative word durations; repair inverted cues#272

Open
maboa wants to merge 1 commit into
mainfrom
repair-inverted-cues
Open

caption: never derive negative word durations; repair inverted cues#272
maboa wants to merge 1 commit into
mainfrom
repair-inverted-cues

Conversation

@maboa

@maboa maboa commented Jul 24, 2026

Copy link
Copy Markdown
Member

Problem

When a word span has no data-d, caption.js derives its duration from the next span's data-m with only a positive cap (js/caption.js:132). If the next data-m sits at or before this word's start — duplicate timestamps on split/glued tokens, or out-of-order times after manual edits — the duration goes negative, producing a cue with stop < start.

Downstream, applyTimingSafeguards deliberately skips exactly these (stop <= start), so the inverted cue serializes: browsers silently drop it from the VTT track, several SRT consumers reject the whole file, and a below-zero result wraps to a ~23:59:59 timestamp via the Date-based formatSeconds.

Fix

  • Clamp the derived duration at 0 so a word never ends before it starts.
  • applyTimingSafeguards now repairs inverted/zero-length cues instead of stepping over them: stop is treated as start, then the cue is extended to the minimum readable duration (capped at the next cue's start, never emitting stop <= start even against out-of-order cue starts).

Tests

Two regression tests in __TEST__/caption.test.js — a missing data-d beside a non-increasing data-m (no negative / 24h timestamp), and an explicit zero-duration word (cue repaired, not dropped). Full suite green (73 passing).

Note

Found by reviewing the vendored copy in hyperaudio/hyperaudio-lite-editor#411 — a hardening fix against malformed/edited timing rather than an observed failure, but such input produces genuinely broken VTT/SRT output today.

When a word has no data-d, its duration is derived from the next span's
data-m with only a positive cap — if the next data-m sits at or before this
word's (duplicate stamps on split tokens, out-of-order times after edits) the
duration went negative, yielding a cue with stop < start. Browsers drop such
cues from a VTT track, several SRT consumers reject the whole file, and a
negative arithmetic result wrapped to a ~24h timestamp via the Date-based
formatSeconds.

Two-part fix:
- clamp the derived duration at zero
- applyTimingSafeguards now REPAIRS inverted/zero-length cues instead of
  stepping over them: stop is treated as the start and the cue is extended to
  the minimum readable duration (capped at the next cue's start; never
  emitting stop <= start even against out-of-order cue starts)

Reported in hyperaudio/hyperaudio-lite-editor#411 from a review of the
vendored copy.
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