Bug-hunt round 30: word-level invisible-text filtering, stale install.sh trap comment - #46
Merged
Conversation
mapSegments judged a word's emptiness on the raw form (w.W after TrimSpace), unlike the sibling segment-level guard five lines above, which decides presence on session.SafeText's rendered form. A word that is entirely invisible-only Unicode (e.g. ZWSP U+200B) is non-empty raw and survives TrimSpace, so it reached transcript.jsonl, timeline.jsonl, and the analysis request as a timestamped word with no visible content. Assisted-by: Claude:claude-sonnet-5
The comment at install_ffmpeg_local's error-handling block claimed an unguarded failure would leak $tmp2 because "the EXIT trap covers only install_binary's $tmp" — describing pre-fix behaviour. The trap set at line 134 already sweeps $tmp2 (added alongside $gnupg/$uvd), directly contradicting the stale parenthetical a few lines above it. Assisted-by: Claude:claude-sonnet-5
Assisted-by: Claude:claude-sonnet-5
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.
Round 30 of the automated bug-hunt loop (state: #24).
Confirmed findings (fixed)
1.
internal/transcribe/transcribe.go:527(mapSegments) — nitpickThe word-level emptiness check judged presence via
strings.TrimSpace(w.W), the raw form, unlike the segment-level guard five lines above it (transcribe.go:508), which decides presence onsession.SafeText's rendered form. A word that is entirely invisible-only Unicode (e.g. a zero-width space, U+200B) is non-empty raw and survivesTrimSpace(which strips only Unicode whitespace, not Cf format characters), so it reachedtranscript.jsonl,timeline.jsonl, and — onceSafeTextwas applied at marshal time inanalyze.EmitRequest— an emitted analysis request as a timestamped word with no visible content ({"w":"","t":...}). Low severity: nothing in the codebase renders or otherwise consumes thewordsfield (report.gonever reads it), so the blast radius is one cosmetic empty entry.Fix: the word-level check now mirrors the segment-level one, deciding presence on
session.SafeText(word)while still storing the raw trimmed form. Covered by a new regression test,TestMapSegmentsDropsInvisibleOnlyWord, mirroring the existingTestMapSegmentsDropsInvisibleOnlyText; verified failing before the fix (the invisible word survived intoutts[0].Words) and passing after.2.
install.sh:282-285— nitpickA comment in
install_ffmpeg_local's error-handling block claimed an unguarded failure would leak$tmp2because "the EXIT trap covers onlyinstall_binary's$tmp" — describing behaviour that predates the trap being widened. The trap set atinstall.sh:134already sweeps${tmp2:+"$tmp2"}alongside$gnupg/$uvd, directly contradicting the stale parenthetical a few lines below it (install.sh:128-130correctly states the traps cover the dependency stage). No behavioural change — comment-only fix, so no new test.Considered and rejected (adversarially refuted, or precedent duplicates)
internal/analyze/validate.go:66(indexTimeline) writingidx.uttText[nid]without the empty-id guard its siblingidx.ids/idx.selectors/idx.routeswrites apply — the read path (validate.go:200) is reached only afteridx.ids[nid]already passed a gate thatidx.ids[""]never satisfies, so the unguarded key is write-only dead data with no observable effect on validation output.internal/session/session.go:299-307(WriteFileAtomicNoFollow) refusing only symlinks at its target path, not other non-regular files (FIFO, device, socket), unlike its siblingopenNoFollow's stricter check — the function never opens the pre-existing file; it writes to a fresh temp file andos.Renames over the target, andrename(2)neither opens, blocks on, nor writes through a FIFO, so the hazard the sibling guard exists to prevent (anopen(2)hang) is absent by construction, not merely unexploited.docs/reference/cli.md:61's-offsettable cell compressing the "external audio vs the session's ownaudio.wav" branch as "with/without-audio" — the surrounding prose (lines 63, 71) states the exception twice within ten lines, and the table cell already compresses two other branches (a bad manifestt0, an unusable sidecar) the same way; a reader following the section is not misled..github/workflows/ci.yml:84-85's cross-compile-step comment ("linux/amd64 already covered by Build above") read as a claim that theBuildstep also usesCGO_ENABLED=0— the comment'sCGO_ENABLED=0clause and its coverage clause are two independent statements joined by a semicolon; the coverage claim (the step's own stated purpose, catching a GOOS-conditional compile break) holds regardless, and the module has no cgo-conditional code paths.docs/how-to/analyse-a-session.md:12's "four steps" intro read against its five numbered headings — the fifth, re-rendering the report, is grammatically set off by an em dash as a follow-on outside the enumerated list ("four steps: A, B, C, and D — then E"), and invokes a different, separately-documented pipeline command (report), not a fifth step of the analysis layer the intro scopes itself to.docs/reference/session-directory.md:76,108's abbreviatedutt-003example text read against the fuller fixture sentence — the page's other examples are established as illustrative reductions too (the manifest example already drops three fixture fields), thewordsarray is trimmed in step with the shortened text rather than left orphaned, and nofindings.jsonlquote citesutt-003, so nothing depends on the byte-exact form.AGENTS.mdclaiming CI runs plaingo test ./...(round 13).Verification
go build,gofmt -l .,go vet ./...,go test ./...,go test -race ./..., and the pipeline smoke (merge/reportonexamples/sample-session) all pass..abcd/work/DECISIONS.mdgains the round's entry.