Repository navigation
Conversation
transcripted-qa-bench.sh writes its report and then exits 1 when a step FAILed or 3 when a step was skipped or held (always the case with --skip-build). LabExperimentRunner treated any nonzero exit as a failed process and never ran QAResultsAnalyzer, so those runs lost their whole breakdown. Now exit 1/3 with a results.tsv on disk gets analyzed (FAIL rows still become hard gates, exit 3 adds a warning); timeouts, other exit codes, and runs with no results still fail as before.
runScenario never removed launch-ui-smoke.json from a previous run, and the default --output is a fixed /tmp path, so an app that crashed before reporting would decode the old report and PASS. Remove it before the launch so only this run's report counts.
meeting-series kept <work>/shared-db across runs, so a --force rerun (or a fresh run over a work root an earlier run used) started with every voice the last run learned, and fresh_db=false meetings silently matched people they should have met for the first time. Now only a plain resume (no --force, some shared-DB meeting already finished) keeps it; every other run clears it, and only after checking the path is under the run's own work root. Promise checks run in autoeval-self-test.
results.tsv exists from the script's first line, so it can't prove write_report ran. A set -u abort after a few PASS steps, or the cd "$REPO_ROOT" || exit 1 failure, exits 1 with a partial results file and got scored as passed or warning. Now exit 1/3 counts only when qa-report.md exists, and exit 1 also needs a FAIL row.
Keying resume off lab_result.json alone could still keep a polluted DB: retrying a failed mid-series meeting after later ones finished, resuming with a different --work, or switching --embedder-* (a different DB file). prepare() now writes lab-shared-db.json into shared-db with the set, work root, ordered shared meetings, backend, DB file, and --embedder-* flags, and recordApplied() appends each shared meeting as it finishes. A run resumes only when the marker matches and the meetings in the DB are exactly the finished ones, in series order with no gap; otherwise it starts empty. Every run logs whether it resumed or reset and why.
Review round 2 on the shared-DB marker: - The marker now records the shared meeting in progress before the pipeline can write voices, and clears it when lab_result.json lands. A run killed mid-meeting no longer resumes on its partial voices. - When the DB can't be resumed but finished meetings exist and --force isn't set, meeting-series stops with the reason and asks for --force instead of running the rest of the series on an empty DB. - The fingerprint covers every flag except --only/--limit/--force (order-free) plus sha256 of the --embedder-thresholds file and the TRANSCRIPTED_LAB_KNOBS_FILE knobs file, so --calendar-naming, --separation, --sep-*, --no-invite and --speaker-hint changes count.
This was referenced Oct 7, 2026
Owner
Author
|
Split into one draft PR per bug, at Justin's request. Same reviewed code (approved with nits after 3 review rounds here):
Closing this one; branch claude/sweep-fix-tools is kept. |
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 confirmed bugs from the Haiku sweep, all in internal tools. Test first each time. The first 3 commits are the original fixes; the next 2 fix review round 1, and the last one fixes round 2.
Speaker lab: shared speaker DB leaked between runs
meeting-serieskept<work>/shared-dbforever, so a--forcererun (or a fresh run over a work root an earlier run used) started with every voice the last run learned. fresh_db=false meetings then matched people they were supposed to meet for the first time, and lab_result.json / naming rows looked better than they were.MeetingLabSharedDB.swift): before the first meeting,prepare()reads alab-shared-db.jsonmarker in shared-db.--only/--limit/--force(flag order doesn't matter), and sha256 of the--embedder-thresholdsfile and theTRANSCRIPTED_LAB_KNOBS_FILEknobs file.inProgress: <id>.recordApplied()clears it and adds the meeting once its lab_result.json is written.--force, the marker matches this run, nothing is marked in progress, and the meetings in the DB are exactly the finished ones (first N in series order, no gap).--force. It only deletes after checking the path is under the run's own work root (refuses..escapes and the root itself).--force, leaving the DB untouched, for any other mismatch while finished meetings exist. Examples: a meeting killed mid-run, a failed mid-series meeting retried after later ones finished, a different--work, changed flags (--calendar-naming,--separation,--sep-*,--speaker-hint,--embedder-*), edited thresholds or knobs files, or a DB with no marker. The error says why. It doesn't silently run the rest of the series on an empty DB.resumedorstarting empty (<reason>).--force --only m3now runs m3 against an empty shared DB, not one holding m1/m2's voices. To rerun one mid-series meeting properly, rerun the series from the start with--force.runMeetingLabSharedDBSelfTests()inspeaker-eval-harness autoeval-self-test. It drivesprepare/beginMeeting/recordApplied/fingerprintArgs/fileHashesagainst real files in a temp work root, and lists every failed promise. The package has no XCTest target.--force,--calendar-naming, and the thresholds/knobs hashes.agent-check.py, which won't run a bare-path command (already true on main). SpeakerEvalHarness is also inTOOLS_WITHOUT_CI, socheck.shand CI don't cover it. I ran it by hand on this head: PASS. TherunMeetingSeriescall sites (prepare before the loop, beginMeeting before the pipeline, recordApplied after lab_result.json, die on refusal) aren't covered by any test, because they need Parakeet and the diarizer models.Lab: qa-bench exit 1/3 never got scored
transcripted-qa-bench.sh'swrite_reportwrites qa-report.md and results.tsv, then returns 1 on any FAIL row and 3 on any SKIP or hard-WARN row.--skip-buildalways records a SKIP, so it always exits 3.LabExperimentRunnertreated any nonzero exit as a dead process and returned beforeQAResultsAnalyzerran, so the run showed as Failed with no breakdown.write_report.cd "$REPO_ROOT" || exit 1,set -uaborts).write_reportstill fail like before.QABenchExitCodeTests, a fake repo with a fake qa-bench script):testQABenchHoldExitStillScoresSkippedRun,testQABenchHoldExitIsNotReportedAsAPass,testQABenchFailExitKeepsStepBreakdown: red ("Experiment process exited with code 3.") then green.testQABenchAbortAfterPassingStepsStillFails(was passed),testQABenchAbortWithEmptyResultsStillFails(was warning) andtestQABenchFailExitWithoutFailRowsStillFails(was passed) went red, then green.testQABenchCrashWithoutReportStillFailsandtestQABenchUnknownExitStillFailsEvenWithReportguard the failure side.QA: Sparkle smoke passed on a stale report
runScenarionever removedlaunch-ui-smoke.jsonfrom an earlier run, and the default--outputis a fixed /tmp path. An app that crashed before reporting would decode the old report and PASS.testScenarioDoesNotPassOnLaunchReportLeftByEarlierRun(fake app script that writes nothing; was PASS, now fails onlaunch-report) andtestScenarioPassesOnLaunchReportWrittenByThisLaunch(a fresh report still counts).runScenariowent from private to internal so the test can drive it without the native-smoke isolation gate. The fake app is a shell script, never the real app.Checks
swift test --package-path Tools/TranscriptedLab --jobs 4: 16 tests passTools/TranscriptedLab/script/build_and_run.sh --verify(run by hand): passswift test --package-path Tools/TranscriptedQA: 94 tests passbash build-deps.sh --force,swift build --package-path Tools/SpeakerEvalHarness,speaker-eval-harness autoeval-self-test(run by hand): PASSbash check.sh: everything else passed. It reports two BLOCKED (invalid-command):build_and_run.sh --verifyandspeaker-eval-harness autoeval-self-test. That'sagent-check.pyrefusing bare-path matrix commands, already true on main. Neither one runs incheck.sh; I ran both by hand.Independent review: changes requested (round 2), fixes pushed, re-review pending
🤖 Generated with Claude Code