feat(moq-catalog): add keyframeIntervalMs/Ticks track field#31
Conversation
The receiver's keyframe-repair tier (moq-lib) derives a keyframe-loss repair timeout from a keyframe/GOP cadence. It reads keyframeIntervalMs/Ticks, which are DISTINCT from groupDurationMs — that field is the per-MFU MMTP media-group duration (one frame for frame-grouped streams), not a keyframe interval, and the player deliberately will not use it as cadence. Add keyframe_interval_ms (serde keyframeIntervalMs) + keyframe_interval_ticks to Track and CommonTrackFields, with the same hoist/expand inheritance as the group-duration fields. Advisory + OPTIONAL (no required check); reject a present-but-zero value (ZeroKeyframeInterval) since a zero cadence would zero the receiver's repair timeout. Round-trip / inherit / zero-reject / optional tests added. This is the canonical-schema parity half of a cross-repo change; the publisher that actually emits the field is the hang catalog + moq_mmt muxer (measured keyframe interval), tracked separately. moqcast-draft §4.4.2 specs the field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR Review — moq-catalog keyframeIntervalMs/Ticks parityReviewed via pr-review-toolkit against Suggestion
Strengths
|
keyframeIntervalMs has no §4.4.2 exactness rule (unlike groupDurationMs): a fractional cadence rounds ms and carries the exact tick count in keyframeIntervalTicks. Pin that both fields round-trip and validate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Head: 9705786
Critical Issues (0)
None.
Important Issues (0)
None.
Suggestions (3)
-
[comments]
moq-catalog/src/lib.rs(keyframe_interval_ticksdoc) — "wins overkeyframeIntervalMswhen both are present" implies schema-level enforcement that doesn't exist. Both fields are stored independently; the priority logic lives in the consumer (moq-lib).- Rephrase to: "consumers should prefer this form over
keyframeIntervalMswhen both are present."
- Rephrase to: "consumers should prefer this form over
-
[tests]
moq-catalog/src/lib.rs:740validate_rejects_zero_keyframe_interval— only tests the direct-path zero (track.keyframeIntervalMs = 0). The validation code correctly handles the inheritance path via.or(self.common_track_fields.keyframe_interval_ms), but there's no test guarding that path against regression.- Add a sibling test:
commonTrackFields: {keyframeIntervalMs: 0}with no track-level override should also produceZeroKeyframeInterval. The inheritance-path gap mirrors the pre-existingvalidate_rejects_zero_group_durationgap; worth closing here since cross-field inheritance is highlighted in the PR description.
- Add a sibling test:
-
[tests]
moq-catalog/src/lib.rs— no test for thededuce_common_track_fields→hoist_to_commonround-trip with the new keyframe fields. A single test where all tracks share the samekeyframeIntervalMswould verify that deduction correctly hoists it tocommonTrackFieldsandhoist_to_commonthen clears the per-track copies.
Strengths
- Schema addition follows the existing
groupDurationMs/groupDurationTickspattern exactly — type choices (Option<u32>/Option<u64>), serde renames,skip_serializing_if, expand + hoist + deduce symmetry all consistent. ZeroKeyframeIntervalvalidation correctly accounts for the inheritance path via.or(self.common_track_fields…)before the zero check, matching howZeroGroupDurationis handled.- Five targeted tests (round-trip, inherit, zero-reject, optional-pass, fractional-cadence) cover the core behavioral surface well.
- PR description correctly distinguishes
keyframeIntervalMsfromgroupDurationMsand explains the cross-repo landing dependency; theZeroKeyframeIntervaldoc string is clear on the failure mode.
Recommended Action
- No Critical or Important issues — safe to merge into the cross-repo set.
- Address Suggestions opportunistically (S1 is a one-line doc touch; S2+S3 are good follow-on test cases).
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Looks good. Single-file, mechanical schema addition (keyframeIntervalMs/keyframeIntervalTicks on Track + CommonTrackFields) that precisely mirrors the existing groupDurationMs/groupDurationTicks pattern at every touch point: struct fields, with_common inheritance, from_tracks hoist/reduce, and the zero-value validation branch (scoped to MMTP tracks, consistent with how groupDuration is already scoped).
Verified locally against head 9705786:
cargo test -p moq-catalog: 61/61 passed (PR description says 60/60 — one extra test is present, not a discrepancy worth flagging).cargo clippy -p moq-catalog --all-targets: clean, no warnings.- No other file in the workspace matches on
CatalogValidationError, so the newZeroKeyframeIntervalvariant doesn't leave any external exhaustive-match sites unhandled.moq-lib(the stated consumer) isn't part of this workspace, confirming the PR's "schema parity only, no consumer yet" scope claim.
Suggestions (1)
- [code]
moq-catalog/src/lib.rs:1391-1401— UnlikegroupDurationMs/groupDurationTicks, there's no%-exactness cross-check betweenkeyframeIntervalMsandkeyframeIntervalTicksagainsttimescale; the fractional-cadence test explicitly documents this as intentional (no §4.4.2 exactness rule for this field). Worth a quick sanity check against the actualmoqcast-draft§4.4.2 text before merge, since this is the one place the new field's validation behavior diverges from its sibling.
Strengths
- Test coverage is thorough for a schema-only change: round-trip, common-field inheritance, zero-rejection, optional-pass, and a fractional-cadence edge case with a rounding rationale in the comment.
- Doc comments clearly disambiguate
keyframeIntervalMsfromgroupDurationMs(the actual RCA motivating this field per the PR description) rather than leaving readers to infer the difference.
Recommended Action
Nothing blocking. Per the PR description this lands as part of a cross-repo set (hang-mmt-fec + FFmpeg + pim gitlink bump) — hold merge until that set is ready, not for anything in this diff.
Reviewed head: 9705786
What
Add
keyframeIntervalMs/keyframeIntervalTicksto the moq-catalogTrack(+CommonTrackFields), the keyframe/GOP repair cadence the moq-lib receiver reads to arm its keyframe-loss repair timeout.Why
Distinct from
groupDurationMs, which is the per-MFU MMTP media-group duration (one frame for frame-grouped streams) — the player deliberately will not use it as a keyframe cadence. Without a keyframe cadence field, moq-lib's keyframe-repair tier stays disabled, leaving packet-FEC as the sole recovery tier (under-recovers large 8K keyframes on the lossy multicast leg).Scope
This is the canonical-schema parity half of a cross-repo change. The publisher that actually emits the field is the
hangcatalog +moq_mmtmuxer (measured keyframe interval) — separate PRs inhang-mmt-fec+FFmpeg.moqcast-draft§4.4.2 specs the field. Do not merge standalone; lands with the set + a pim gitlink bump.ZeroKeyframeInterval) — a zero cadence would zero the receiver's repair timeout.cargo test -p moq-catalog60/60, clippy clean.🤖 Generated with Claude Code