Mockup · ingest

What the researcher sees when files don't make it

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.

Palette
Artefact — real pixels, nothing that isn't in the product Commentary — reasoning, not shipped

Primary — macOS diagnostic popover

Anchored off the sidebar row's status glyph, as today.

Bristlenose — sidebar row → diagnostics
Analysis complete
38 of 58 files · 14 min 22 s
Transcribed 38 sessions12 m 04 s
Extracted 291 quotes1 m 47 s
Not in this report · 20 files
p07 failed download.mp4file is empty
interview half sent.mp4transfer incomplete
notes-not-video.mp4not a recording
forgot-to-talk.mp4no sound
skype-for-business.wmvWindows Media
avchd-camcorder.mtsAVCHD
feature-phone.3gp3GPP
dvd-era-archive.mpgMPEG program stream
adobe-connect-webinar.flvFlash Video
tape-capture.dvDV
…and 10 more
Commentary

The header states the cost before the detail

“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.

One list, not two — because the consequence is one thing

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.

Every row is .warning — none is .skipped

MessageKind.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.

Truncation is real and is why the footer button exists

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.

Basenames only

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.

Secondary — CLI

Same run, same taxonomy. The pipeline ships on both channels, so the vocabulary has to survive the trip.

bristlenose run ~/studies/worst-ux/
  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.
Commentary

The closing line repeats the cost

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.

Nothing new was invented for this

_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.

The alternative, and why not

Splitting by cause, and letting the policy decline be the quiet one.

Commentary · rejected
✗ Split by cause
p07 failed download.mp4
Skipped · 16 files
skype-for-business.wmv
avchd-camcorder.mts
✓ Shipped — one list
p07 failed download.mp4file is empty
skype-for-business.wmvWindows Media
avchd-camcorder.mtsAVCHD

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.