Commit Graph
100 Commits
Author SHA1 Message Date
mathiasandClaude Sonnet 5.5 c9b7df9f95 feat(config): TAPIR_TRANSCRIBE_ENGINE_TIMEOUT, default 25 minutes (review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:42:46 +02:00
mathiasandClaude Sonnet 5.5 c8ec468e47 feat(transcribe): WithTimeout -- each engine call gets its own deadline so a wedged engine fails while the job lives (review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:42:46 +02:00
mathiasandClaude Sonnet 5.5 81a60d5fd4 test: a per-engine deadline so a wedged primary reaches the fallback (red; adversarial review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:41:38 +02:00
mathiasandClaude Sonnet 5.5 c8c7356f19 test: a per-engine deadline so a wedged primary reaches the fallback (red; adversarial review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:41:38 +02:00
mathiasandClaude Sonnet 5.5 8d1b7d887f test: a per-engine deadline so a wedged primary reaches the fallback (red; adversarial review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:41:38 +02:00
mathiasandClaude Sonnet 5.5 21b337702a test: a per-engine deadline so a wedged primary reaches the fallback (red; adversarial review F4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:41:38 +02:00
mathiasandClaude Sonnet 5.5 d16c2998d0 test(reconcile): the stored reason is a kind -- the old assertion encoded the leak the review found
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 fb79dbb045 fix(uploads.go): an error reaches the log, the row and the page as a kind, never its text (adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 a2587eae9b fix(worker.go): an error reaches the log, the row and the page as a kind, never its text (adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 0b35278cdf fix(transcribe): an error reaches the log, the row and the page as a kind, never its text (adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 16a8833f79 fix(reconcile.go): an error reaches the log, the row and the page as a kind, never its text (adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 03a122c9f5 fix(tracker.go): an error reaches the log, the row and the page as a kind, never its text (adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:55 +02:00
mathiasandClaude Sonnet 5.5 31f5a74d2a test(web): the upload routes' error paths log a kind, not the text (red; review F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:10 +02:00
mathiasandClaude Sonnet 5.5 166ff849c0 test(uploads): a failure logs a kind, never the error text or the spool path (red; review F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:10 +02:00
mathiasandClaude Sonnet 5.5 e9863c2e12 test(progress): a keyed failure logs its kind, not the error's text (red; review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:10 +02:00
mathiasandClaude Sonnet 5.5 8f3300b377 test(transcribe): a failed engine's reason is a kind, not its error text (red; review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:10 +02:00
mathiasandClaude Sonnet 5.5 f6c3f2af23 test(reconcile): the skipped reason carries a kind, not the model's text (red; review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:40:10 +02:00
mathiasandClaude Sonnet 5.5 2d1b08458b feat(transcribe): StatusError.HTTPStatus -- its code, never its snippet, becomes the kind (review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:38 +02:00
mathiasandClaude Sonnet 5.5 2608ad2f09 feat(llm): HTTPError -- a status code to branch on, a bounded body in the text (review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:38 +02:00
mathiasandClaude Sonnet 5.5 81f3d7ffc6 test(transcribe): a StatusError exposes its code as a kind, not its snippet (red; adversarial review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:25 +02:00
mathiasandClaude Sonnet 5.5 8c82d67b12 test(llm): a non-200 is an HTTP status error whose kind carries no body, and the body is bounded (red; adversarial review F3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:25 +02:00
mathiasandClaude Sonnet 5.5 d8eea66c4c feat(errkind): Of -- a kind from a fixed vocabulary, never the error's text (review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:10 +02:00
mathiasandClaude Sonnet 5.5 dc0c64ddeb test(errkind): an error reduced to a safe kind, never its text (red; adversarial review F3, F5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:39:04 +02:00
mathiasandClaude Sonnet 5.5 99ac5580e0 test(web): the upload chat helper says which models are offered
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 ef815edded fix(web): upload chat offers and accepts local models only and fails closed; a forged cloud model is replaced before anything is sent (review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 4933504982 feat(web): App.UploadChatModels -- the models upload chat offers and accepts (review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 e121ef241d fix(cmd): wire the local-only chat models into the upload routes (review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 5ae9212869 feat(cmd): uploadChatModels -- the chat switcher for a private recording is local models only (review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 a9a2a9270f fix(config): a strict shape for a local model alias; the upload chat model must be local (adversarial review F1, F8)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:38:30 +02:00
mathiasandClaude Sonnet 5.5 7fe746173d test(web): the upload chat offers and accepts local models only, and fails closed (red; adversarial review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:37:49 +02:00
mathiasandClaude Sonnet 5.5 4b16e33715 test(cmd): the upload chat switcher never offers a cloud model (red; adversarial review F1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:37:49 +02:00
mathiasandClaude Sonnet 5.5 896ce6a952 test(config): a strict shape for a local model alias, and the upload chat model must be local (red; adversarial review F1, F8)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 16:37:49 +02:00
mathiasandClaude Sonnet 5.5 7029dd1d7f test(e2e): a finished job's phases are all closed and it was reporting while it ran (ADR-035)
CI / Lint / Test / Vet (pull_request) Successful in 23s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:05:36 +02:00
mathiasandClaude Sonnet 5.5 c977618979 docs(claude): the progress tracker, the two timestamps, and the log's privacy rule (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:04:32 +02:00
mathiasandClaude Sonnet 5.5 0763e6238b docs(data-model): progress, progress_at, alive_at, and every judged spot stored (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:04:32 +02:00
mathiasandClaude Sonnet 5.5 6722433eb0 test(acceptance): map the progress, log and judged-spot scenarios to their covering tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:04:23 +02:00
mathiasandClaude Sonnet 5.5 ac75971030 docs(use-cases): scenarios for progress, the log and the judged spots (ADR-035) -- the coverage gate is red until they are mapped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:04:19 +02:00
mathiasandClaude Sonnet 5.5 02a065b826 test(web): opt-in renderer of every progress state for a screenshot review (TAPIR_SHOT_DIR)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:03:55 +02:00
mathiasandClaude Sonnet 5.5 105777f1aa fix(web): the spinner sits in the same mark column as the other glyphs; a lost job's running phase gets a warning mark (screenshot review)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:03:55 +02:00
mathiasandClaude Sonnet 5.5 18d8050a2b fix(web): the progress bar ends at the time column and the lost mark is error-coloured (screenshot review)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:03:55 +02:00
mathiasandClaude Sonnet 5.5 c06d285a3a test(web): the lost job's running phase carries a warning mark (red; found in the screenshot review)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:03:32 +02:00
mathiasandClaude Sonnet 5.5 f74fbbc40e test(cmd): the uploads store double has the progress methods the worker now needs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:01:37 +02:00
mathiasandClaude Sonnet 5.5 cd7595a048 feat(web): a spot shows the words before it, and an empty list shows no section (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:01:21 +02:00
mathiasandClaude Sonnet 5.5 24d1a99ed0 feat(web): list only the spots to check, in order and capped (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:01:21 +02:00
mathiasandClaude Sonnet 5.5 8cb0b0a12d test(web): the kept-spot assertion looks for what the page actually renders (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:56 +02:00
mathiasandClaude Sonnet 5.5 6dfd53ac71 test(web): the page lists only changed and uncertain spots, with the words before each, though every judged spot is stored (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:49 +02:00
mathiasandClaude Sonnet 5.5 d62331b5f9 test(web): the quiet note is capitalised as the page writes it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:23 +02:00
mathiasandClaude Sonnet 5.5 a7668b670e feat(web): the upload page shows the job's phases, a bar only where the count is real, and says when the service is lost (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:23 +02:00
mathiasandClaude Sonnet 5.5 89c9dd6705 feat(web): tell running from quiet from lost; poll every two seconds (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:23 +02:00
mathiasandClaude Sonnet 5.5 d1dcb131f2 feat(web): progress styles in tapir's own tokens -- a mono step log, a CSS spinner that respects reduced motion (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 09:00:23 +02:00
mathiasandClaude Sonnet 5.5 d0f2dcf838 test(web): the page shows real phases, tells running from quiet from lost, and never invents a percentage (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:57:58 +02:00
mathiasandClaude Sonnet 5.5 a97598586c test(reconcile): a span across a segment edge leaves neither segment holding a replaced word -- a mutation that skipped this survived
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:56:53 +02:00
mathiasandClaude Sonnet 5.5 976aeb71c6 feat(reconcile): report the comparison and deciding phases, store every judged spot, merge the words into the segments (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:56:53 +02:00
mathiasandClaude Sonnet 5.5 f74ad726e2 feat(domain): a judged spot carries the few words before it (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:56:53 +02:00
mathiasandClaude Sonnet 5.5 9297f728c2 test(reconcile): every judged spot with its left context; segments rewritten per segment, or left alone when they do not line up (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:55:43 +02:00
mathiasandClaude Sonnet 5.5 520ab666f8 test(reconcile): the comparison and the deciding phase report real counts, and a shutdown is neither done nor failed (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:55:43 +02:00
mathiasandClaude Sonnet 5.5 0b7bf08c95 test(reconcile): kept spots are stored, segments carry the merged words, the cap is an option -- three old assertions changed on purpose (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:55:43 +02:00
mathiasandClaude Sonnet 5.5 aefc8103f7 feat(transcribe): the ensemble declares and reports its phases; a failed engine shows failed, a shutdown does not (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:54:31 +02:00
mathiasandClaude Sonnet 5.5 f064dec185 test(transcribe): the ensemble declares and reports its phases; a failed engine is shown failed, a shutdown is not (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:54:07 +02:00
mathiasandClaude Sonnet 5.5 c6319b9bc6 refactor(uploads): the worker's own failure is FailRunning
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:43 +02:00
mathiasandClaude Sonnet 5.5 5f279d7e71 feat(progress): keyed Fail for a soft failure, Note for the operator, FailRunning for the job's own (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:43 +02:00
mathiasandClaude Sonnet 5.5 a6b8a2b744 test(progress): a keyed soft failure that logs why, a note that costs no write, and FailRunning for the job's own failure (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:33 +02:00
mathiasandClaude Sonnet 5.5 9393c27cdb test(uploads): the worker waits for its heartbeat to finish -- a mutation that skipped the wait survived until now
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:10 +02:00
mathiasandClaude Sonnet 5.5 538ed93ccd test(uploads): a slow heartbeat write, so one is in flight when the job ends
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:10 +02:00
mathiasandClaude Sonnet 5.5 27a88a0a1f feat(uploads): the worker reports real phases, beats on its own, and logs each one (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:53:10 +02:00
mathiasandClaude Sonnet 5.5 eb4d4b67e6 test(uploads): the worker reports real phases, beats on its own, and logs them in order without the transcript (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:52:20 +02:00
mathiasandClaude Sonnet 5.5 3f66c35497 test(uploads): the worker's store double records progress saves and heartbeats
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:52:20 +02:00
mathiasandClaude Sonnet 5.5 f8526d4549 feat(store): SaveProgress and Heartbeat; Get returns the phases and both timestamps (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:51:39 +02:00
mathiasandClaude Sonnet 5.5 41ebba3963 feat(store): migration 020 -- uploaded_transcripts.progress, progress_at, alive_at (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:51:11 +02:00
mathiasandClaude Sonnet 5.5 256e5b1a66 test(store): progress and heartbeat on an upload row -- round trip, alive is not progress, another user's write changes nothing (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:51:04 +02:00
mathiasandClaude Sonnet 5.5 8ec43ad393 test(progress): read the log buffer safely while the heartbeat writes to it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:50:39 +02:00
mathiasandClaude Sonnet 5.5 4bfe578a05 feat(progress): Tracker -- one writer for the page and the log, throttled counts, a heartbeat of its own (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:50:39 +02:00
mathiasandClaude Sonnet 5.5 c9ebe526cc feat(domain): progress steps and the two timestamps that tell alive from progressing (ADR-035)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:50:39 +02:00
mathiasandClaude Sonnet 5.5 7bf5f6b8b7 test(progress): a tracker that shows the plan, times each step, throttles counts and heartbeats on its own (red)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:49:44 +02:00
mathiasandClaude Sonnet 5.5 7e9f5d7ca5 docs(adr): ADR-035 -- progress as real phases, the same transitions in the log, every judged spot kept (#42 #43 #44)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:49:06 +02:00
mathiasandClaude Sonnet 5.5 1a89eb3868 docs(adr-034): record the first blind check; bar ambiguity and the unanswered second condition
CI / Lint / Test / Vet (pull_request) Successful in 23s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:01:31 +02:00
mathiasandClaude Sonnet 5.5 2e9d76dad0 docs(research): first blind check of two-engine reconcile on a real recording (aggregates only)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:01:31 +02:00
mathiasandClaude Sonnet 5.5 7f8e3677b3 docs(adr-034): gemma4-31b slowness explained; reopen the 26B-vs-31B reconciler choice
CI / Lint / Test / Vet (pull_request) Successful in 22s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 07:13:10 +02:00
mathiasandClaude Sonnet 5.5 e3aa661cf2 docs(research): Low Power Mode confirmed as the cause of slow gemma4-31b (22.3 vs 7.9 tok/s decode)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 07:13:10 +02:00
mathiasandClaude Sonnet 5.5 7ae888a468 docs(claude): two-engine reconciliation, and that task check does not gate lint (#41)
CI / Lint / Test / Vet (pull_request) Successful in 21s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:47 +02:00
mathiasandClaude Sonnet 5.5 b9e0dfa1c9 docs(homelab): two-engine mode, its settings and why every model must be local
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:47 +02:00
mathiasandClaude Sonnet 5.5 8dbcb9a9eb docs(data-model): reconciliation column
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:47 +02:00
mathiasandClaude Sonnet 5.5 26cc00c1cc test(acceptance): map the two-engine scenarios to their covering tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:37 +02:00
mathiasandClaude Sonnet 5.5 36a80ac4f5 docs(use-cases): scenarios for two-engine reconciliation (ADR-034)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:22 +02:00
mathiasandClaude Sonnet 5.5 2497554683 docs(adr): ADR-034 records the first live smoke, including the wrong call
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:22 +02:00
mathiasandClaude Sonnet 5.5 c3c9b1e48a test(e2e): two engines + local reconciler, live
TAPIR_E2E_RECONCILE=1 runs pianissimo + kb-whisper + gemma4-26b on the audio and
asserts the reconciliation is recorded, every contributor is named in the endpoint, and
the page says what was done. Run 2026-10-01 on 82 s of synthetic Swedish: 3 disputes, all
3 changed; against the known script 2 were right (virket, a missing 'procent') and 1 was
WRONG (Maria -> Vi replaced a correct base reading). A smoke test, not a measurement.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:27:22 +02:00
mathiasandClaude Sonnet 5.5 ed8ca54674 feat(cmd): buildTranscriber -- the base-engine setting turns on the two-engine ensemble
Default is the single-engine chain exactly as before. With TAPIR_RECONCILE_BASE_MODEL set,
the base engine and the primary run on the same WAV and a LOCAL model (config has already
refused any non-local alias) reconciles them, at temperature 0 with a short reply -- the
conditions its accuracy was measured under. The cloud fallback is unchanged and runs
only when both local engines fail.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:26:02 +02:00
mathiasandClaude Sonnet 5.5 7338d9d603 test(e2e): discard the deferred Close error golangci-lint flags
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:26:02 +02:00
mathiasandClaude Sonnet 5.5 3d755fd57a fix(transcribe): check (discard) the deferred Close errors golangci-lint flags
Found because the project's lint step cannot fail: the Taskfile runs
'golangci-lint run ./... || echo "not installed -- skipping"', so a failing lint
prints that message and exits 0. CI's log showed these findings and still passed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:26:02 +02:00
mathiasandClaude Sonnet 5.5 b492a3144e test(cmd): the base-engine setting turns on the ensemble, and nothing else does (red)
Red: buildTranscriber is undefined.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:25:10 +02:00
mathiasandClaude Sonnet 5.5 505670c0e1 feat(llm): WithTemperature, default unchanged
Zero is sent as zero (the field has no omitempty). The reconciler's measured accuracy
was at temperature 0, so it runs there; every other caller keeps 0.2.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:25:10 +02:00
mathiasandClaude Sonnet 5.5 7891675393 test(llm): a temperature option; zero is sent as zero, not 'unset' (red)
The reconciler was measured at temperature 0 but the client hardcodes 0.2. Zero must
be sent explicitly, and the default must not change for existing callers.

Red: WithTemperature is undefined.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:54 +02:00
mathiasandClaude Sonnet 5.5 8110fe56ab style(config): gofumpt the new test rows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:38 +02:00
mathiasandClaude Sonnet 5.5 61fb50ce99 feat(config): two-engine reconciliation settings with a local-only guard (ADR-034)
TAPIR_RECONCILE_BASE_MODEL turns it on and needs TAPIR_RECONCILE_MODEL; every model must
be a local alias (koala/ or iguana/, matched as a PREFIX): a cloud adjudicator is a
start-up error because private meeting content must not reach it; the two engines must
differ; default job timeout 60m. Off by default. Mutation-checked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:34 +02:00
mathiasandClaude Sonnet 5.5 f25fdaf398 test(config): a cloud alias that merely contains a local host name is still cloud
Mutation-testing showed a substring match instead of a prefix match went unnoticed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:34 +02:00
mathiasandClaude Sonnet 5.5 ad071d44cb test(config): reconciliation settings -- off by default, local only, complete (red)
Off by default; a base engine needs an adjudicator; every model must be a local alias
(koala/ or iguana/): a cloud adjudicator is a start-up error because private meeting
content must not reach it; the base engine must differ from the other engine; default
job timeout 60m (two engines plus adjudication).

Red: the Config fields do not exist.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:20 +02:00
mathiasandClaude Sonnet 5.5 59f2893434 docs(adr): ADR-034 names the settings for what they are
TAPIR_RECONCILE_BASE_MODEL, not 'second model': the engine added to turn the
feature on is the one whose TEXT is the base, and the old name hid that. All three
models must be local aliases; the base must differ from the other engine. ADR is
still Proposed, so this is an in-place correction.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:24:09 +02:00
mathiasandClaude Sonnet 5.5 6fb7a52980 feat(web): say what reconciliation did, and never claim a second opinion that was not there
CI / Lint / Test / Vet (pull_request) Successful in 21s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Reconciled: the two engines, the deciding model and the exact counts; the contested
spots (changed or uncertain) listed with a minute mark and both readings, the first
50 shown and the rest counted from the exact totals. Single-engine and
model-unavailable results say why. A nil reconciliation renders nothing. Readings are
escaped. Mutation-checked: the cap, the minute rounding and the 'more' count.

uploads.go and the templ pair are one commit: the helpers and the template need each other.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:23:39 +02:00
mathiasandClaude Sonnet 5.5 d6ba11d288 test(web): the page says what reconciliation did, plainly, and never claims more (red)
Reconciled: who the two engines and the deciding model were, and the counts
(differences, settled automatically, decided by the model, uncertain). The contested
spots are listed with a minute mark, both readings and which was used, uncertain ones
marked, readings escaped, and a very long list shortened with its true count. A
single-engine transcript makes no claim of a second opinion; one-engine and
model-unavailable cases say why.

Red: the page renders none of this yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:23:00 +02:00
mathiasandClaude Sonnet 5.5 ae4f9fd775 feat(store): persist and read back the reconciliation
CompleteUpload writes it (SQL NULL when there was none, never the JSON text 'null':
the page claims a second opinion only if the column is non-NULL); GetUpload reads it,
List does not. Mutation-checked.

domain.go and the store are one commit: the store tests need the new field.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 23:22:09 +02:00