Repository navigation
fix(producer): credit held video tails in coverage gate #2606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,10 +128,51 @@ describe("computeVideoFrameCoverage", () => { | |
| // landed in framePaths (mid-extraction crash, partial cache read, …). | ||
| const partial = makeExtracted("a", 5); | ||
| partial.totalFrames = 30; | ||
| partial.metadata.durationSeconds = 1; | ||
| const reports = computeVideoFrameCoverage(videos, [partial], 30); | ||
| expect(reports[0]!.capturedFrames).toBe(5); | ||
| expect(reports[0]!.ratio).toBeCloseTo(5 / 30, 5); | ||
| }); | ||
|
|
||
| it("credits a non-looping held tail against the source portion only", () => { | ||
| const videos = [makeVideo({ id: "held", start: 0, end: 10 })]; | ||
| const extracted = [makeExtracted("held", 90)]; | ||
| extracted[0]!.metadata.durationSeconds = 3; | ||
| const reports = computeVideoFrameCoverage(videos, extracted, 30); | ||
| expect(reports[0]).toMatchObject({ expectedFrames: 90, capturedFrames: 90, ratio: 1 }); | ||
| }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 [nit] No test exercises — Rames D Jusso |
||
|
|
||
| it("still requires the full authored slot for looping clips", () => { | ||
| const videos = [makeVideo({ id: "loop", start: 0, end: 10, loop: true })]; | ||
| const extracted = [makeExtracted("loop", 90)]; | ||
| extracted[0]!.metadata.durationSeconds = 3; | ||
| const reports = computeVideoFrameCoverage(videos, extracted, 30); | ||
| expect(reports[0]).toMatchObject({ expectedFrames: 300, capturedFrames: 90 }); | ||
| expect(reports[0]!.ratio).toBeCloseTo(0.3, 5); | ||
| }); | ||
|
|
||
| it("still fails when extraction is truncated before the held-tail source", () => { | ||
| const videos = [makeVideo({ id: "truncated", start: 0, end: 10 })]; | ||
| const extracted = [makeExtracted("truncated", 60)]; | ||
| extracted[0]!.metadata.durationSeconds = 3; | ||
| const reports = computeVideoFrameCoverage(videos, extracted, 30); | ||
| expect(reports[0]).toMatchObject({ expectedFrames: 90, capturedFrames: 60 }); | ||
| expect(() => assertVideoFrameCoverage(reports, 0.95)).toThrow(VideoFrameCoverageError); | ||
| }); | ||
|
|
||
| it("fails closed for invalid or exhausted source durations", () => { | ||
| const videos = [ | ||
| makeVideo({ id: "zero", start: 0, end: 10 }), | ||
| makeVideo({ id: "trimmed-away", start: 0, end: 10, mediaStart: 4 }), | ||
| ]; | ||
| const extracted = [makeExtracted("zero", 0), makeExtracted("trimmed-away", 30)]; | ||
| extracted[0]!.metadata.durationSeconds = 0; | ||
| extracted[1]!.metadata.durationSeconds = 3; | ||
| const reports = computeVideoFrameCoverage(videos, extracted, 30); | ||
| expect(reports[0]).toMatchObject({ expectedFrames: 300, capturedFrames: 0 }); | ||
| expect(reports[1]).toMatchObject({ expectedFrames: 300, capturedFrames: 30 }); | ||
| expect(() => assertVideoFrameCoverage(reports, 0.95)).toThrow(VideoFrameCoverageError); | ||
| }); | ||
| }); | ||
|
|
||
| describe("assertVideoFrameCoverage", () => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 [nit] Test-fixture coupling —
makeExtracteddefaultsdurationSeconds = delivered/fps. This is why line 131 is now load-bearing on the pre-existing test: without it,makeExtracted("a", 5)at fps=30 setsdurationSeconds = 5/30 = 0.167, the new code computessourceFrames = ceil(0.167 * 30) = 5, givingexpectedFrames = min(30, 5) = 5andratio = 5/5 = 1— the test's ownratio ≈ 5/30expectation would then fail.Not a defect in this PR — the workaround is correct — but future tests that call
makeExtractedto model "extraction failure" (delivered < expected) need to also overridedurationSeconds, or they'll silently report full coverage and mask the failure. Consider makingmakeExtractedtakedurationSecondsas an explicit parameter, or defaulting it to something that doesn't couple withdelivered(e.g.videos[i].end - videos[i].start, or a fixed 10s).— Rames D Jusso
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed at the root instead of leaving it as a footgun:
makeExtractednow takesdurationSecondsas an explicit param (defaultInfinity, decoupled fromdelivered) rather than deriving it fromdelivered / fps. That also let me drop the two post-hoc.metadata.durationSeconds = ...mutations that existed only to work around the coupling. Pushed in 7382ef7.