mathias and Claude Sonnet 5.5
0828f0debf
test(web): the language refusal asserts its message, not a word the form always contains ( #61 )
...
Found by the PR #62 review: the message could be replaced with 'x' and the test stayed green.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:40:47 +02:00
mathias and Claude Sonnet 5.5
7282893877
test(transcribe): WithTimeout hands the engine the job's language, as on the production path ( #61 )
...
The wrapper sits in front of both local engines; a fresh context there would send an auto
upload as language=sv and un-cancel the job, and no test noticed. Found by the PR #62 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:40:35 +02:00
mathias and Claude Sonnet 5.5
cc6fe7083d
refactor(web): drop a length check the closed-set parse already makes ( #61 )
...
CI / Lint / Test / Vet (pull_request) Successful in 36s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
The read is capped at 17 bytes and no valid language is longer than 4, so the parse
refuses anything the length check would; the mutant that removed it survived.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:31:03 +02:00
mathias and Claude Sonnet 5.5
0338b18a17
feat(uploads): choose the language of a recording; record it, show it, carry it to the engines ( #61 )
...
Form field (Swedish preselected, Other = auto) read before the file part and refused
before anything is spooled if outside the closed set; stored on the row (migration 021,
CHECK constraint, default sv for history); carried on the Job and the worker's context;
shown on the status page. Feature scenarios and the coverage map are updated, and
ADR-033/034 amended.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:29:58 +02:00
mathias and Claude Sonnet 5.5
ed9d76b0cf
feat(transcribe): a non-Swedish upload skips the Swedish-only base engine and is not reconciled ( #61 )
...
The other engine transcribes alone, then the cloud fallback if it fails and the job is
still live. A cancelled job never reaches the fallback (mutation-checked).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:26:37 +02:00
mathias and Claude Sonnet 5.5
0b807c6bcd
feat(transcribe): the gateway sends language=sv, omits it for auto, and refuses anything else ( #61 )
...
The request used to hard-code language=sv for every upload, so a recording in another
language was decoded as Swedish. The language now comes from the context; no language in
the context is still sv.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:26:13 +02:00
mathias and Claude Sonnet 5.5
8e4872d2e7
feat(domain): Language, a closed set carried to the engines on the context ( #61 )
...
sv and auto; an empty form value is sv, anything else is refused. LanguageFrom defaults to
sv so a caller that sets nothing behaves as before.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 22:25:51 +02:00
mathias and Claude Sonnet 5.5
4affeb12e8
docs: ADR-034 second blind check protocol; D8 decided (Berget allowed, per-recording local-only opt-out first, #60 ); #37 verified
...
CI / Lint / Test / Vet (push) Successful in 33s
CI / Build & Import (push) Successful in 10s
CI / Deploy via GitOps (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 08:47:10 +02:00
mathias and Claude Sonnet 5.5
460e07719d
docs(sprint): #50 observed live (old pod Completed); #37 and #52 wait for an authenticated look
...
CI / Build & Import (push) Successful in 10s
CI / Lint / Test / Vet (push) Successful in 32s
CI / Deploy via GitOps (push) Successful in 4s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 00:41:07 +02:00
mathias and Claude Sonnet 5.5
7b7da650d4
docs(sprint): v0.31.1 and v0.32.0 shipped; what is observed live and what waits for an authenticated look
...
CI / Deploy via GitOps (push) Successful in 5s
CI / Lint / Test / Vet (push) Successful in 31s
CI / Build & Import (push) Successful in 10s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 00:34:59 +02:00
mathias
85f4cc3236
Merge pull request 'v0.32.0: per-recording delete and nav link, cloud-served note, tracker hardening, bounded LLM reads ( #37 #51 #52 #53 )' ( #58 ) from sprint/v032 into main
CI / Deploy via GitOps (push) Successful in 5s
CI / Lint / Test / Vet (push) Successful in 34s
CI / Build & Import (push) Successful in 11s
v0.32.0
2026-10-03 22:31:26 +00:00
mathias and Claude Sonnet 5.5
41ab1f5d50
fix(web): take the reconciled endpoint apart exactly, so a connector word used as a model name is still judged ( #52 )
...
CI / Lint / Test / Vet (pull_request) Successful in 35s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
Skipping 'by', 'reconciled' and '+' as words everywhere let an alias with one of those
names pass as local. The two-engine shape is now split on its own separators and each alias
judged whole; a reconciler that is not local is pinned too. Hardening suggested by the third
PR #58 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 00:28:09 +02:00
mathias and Claude Sonnet 5.5
67bd0350a3
fix(web): judge every word of a reconciled endpoint that is not a connector, so an unprefixed alias is not called local ( #52 )
...
CI / Lint / Test / Vet (pull_request) Successful in 33s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
The previous version kept only words containing '/' and dropped the rest, so a bare
TAPIR_TRANSCRIBE_MODEL alias in the composite produced a false 'all local' result. Found
by the PR #58 re-review; red tests for a bare alias, an alias with a space and a split
'berget / x' first.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-04 00:22:41 +02:00
mathias and Claude Sonnet 5.5
c24573bd9f
docs: state what the save timeout and a racing delete actually guarantee ( #51 , #37 )
...
CI / Lint / Test / Vet (pull_request) Successful in 29s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped
The tracker comment said 'never a stalled job'; each transition can wait up to the timeout.
The delete refusal is judged at the moment of the attempt. Found by the PR #58 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:32:14 +02:00
mathias and Claude Sonnet 5.5
fc1e8e7ba8
test(web): a foreign post to the recording delete route leaves the recording, on an app that mounts uploads ( #37 , #48 )
...
The earlier entry posted to an app without uploads, where the route does not exist, and
stayed green with the route removed. This one seeds a finished row and goes red without the
gate. Found by the PR #58 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:32:14 +02:00
mathias and Claude Sonnet 5.5
4a0226d8bd
test(llm): the response cap is pinned at its boundary and as the production default ( #53 )
...
Only the 8-byte override was exercised; >= vs >, a huge default and a non-positive option
all stayed green. Also says why the error-body read ignores its error. Found by the PR #58
review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:31:30 +02:00
mathias and Claude Sonnet 5.5
2e54d80a78
test(uploads): jobSink forwards the tracker's timestamp to the store ( #51 )
...
The worker fake ignored the heartbeat time, so the store-boundary half of the app-clock
fix had no assertion. Found by the PR #58 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:31:14 +02:00
mathias and Claude Sonnet 5.5
01c1606caa
test(progress): the default save and heartbeat deadline is pinned, not only the override ( #51 )
...
Every earlier test passed WithSaveTimeout; the worker passes nothing, so the 5 s default
was the only production value and a flip to 0, 1ms or 1h stayed green. Found by the PR #58
review; each flip is now red.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:30:58 +02:00
mathias and Claude Sonnet 5.5
9aa01468ce
fix(web): judge each alias of a reconciled endpoint, so an all-local transcript is not called cloud-served ( #52 )
...
The two-engine path writes '<base> + <alt>, reconciled by <model>'. IsLocalModel is a
single-alias match, so the composite was 'not local' and the note claimed the audio left
the homelab, naming a local host as the provider. Found by the PR #58 review.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:30:44 +02:00
mathias and Claude Sonnet 5.5
25628a9994
test(web): the per-recording delete route is covered by the cross-origin gate ( #37 , #48 )
...
CI / Lint / Test / Vet (pull_request) Successful in 30s
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-03 21:22:24 +02:00
mathias and Claude Sonnet 5.5
a6691ac46b
docs: per-recording delete and the recordings link are built; feature scenarios and coverage map ( #37 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
c909b4e775
feat(web): confirm-then-delete control on a finished or failed recording ( #37 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
f309a39027
feat(web): POST /uploads/{id}/delete, owner-scoped and refused while the recording is active ( #37 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
89611164e3
test(web): per-recording delete is owner-scoped, refused while active, offered only when finished ( #37 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
93860210ef
feat(store): DeleteUpload removes a finished upload of the owner ( #37 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
8509004eb7
test(store): an owner can delete a finished upload; an active or foreign one is refused ( #37 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
453464a22b
feat(web): the home list links to recordings when uploads are mounted ( #37 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
4ef3e85d16
test(web): the home list links to recordings only when uploads are mounted ( #37 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
b8af7f32c7
fix(progress): stamp the heartbeat with the application clock the page compares it with ( #51 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
813192e5ba
test: heartbeats are stamped with the application clock, not the database's NOW() ( #51 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
2ec1557a8c
fix(progress): bound every save and heartbeat write so a hung database cannot stall the job ( #51 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
68815755e8
test(progress): a hung save or beat must not stall the reporter or the heartbeat ( #51 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
ba18668796
docs(feature): cloud-served transcripts say the audio left the homelab; empty transcript also triggers the fallback ( #52 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
a65f2f2492
feat(web): say in plain words when a recording's audio left the homelab ( #52 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
a43ee19505
feat(web): helper naming the cloud provider of a transcript, one definition of local ( #52 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
4301e691f5
test(web): a cloud-served transcript says the audio left the homelab ( #52 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
61d1ff2255
fix(llm): read a bounded response body, 8 MiB on success and the error bound on failure ( #53 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias and Claude Sonnet 5.5
9cc954df40
test(llm): the client reads a bounded response body, success and error ( #53 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:22:17 +02:00
mathias
e037c6b683
Merge pull request 'v0.31.1: cross-origin POST protection, ffprobe/ffmpeg limits, receive cap, SIGTERM, lint gate ( #41 #47 #48 #49 #50 )' ( #55 ) from sprint/audio-followups into main
CI / Deploy via GitOps (push) Successful in 6s
CI / Lint / Test / Vet (push) Successful in 30s
CI / Build & Import (push) Successful in 10s
v0.31.1
2026-10-03 19:19:55 +00:00
mathias and Claude Sonnet 5.5
5baffd0189
fix(test): strip colour codes before looking for the lint skip notice (CI run 8937)
...
CI / Lint / Test / Vet (pull_request) Successful in 30s
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-03 21:18:05 +02:00
mathias and Claude Sonnet 5.5
228bcc77da
test(lint): the skip notice is found behind CI's colour codes, red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:18:01 +02:00
mathias and Claude Sonnet 5.5
4ef446548d
docs(adr): spool arithmetic and the unbounded slow-drip limitation for the receive cap ( #47 )
...
CI / Lint / Test / Vet (pull_request) Failing after 30s
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-03 21:12:48 +02:00
mathias and Claude Sonnet 5.5
145949875e
fix(audio): keep a bounded head of ffmpeg's output instead of buffering all of it ( #49 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:12:48 +02:00
mathias and Claude Sonnet 5.5
82aeac7c19
fix(store): FailUpload only fails a queued or transcribing upload (review of #55 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:12:48 +02:00
mathias and Claude Sonnet 5.5
1b4747ed03
test: FailUpload must not overwrite a finished upload; ffmpeg stderr is bounded, red (review of #55 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:12:34 +02:00
mathias and Claude Sonnet 5.5
9939afb90c
test: pin the production receive limits, split the vacuous drain test, harden the lint-gate test (review of #55 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:12:34 +02:00
mathias and Claude Sonnet 5.5
3e69c00a64
docs(adr): ADR-033 amended for SIGTERM handling and the recorded deploy limitation ( #50 , #47 )
...
CI / Lint / Test / Vet (pull_request) Failing after 31s
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-03 21:00:55 +02:00
mathias and Claude Sonnet 5.5
253aa567aa
fix(serve): handle SIGTERM and wait for in-flight requests and the worker before exiting ( #50 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:00:55 +02:00
mathias and Claude Sonnet 5.5
5644dc3fc8
fix(uploads): record a job interrupted by shutdown at once, on its own short context ( #50 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 21:00:55 +02:00
mathias and Claude Sonnet 5.5
7df1de6628
test(serve): shutdown waits for in-flight requests and the worker, bounded ( #50 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:59:57 +02:00