Repository navigation
docs(windows): spec the LTC and MTC schedule contract (#728 M3 slice 2) - #858
Merged
Merged
Conversation
Slice 2 of the timecode contract: LTCFrameStream, LTCSchedule and MTCSchedule. Pins composition (samples per frame/buffer, buffer timecodes, the endLevel == startLevel invariant) plus PCM run-lengths in a +/-16 sample window around each join, and MTCSchedule's host-clock windowing including the 1us quantise before ceil. Records three findings verified numerically rather than argued: - the parity bit is what makes buffer joins seamless (even ones count => even flip count => endLevel always equals startLevel), which also makes LTCSchedule's existing doc comment's justification wrong; - three fresh half-away-from-zero rounding divergences plus one round-then-multiply ordering hazard in samplesPerBuffer; - MTCSchedule's 1us quantise is load-bearing, not padding: at 1e9 ticks/s a port without it drops 74/200 messages at 24 fps. Also corrects the milestone label - this is M3 (hardware), not M2 (media), which slice 1's spec and issue titles got wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the slice-2 spec for the Windows timecode contract (epic #728):
LTCFrameStream,LTCScheduleandMTCSchedule. Spec only — no executable change in this PR.Part of #728
What Changed
Slice 1 (#854) pinned what one LTC frame and one MTC message look like on the wire. This spec covers the layer above: how frames compose into a stream, how that stream is cut into playback buffers, and how a host-clock window selects the quarter-frames due in it.
Three findings, each verified numerically rather than argued:
The parity bit is what makes LTC buffer joins seamless. Each frame emits 80 bit-boundary flips plus one mid-bit flip per
1bit; the parity bit forces an even number of ones, so the flip count is even andendLevelalways equalsstartLevel. All tenencodecases ingolden/ltc-wire-v1.jsonconfirm it. A side effect:LTCSchedule's doc comment justifies the inter-buffer polarity reset with "harmless, since an LTC reader keys on transitions, not absolute polarity" — that reasoning is wrong (a missing transition is a misread bit, not a polarity inversion), even though the conclusion holds for the stronger even-parity reason. The spec schedules a comment-only correction.Three fresh rounding divergences, plus an ordering hazard.
framesPerBuffer(forTargetSeconds:)at0.1 s @ 25 fpsis2.5→ Swift 3, C#Math.Round2. Same at0.5 s @ 25 fps(12.5 → 13 vs 12).MTCSchedule.timestampdiverges at a deliberately coarse clock. Separately,samplesPerBufferrounds per frame then multiplies — at 44100 Hz / 24 fps that is4 × 1838 = 7352, where the arithmetically-similarround(4 × 44100/24)gives 7350, i.e. a two-sample-per-buffer drift forever. Pinning only at 48 kHz (exact division) would miss it.MTCSchedule's 1 µs quantise beforeceilis load-bearing. Simulated over the first 200 quarter-frames atticksPerSecond = 1e9: without it a tiled window chain drops 74/200 messages at 24 fps and 66/200 at 30 fps, while 25 fps (exact 10 000 000-tick period) drops none. So the vectors must include a 1e9 @ 24 fps chain or the hazard is untested — and the C# spelling isMath.Ceilingwith an innerAwayFromZero, notMath.Round.The spec also records the consequence of (3) honestly: the quantise makes the half-open
[from, until)window exact only to the tolerance. That never bitesMTCOutput, which tiles, and the invariant that matters — each message exactly once across a chain — holds. Pinned as-is per the approved decision, with the reasoning left in the spec rather than discovered later.Milestone label correction. Slice 1's spec and issue titles say "M2 slice 1". Epic #728's M2 is media; timecode I/O is M3 — hardware. The epic body is already corrected; this spec uses the right milestone and the filename carries the
m3prefix.Affected Documentation
docs/superpowers/specs/2026-09-16-windows-m3-timecode-schedules.md— new. Goal, non-goals, four findings, five decisions, both golden-file contracts with full case matrices, work plan, implementation traps, and a mandatory eight-mutant mutation-testing list.Review Checklist
ticksPerSecond = 50clock is the only way found to maketimestamp(forQuarterFrame:)'s rounding mode divergent, but it is unphysical. Keep the case, or accept that site is untested?OnlyCue verification (required)
Spec link:
docs/superpowers/specs/2026-09-16-windows-m3-timecode-schedules.mdCloses: n/a — spec only; the implementation issue is filed after approval (also updates parent Epic #728 task list)
docs/— this PR is the spec;docs/architecture.mdis updated by the implementation PR