A 58-file folder dropped on a project. Measured, not imagined — these counts come from
experiments/folder-of-horrors/acceptance.py run against the real stages:
38 analysed, 4 unusable, 16 in formats we don't read.
The question this answers: damaged files and declined formats have different causes but the same consequence — a recording the researcher expected is not in the report.
Anchored off the sidebar row's status glyph, as today.
“Analysis complete · 38 of 58 files”. The run succeeded — 38 sessions are in the report —
so the title is not a failure. But 38 of 58 is in the subtitle, not buried, because a
researcher who reads only the title must still learn that twenty files are missing.
A zero-byte upload and a .wmv have nothing in common technically: one is a broken file,
the other is a deliberate policy of ours. Split into “Errors” and “Skipped” they read as two unrelated
footnotes. Under one heading — Not in this report — they read as what they are: the list of
participants who won't appear. The cause lives in the trailing column, where it belongs.
.warning — none is .skippedMessageKind.swift already carries the argument. .warning is
exclamationmark.triangle.fill, and the comment beside it reads “filled · caution earns
weight”. .skipped is minus.circle.fill in cyan — “intentionally
untouched”. A recording the researcher deliberately handed us is precisely not intentionally
untouched. Using .skipped for the declined formats would be technically defensible from
our side of the boundary and wrong from theirs.
STAGE_FAILED_MAX = 10 caps the per-stage failed[] list, so the popover shows
ten and one overflow row. That's correct for a diagnostic — but ten of twenty is useless if the
missing one is P14. Show All 20 Files… is not decoration; it's the only complete list.
StageFailure.source_file is documented as basename-only because a diagnostic is
copy-pasteable, and a full path leaks the researcher's directory structure into a support thread.
The mockup honours that: no row shows a path.
Same run, same taxonomy. The pipeline ships on both channels, so the vocabulary has to survive the trip.
42 sessions in worst-ux/ ✓ Ingested 42 sessions (38 video, 4 audio) 0.4s ⚠ 16 files not analysed — format not read skype-for-business.wmv Windows Media avchd-camcorder.mts AVCHD feature-phone.3gp 3GPP … and 13 more — see bristlenose.log ✓ Transcribed 38 sessions 12m 04s ⚠ 4 files unusable p07 failed download.mp4 file is empty interview half sent.mp4 transfer incomplete notes-not-video.mp4 not a recording forgot-to-talk.mp4 no sound ✓ Extracted 291 quotes 1m 47s ✓ Report written 0.9s Report: worst-ux/bristlenose-output/bristlenose-worst-ux-report.html ⚠ 20 of 58 files are not in this report.
A long run scrolls. The two ⚠ lines will have left the screen by the time the report path
appears, and the researcher's eye goes to the last line. Restating it there costs one line and is the
difference between noticing and not.
_print_warn_step() already exists in pipeline.py, documented as
“partially-succeeded pipeline step (WARNING)”, and _print_stage already right-aligns the
trailing column at 58 characters. The per-file lines are indented detail under a stage line, which is
the shape the CLI already uses.
Splitting by cause, and letting the policy decline be the quiet one.
The left-hand version is the honest engineering model: nothing went wrong with
the .wmv, we simply don't read it. But it renders sixteen missing participants in dim cyan
under a heading that means “nothing to see”. That is the demotion we spent the day removing from the
ingest path — reintroduced at the last surface before the researcher's eye.
The open question this doesn't settle: if the accepted-format list widens, the sixteen mostly disappear and only the four damaged files need this surface at all. Worth deciding the format policy before building the grouping.