From the poka-yoke audit of 2026-09-04. Lens: fixed-value. Today: rung 0. Device reaches: rung 2 (Warning). Silent, and confinement-adjacent.
The mistake available
Add a fifth destination kind — an HLS or WHIP output — to internal/db and not
to internal/ffmpeg.
Two independent declarations of four values each:
internal/db/destinations.go:18-28 and internal/ffmpeg/build.go:831-842,
joined by ffmpeg.DestKind(row.Kind) at internal/engine/destinations.go:443
and internal/api/expert.go:436. That conversion compiles for any string.
What happens
internal/engine/destinations.go:693:
func destWritesAFile(row *db.Destination) bool {
switch row.Kind {
case db.DestFile: return true
case db.DestAudio: return !strings.Contains(row.URL, "://")
default: return false // a new file-writing kind lands here
}
}
The comment above it states the stake: "Without this an audio file target would
be written relative to the process working directory, outside the confinement
every other file destination has." A new kind silently inherits false.
Separately, build.go:1286 and build.go:1368 switch on s.Kind over
RTMP/SRT/File with no default — a fifth kind emits no -f at all and lets
FFmpeg guess the muxer from the target string. build.go:1364 warns about
exactly this in prose.
Today
Rung 0. db.Destination.Validate has a hand-listed
case DestRTMP, DestSRT, DestFile, DestAudio: that must be remembered too.
Device → rung 2, Warning
exhaustive in golangci-lint with default-signifies-exhaustive: false, plus a
default: arm in destWritesAFile that returns true — fail closed. The
confinement is cheap; the alternative is an arbitrary-file-write primitive.
What stops Control: it would need ffmpeg to import db's type rather than
redeclaring it, and the redeclaration is deliberate — internal/ffmpeg is
dependency-free by design. The linter is the honest ceiling.
From the poka-yoke audit of 2026-09-04. Lens: fixed-value. Today: rung 0. Device reaches: rung 2 (Warning). Silent, and confinement-adjacent.
The mistake available
Add a fifth destination kind — an HLS or WHIP output — to
internal/dband notto
internal/ffmpeg.Two independent declarations of four values each:
internal/db/destinations.go:18-28andinternal/ffmpeg/build.go:831-842,joined by
ffmpeg.DestKind(row.Kind)atinternal/engine/destinations.go:443and
internal/api/expert.go:436. That conversion compiles for any string.What happens
internal/engine/destinations.go:693:The comment above it states the stake: "Without this an audio file target would
be written relative to the process working directory, outside the confinement
every other file destination has." A new kind silently inherits
false.Separately,
build.go:1286andbuild.go:1368switch ons.KindoverRTMP/SRT/File with no
default— a fifth kind emits no-fat all and letsFFmpeg guess the muxer from the target string.
build.go:1364warns aboutexactly this in prose.
Today
Rung 0.
db.Destination.Validatehas a hand-listedcase DestRTMP, DestSRT, DestFile, DestAudio:that must be remembered too.Device → rung 2, Warning
exhaustivein golangci-lint withdefault-signifies-exhaustive: false, plus adefault:arm indestWritesAFilethat returnstrue— fail closed. Theconfinement is cheap; the alternative is an arbitrary-file-write primitive.
What stops Control: it would need
ffmpegto importdb's type rather thanredeclaring it, and the redeclaration is deliberate —
internal/ffmpegisdependency-free by design. The linter is the honest ceiling.