From the poka-yoke audit of 2026-09-04. Lens: contact. Today: rung 3, for three files only. Device reaches: rung 2 (Warning). Silent.
The mistake available
Add a read to a dialog and use the empty array as the failure value.
ui/src/components/DestinationDialog.tsx:727,731,732,741,749:
api.listAccounts().then(setAccounts).catch(() => setAccounts([]));
api.listRenditions().then(setRenditions).catch(() => setRenditions([]));
ui/src/lib/readState.ts exists precisely to make that unwriteable. Its header
calls itself "a CONTROL rather than a warning" because mayClaim is a type
guard. This file never imports it.
What happens — and it drives the operator to act
- A failed
listRenditions() renders, at :1502, the sentence "No shared
encodes yet. Create one on the Renditions page first." and disables the
shared-encode radio. That is a positive claim, and it sends the operator to
build a second real encode they do not need.
- A failed
listAccounts() replaces the account picker with a "Connect
{platform} account" button linking to the OAuth consent flow
(:1306-1310) — a re-authorisation for an account that is already linked,
which also discards the half-filled dialog.
Today
Rung 3, and only for three files. ui/src/lib/readState.test.ts:51,72,73,74
enforces the rule by asserting that specific source string literals are
absent from SettingsPage.tsx and AutomationPage.tsx. That is a
hand-maintained list of filenames — training, not a device. It does not know
DestinationDialog.tsx exists.
Device → rung 2, Warning
An ESLint no-restricted-syntax rule matching a .catch() whose body is a
single setX([]) or setX(null), run as a required check.
Control would mean the read helpers in ui/src/lib/api.ts returning
ReadState<T>, so an empty array has no spelling on a failed read. strict: true
is on and there are only six anys repo-wide, so the type system is available —
but it touches every caller.
What stops the Warning today: there is no ESLint config in the repository
at all.
From the poka-yoke audit of 2026-09-04. Lens: contact. Today: rung 3, for three files only. Device reaches: rung 2 (Warning). Silent.
The mistake available
Add a read to a dialog and use the empty array as the failure value.
ui/src/components/DestinationDialog.tsx:727,731,732,741,749:ui/src/lib/readState.tsexists precisely to make that unwriteable. Its headercalls itself "a CONTROL rather than a warning" because
mayClaimis a typeguard. This file never imports it.
What happens — and it drives the operator to act
listRenditions()renders, at:1502, the sentence "No sharedencodes yet. Create one on the Renditions page first." and disables the
shared-encode radio. That is a positive claim, and it sends the operator to
build a second real encode they do not need.
listAccounts()replaces the account picker with a "Connect{platform} account" button linking to the OAuth consent flow
(
:1306-1310) — a re-authorisation for an account that is already linked,which also discards the half-filled dialog.
Today
Rung 3, and only for three files.
ui/src/lib/readState.test.ts:51,72,73,74enforces the rule by asserting that specific source string literals are
absent from
SettingsPage.tsxandAutomationPage.tsx. That is ahand-maintained list of filenames — training, not a device. It does not know
DestinationDialog.tsxexists.Device → rung 2, Warning
An ESLint
no-restricted-syntaxrule matching a.catch()whose body is asingle
setX([])orsetX(null), run as a required check.Control would mean the read helpers in
ui/src/lib/api.tsreturningReadState<T>, so an empty array has no spelling on a failed read.strict: trueis on and there are only six
anys repo-wide, so the type system is available —but it touches every caller.
What stops the Warning today: there is no ESLint config in the repository
at all.