A first-week engineer ships an upload feature before lunch. Twelve lines, one <input type="file">, an onChange that sets a file into state, a fetch to /api/upload with a FormData body. The demo passes — picks a file, uploads it, console-logs success. Merged, deployed, forgotten.

Week one of real users. The product manager files four bugs in 48 hours. “People can't drag files onto the upload area.” “No preview — users submit blind.” “The 500 MB upload shows a spinner for ninety seconds and then users think it froze.” “Someone uploaded a 4 GB file to a profile-photo field and the server spent two minutes reading garbage before rejecting.” Each bug looks independent; together they're the SAME bug — the upload isn't really an upload widget yet. It's an HTML element with a few bolt-ons.

Counter · hand-receive slotprobe the lamps
Passing0
Failing0
Probed0 / 8
Eight-symptom probetap to light

Try each probe button on the left. The click probe triggers the real OS dialog — the one thing the element does. The drag probe exposes the first ugly truth: even with preventDefault on the WRAPPER <div>, the <input> itself never receives the file. files stays empty. The desktop drop lamp lights red. Size, preview, progress, cancel, retry, multi-file — each a separate station the element simply doesn't have. A single input slot where a full counter needs to be.

Eight lamps. Probe them all. Watch which ones light green and which light red. When you've tried them, come back and count what passes.