21.2 review remediation: pause-spin, OQ7 comment, rename, C2 cross-check

Skip the back-pressure interop poll while paused (UC5). Document complete()
draining the stash in full by design. Rename scheduler isProductionPaused to
evaluateProductionPause (latch-advancing); window exposure name unchanged.
This commit is contained in:
daniel-c-harvey
2026-06-23 23:28:42 -04:00
parent 518479e7ae
commit 29e8747c69
5 changed files with 42 additions and 24 deletions
@@ -352,7 +352,7 @@ function fillAndStart(s: PlaybackScheduler, cm: FakeContextManager, count: numbe
}
// High-water reached → production pauses; the signal reflects the forward lookahead.
test('isProductionPaused latches true when forward lookahead reaches high-water', () => {
test('evaluateProductionPause latches true when forward lookahead reaches high-water', () => {
const cm = new FakeContextManager();
const s = makeScheduler(cm);
s.setForwardWindow(10, 5, 0); // high 10s, low 5s, byte cap disabled
@@ -360,45 +360,45 @@ test('isProductionPaused latches true when forward lookahead reaches high-water'
cm.now = 0; // playhead at 0 → forward lookahead = 40s ≥ 10s high-water
assertEqual(s.getForwardLookaheadSeconds(), 40, 'lookahead is full decoded tail at t=0');
assertEqual(s.isProductionPaused(), true, 'pauses at/above high-water');
assertEqual(s.evaluateProductionPause(), true, 'pauses at/above high-water');
});
// Below high-water but above low-water while NOT yet paused → stays unpaused (no premature pause).
test('isProductionPaused stays false in the hysteresis band before the high-water crossing', () => {
test('evaluateProductionPause stays false in the hysteresis band before the high-water crossing', () => {
const cm = new FakeContextManager();
const s = makeScheduler(cm);
s.setForwardWindow(10, 5, 0);
fillAndStart(s, cm, 8); // 8s decoded
cm.now = 0; // lookahead 8s: between low(5) and high(10), never latched → unpaused
assertEqual(s.isProductionPaused(), false, 'no pause until high-water is actually reached');
assertEqual(s.evaluateProductionPause(), false, 'no pause until high-water is actually reached');
});
// Hysteresis: once paused at high-water, stays paused through the band until lookahead drains
// below low-water, then resumes. Drain is modeled by advancing the clock (playhead moves forward,
// shrinking forward lookahead).
test('isProductionPaused holds through the band and resumes only below low-water', () => {
test('evaluateProductionPause holds through the band and resumes only below low-water', () => {
const cm = new FakeContextManager();
const s = makeScheduler(cm);
s.setForwardWindow(10, 5, 0);
fillAndStart(s, cm, 40); // track [0,40)
cm.now = 0;
assertEqual(s.isProductionPaused(), true, 'latched at high-water (40s ahead)');
assertEqual(s.evaluateProductionPause(), true, 'latched at high-water (40s ahead)');
// Playhead at 32 → lookahead 8s: in the band (5..10) → must STAY paused (hysteresis).
cm.now = 32;
assertEqual(s.getForwardLookaheadSeconds(), 8, 'lookahead drained to 8s');
assertEqual(s.isProductionPaused(), true, 'still paused inside the band');
assertEqual(s.evaluateProductionPause(), true, 'still paused inside the band');
// Playhead at 36 → lookahead 4s ≤ low-water 5 → resume.
cm.now = 36;
assertEqual(s.getForwardLookaheadSeconds(), 4, 'lookahead below low-water');
assertEqual(s.isProductionPaused(), false, 'resumes below low-water');
assertEqual(s.evaluateProductionPause(), false, 'resumes below low-water');
// Refill back over high-water re-latches (the next chunk would re-pause).
for (let i = 0; i < 20; i++) s.addBuffer(buf(1)); // +20s decoded ahead
assertEqual(s.isProductionPaused(), true, 're-latches when fill exceeds high-water again');
assertEqual(s.evaluateProductionPause(), true, 're-latches when fill exceeds high-water again');
});
// OQ3 hard byte ceiling pauses production independent of the time window, and releases as soon as
@@ -418,7 +418,7 @@ test('OQ3 byte ceiling pauses regardless of the time window', () => {
if (s.getDecodedByteEstimate() <= perBuffer * 4) {
throw new Error('test setup: byte estimate should exceed the cap');
}
assertEqual(s.isProductionPaused(), true, 'byte ceiling pauses even with a huge time window');
assertEqual(s.evaluateProductionPause(), true, 'byte ceiling pauses even with a huge time window');
});
// clear() / clearForSeek() release the latch so a fresh stream/seek starts unthrottled (C2).
@@ -428,17 +428,17 @@ test('clear and clearForSeek release the back-pressure latch (C2 latency parity)
s.setForwardWindow(10, 5, 0);
fillAndStart(s, cm, 40);
cm.now = 0;
assertEqual(s.isProductionPaused(), true, 'latched');
assertEqual(s.evaluateProductionPause(), true, 'latched');
s.clear();
// After clear there are no buffers, lookahead is 0, and the latch is reset → unpaused.
assertEqual(s.isProductionPaused(), false, 'clear resets the latch and empties fill');
assertEqual(s.evaluateProductionPause(), false, 'clear resets the latch and empties fill');
fillAndStart(s, cm, 40);
cm.now = 0;
assertEqual(s.isProductionPaused(), true, 'latched again after refill');
assertEqual(s.evaluateProductionPause(), true, 'latched again after refill');
s.clearForSeek();
assertEqual(s.isProductionPaused(), false, 'clearForSeek resets the latch');
assertEqual(s.evaluateProductionPause(), false, 'clearForSeek resets the latch');
});
// --- run -------------------------------------------------------------------------------------