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
mathias and Claude Sonnet 5.5
7e920102f6
test: SIGTERM cancels the process context; a shutdown mid-job records the row interrupted at once ( #50 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:59:40 +02:00
mathias and Claude Sonnet 5.5
480c7227b5
fix(uploads): bound concurrent request-body receives, 4 total and 2 per user ( #47 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:59:09 +02:00
mathias and Claude Sonnet 5.5
0eb3be9631
test(uploads): concurrent receives are bounded in total and per user ( #47 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:57:31 +02:00
mathias and Claude Sonnet 5.5
e8c5ac50bf
fix(audio): give ffprobe its own 45s deadline, a timeout is the file's fault ( #49 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:56:58 +02:00
mathias and Claude Sonnet 5.5
6101dd4e2f
test(audio): a hung ffprobe times out on its own deadline as unreadable ( #49 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:56:47 +02:00
mathias and Claude Sonnet 5.5
089444c19f
fix(audio): stop reading ffprobe output past a cap and call the file unreadable ( #49 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:56:47 +02:00
mathias and Claude Sonnet 5.5
d44db88787
test(audio): ffprobe output past a cap is unreadable, not buffered ( #49 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:56:37 +02:00
mathias and Claude Sonnet 5.5
1f8bd849fe
fix(audio): cap ffprobe/ffmpeg streams at 32 and narrow the probe output ( #49 )
...
A 900-stream file cost ~570 MB RSS in each tool; with the cap the same file fails
in ~18 MB and is reported as unreadable.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:56:28 +02:00
mathias and Claude Sonnet 5.5
7b19801bfa
test(audio): ffprobe/ffmpeg must cap streams, ffprobe must narrow its output ( #49 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:55:54 +02:00
mathias and Claude Sonnet 5.5
1260500d32
fix(web): refuse cross-origin non-safe requests at the router ( #48 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:55:19 +02:00
mathias and Claude Sonnet 5.5
10b4c43bd2
test(web): foreign-origin POSTs must be refused by the router ( #48 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:55:00 +02:00
mathias and Claude Sonnet 5.5
f1f8b6d02e
fix(task): lint step fails on findings instead of printing 'not installed' ( #41 )
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:54:20 +02:00
mathias and Claude Sonnet 5.5
0d4c5c9d1d
test(lint): task lint must exit non-zero on a finding ( #41 ), red
...
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:53:50 +02:00
mathias and Claude Sonnet 5.5
24d65b2085
docs(sprint): audio upload follow-ups sweep sprint plan, oath and decision list
...
CI / Lint / Test / Vet (push) Successful in 27s
CI / Build & Import (push) Successful in 22s
CI / Deploy via GitOps (push) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 20:50:34 +02:00
mathias and Claude Sonnet 5.5
df7bd459ed
docs(adr): the ingress body-size item is resolved, and uploads are on in production (infra#520)
...
CI / Build & Import (push) Successful in 13s
CI / Deploy via GitOps (push) Successful in 5s
CI / Lint / Test / Vet (push) Successful in 36s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com >
2026-10-03 16:29:32 +02:00
mathias
4a2067063d
feat: upload audio, get a private Swedish transcript, discuss it ( #33 , ADR-033) ( #39 )
...
CI / Deploy via GitOps (push) Successful in 7s
CI / Lint / Test / Vet (push) Successful in 33s
CI / Build & Import (push) Successful in 23s
Upload a recording (audio, or video with the camera off), get a private Swedish transcript, and chat about it.
- ADR-033: RLS-scoped private transcript store; ffprobe/ffmpeg intake; gateway transcription (iguana kb-whisper, berget fallback); in-process single-replica worker; chat over the transcript (local models only).
- ADR-034: optional two-engine mode (pianissimo + kb-whisper) reconciled by a LOCAL model; off unless TAPIR_RECONCILE_BASE_MODEL is set.
- ADR-035: real progress (phases, running/quiet/lost), phase logging, every judged spot stored, merged segments.
- Hardening from four adversarial reviews: errors logged and stored as kinds never text; per-engine deadlines; converted-length check; bounded queue; client hang-ups are not errors; strict local-alias check.
- Dockerfile: static ffmpeg/ffprobe 7.0.2 pinned by sha256 (#34 ). Built and inspected by hand; CI does not build the image on a PR, so its first CI build is this merge.
Uploads stay OFF until TAPIR_UPLOADS_ENABLED is set in the deployment.
Closes #33 , #34 , #42 , #43 , #44 .
Co-authored-by: Mathias <mthbqv@gmail.com >
v0.31.0
2026-10-03 14:13:37 +00:00
mathias
4bafd5f082
fix(web): views.templ imports the pre-rename gitea.d-ma.be host
...
CI / Build & Import (push) Successful in 11s
CI / Deploy via GitOps (push) Successful in 4s
CI / Lint / Test / Vet (push) Successful in 19s
internal/web/views.templ:7 still imports
gitea.d-ma.be/mathias/tapir/internal/adapters/store
while go.mod declares
git.d-ma.be/mathias/tapir
Left behind by the gitea rename (infra ADR-0004). The old hostname still
resolves in DNS but no longer serves — HTTPS to it fails outright — so the
import is genuinely broken, not merely outdated.
Why nothing caught it: the COMMITTED internal/web/views_templ.go is correct,
so builds and CI use a good generated file and stay green. The rot is only in
the source. It surfaces the moment anyone runs `templ generate` — which
regenerates the broken import over the good output, and then the build fails
with
no required module provides package gitea.d-ma.be/mathias/tapir/internal/adapters/store
Found exactly that way while evaluating this repo for the estate-wide lint
config: regenerating templ as part of the check turned a green repo red, and
the cause was the source, not the check.
Source fixed; regenerating now reproduces the committed generated file
byte-for-byte, so views_templ.go is unchanged here. Verified: go build and
go vet pass.
2026-09-05 14:44:39 +02:00
mathias
e3e78e042b
style: apply gofumpt
...
CI / Build & Import (push) Successful in 10s
CI / Lint / Test / Vet (push) Successful in 21s
CI / Deploy via GitOps (push) Successful in 4s
Estate-wide consolidation pass. The canonical .golangci.yml
(infra ci-templates/golangci.yml, infra#309 pattern) enables the gofumpt
formatter; golangci-lint v2 default set enables NO formatter, which is why
this drift accumulated silently -- the same hole that let two files rot in
dma-cli until they were found by hand (dma-cli#12).
Mechanical and deterministic: `gofumpt -w .`, nothing hand-edited. Verified
per repo before commit -- gofumpt -l now reports 0, gofmt -l reports 0, and
go build + go vet both pass.
Clears this repo to adopt the canonical lint config in a later wave.
2026-09-05 12:39:31 +02:00