Conversation
A re-hunt over the previous round's tree confirmed 9 findings (7 distinct). Five were the same defect class as a fix from that round, left on a sibling path — the previous round patched reported sites rather than classes. This round fixes each defect and sweeps the repo for its siblings. Reported defects: - analyze: reject a finding whose required t is absent. It decoded to the zero value, passed the range check, and filed at [00:00] — tens of seconds from the utterance it quoted. Decoded through a pointer-typed raw shape, mirroring timeline.rawInteraction, because t = 0 is a legitimate anchor. - analyze: bound a finding's serialised length, not just its evidence count, so ingest cannot write a findings.jsonl line no reader can take back. - session: enforce MaxJSONLLine inside WriteJSONL, the invariant its own doc comment declared every writer must respect. Closes timeline.jsonl, findings.jsonl and transcript.jsonl at once. - record: stop the demo server through the bounded demo.Shutdown at both call sites, so record -demo gets the deadline the previous round added. - report: render negative session-relative times signed instead of clamping them to zero. Pre-t0 entries are legitimate and were misreported as 00:00. - transcribe: refuse any non-regular ffmpeg input or output path, not just a symlink, so a planted FIFO cannot block open(2) for ever. - review: roll back a partial verdict write, so a short write cannot leave a newline-less fragment that breaks findings.jsonl for every reader. Siblings the sweeps found, fixed here: - review: the same negative-time clamp, byte-identical to report's. - timeline: utterances were value-typed while interactions in the same file were already guarded, so a transcript omitting t0 planted speech at the session start. A missing t1 now defaults to t0, matching SpeechEnd, rather than inverting the join window. - transcribe: whisperx and whisper.cpp segment times were value-typed while the word-level times beside them were already pointers. Sweeps also confirmed the remaining matches are unaffected, with reasons recorded in the code: signal-wait contexts that must not carry a deadline, sort and window arithmetic that handles negatives correctly, and manifest t0 which timeline.Merge already guards. gofmt, vet, go test -race, and the sample pipeline all pass; the sample session's merged output is byte-identical. Assisted-by: Claude:claude-opus-4-8
A third hunt (truncated by a usage limit, but its first round complete) found a major left by the previous round: session.Manifest.T0() was added with a doc comment naming timeline.BuildEntries and transcribe's offset derivation as mandatory callers, then wired to neither. A guard with a doc comment and no callers is worse than none — it reads as protection that is not there. - timeline.Merge: resolve the anchor through man.T0() instead of an inline `== 0` test. The old test was narrower than T0()'s `<= 0`, so a negative t0_epoch_ms slipped through and BuildEntries shifted every interaction by +|t0|, writing a silently corrupt timeline and exiting 0. The transcript- only exemption (no interactions, no anchor needed) is preserved. - transcribe.Run: derive the audio offset through man.T0(), failing the run when an external recording's manifest carries no usable anchor. Pre-fix a missing t0 made deriveOffset return roughly the whole Unix epoch, writing a transcript ~56 years off and reporting success. The session-audio and explicit -offset paths never consult t0 and are unaffected. Read-side FIFO guard (same class as the write-side fix already shipped): - session: OpenFileNoFollow's symlink+regular-file check is now shared with a new OpenFileNoFollowRead via one openNoFollow core (no third copy). ReadJSONL and LoadManifest route through it, so a FIFO planted at a session artefact is refused rather than blocking open(2) for ever. Write-side messages unchanged. - analyze.Load and analyze.holdsVerdicts: the two sibling os.Open sites the session sweep flagged, now routed through OpenFileNoFollowRead as well. gofmt, vet, go test -race and the sample pipeline all pass; sample output byte-identical. Assisted-by: Claude:claude-opus-4-8
A robustness release: no new commands, but the pipeline no longer accepts malformed or hostile session input in silence. Groups the ~35 fixes since v0.2.0 by theme — evidence-record integrity, robustness against exchanged sessions, and resource lifecycle — and records under Changed that boundary validation is now stricter, refusing schema-violating input that earlier versions accepted and turned into a silently wrong artefact. Assisted-by: Claude:claude-opus-4-8
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.
Three commits, reviewable separately. This is the branch that takes the hunt to genuine convergence and prepares the v0.3.0 release.
What's here
85586c1) — a re-hunt over the previous tree confirmed 7 distinct defects, five of them the same class as a fix from the prior round, left on a sibling path. Each is fixed here and the repo swept for further instances. Includes the round's one major:analyzefindings had notpresence check, so a finding omitting its time filed silently at[00:00].c40ba64) — a further hunt found a major left by the previous round:session.Manifest.T0()was added with a doc comment naming its mandatory callers, then wired to none of them.timeline.Mergeandtranscribe.Runstill read the raw field, so a manifest with an absent or negative anchor silently corrupted the timeline / transcript and reported success. Both now route through the accessor. Also closes the read-side counterpart of the FIFO guard (ReadJSONL,LoadManifest,analyze.Load,holdsVerdicts).2155ec3).Convergence
This branch was driven to a genuinely clean review, not a declared one. The full history across this effort:
T0()guard)The final hunt added a dedicated unwired-guard audit — enumerating every guard, accessor and validator in the repo and confirming each is actually called by every site it protects — precisely because the
T0()bug was a guard that existed but wasn't wired. It found nothing further.Every fix carries a regression test verified failing against the pre-fix code.
gofmt,go vet,go test -race ./...and the sample pipeline all pass; the sample session's merged output is byte-identical.Note on process
The recurring pattern — each round finding real bugs the previous round's "done" missed, five of them siblings of just-applied fixes — is why the later rounds mandate a documented sibling sweep at every fix, and why the final round audits guards for their callers rather than their existence. A fix is not done when the reported line is patched; it is done when its class has been swept.
Assisted-by: Claude:claude-opus-4-8