Skip to content

bug: excessivePadding fires on healthy recordings — leading silence before the call counts as fabricated (fix written, parked on a branch) #179

Description

@fmasi

Status: fix already written and committed locally on fix/pad-false-positive — deliberately NOT pushed yet. This issue exists so the known-bad behaviour on main is recorded and the work is recoverable.

The bug

PadRatioMonitor labels healthy recordings as compromised. Device-observed on the first real firing since the detector shipped (2026-08-11, "Intro Call - Hamilton Barnes", 30 min, speaker only, no device changes).

The user got:

Transcription Complete — capture anomalies
115944-Intro Call - Hamilton Barnes.json — 1 capture anomaly recorded; audio may be affected

The recording was fine. Measured on the system track:

window zero-sample ratio
0–30 s 97.6%
30–60 s 18.2%
60–300 s 2.8%
whole file 4.2%

48 kHz throughout, no rate drift, no chipmunk. The call audio simply started ~60 s after recording began. The diagnostic recorded excessivePadding with ratio 0.911, padded 27s of 30s, judged at exactly t=30 s — on nothing but leading silence.

Root cause

A property of the Core Audio tap that ScreenCaptureKit does not share: the tap delivers no buffers at all while the output device is idle. SCK keeps delivering zero-filled buffers (the #86 liveness probe depends on that), which is why this was not anticipated. Before a call connects there is genuinely nothing to capture, so timelineSilencePad fabricates the whole span and every one of those frames counts toward the ratio.

The 15 s absolute floor added during review to prevent exactly this class of false positive does not help: leading silence trivially exceeds any absolute floor.

Starting a recording before joining the call is the ordinary way to use this app, so this fires on the common case — which is the failure mode that makes a warning worthless. See gotcha #62 on why a label that appears every time destroys the signal it carries.

The fix (written, on fix/pad-false-positive @ 5b738b4)

Not a bigger threshold — the right distinction: padding before a track has ever delivered a frame is a start offset, not a deficit. Nothing went missing because there was nothing to capture. PadRatioMonitor accumulates nothing until its first dataFrames > 0.

#58 detection is preserved exactly: in a genuine rate drift the device IS delivering (a call is connected, so silence still arrives as zero-filled buffers at the wrong rate), so the monitor starts when the frames do. Both cases are pinned by tests — leadingSilenceBeforeTheCallStartsIsNotCorruption and deficitAfterDataStartsStillFires, the latter also asserting the leading silence does not inflate the ratio.

Recorded as gotcha #65 on that branch.

Also on that branch (9745c66) — the error-message taxonomy

Same session surfaced a second reporting bug, unrelated to capture. A summary request timeout was reported as "Couldn't read the transcript or write the summary — check disk space and permissions", because MeetingSummarizer.runSummary's catch-all assumed any non-SummaryError was a file failure and URLError isn't one. That misdirection cost two separate debugging sessions (2026-08-04 and 2026-08-11) chasing a permissions problem that never existed.

The branch adds explicit URLError handling (timeout / unreachable / other), classifies 401-403 as SummaryError.authenticationFailed with a message that names the API key and deliberately omits the response body (some servers echo the offending credential back, and this text reaches a notification that can be on screen during a shared meeting), and raises the summary timeout to a configurable 600 s default (#173). Gotcha #66.

881 tests across 100 suites pass on the branch.

Impact while unfixed

main ships the detector as-is, so recordings started before the call connects — most of them — will be labelled "capture anomalies". The transcripts and audio are unaffected; it is purely a false warning. The risk is habituation: once the label is routine it stops being read, and the whole point of #58's surfacing work was that a compromised recording must not look like a clean one.

Related

#175 (the work that introduced this), #173 (timeout), #178 (summary reliability), #176 (other #175 follow-ups).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions