Skip to content
codingncaffeine edited this page Sep 8, 2026 · 1 revision

Traps

Each of these cost real time. They are collected here because every one of them shares a shape: something reports success while doing nothing.

Hardware and access

A udev rule numbered above 73 grants nothing, silently. TAG+="uaccess" is consumed by 73-seat-late.rules; a rule evaluated after it applies the tag to nobody. The tag being present proves nothing — check getfacl for the ACL. See Device Access on Linux.

Two writers to one hidraw node do not error. The writes interleave and the panel flickers between two pictures. Nothing fails, nothing is logged. Decide single-instance ownership before opening the device.

A bound socket whose owner stopped accepting still accepts connect and send. "Message sent" is not evidence the other process did anything. Wait for an acknowledgement.

Blanking the panel on exit looks like broken hardware. Hand it back to a firmware animation instead.

A fast swipe arrives as two touches. One report is dropped, ~10 ms apart. Naive per-press gesture handling does the wrong thing.

Audio

pw-record --target=<sink>.monitor captures pure zeros and does not error. A PipeWire monitor is a port on the sink node, not a node; the name never resolves and it falls back silently. Use parec.

A monitor on a suspended sink emits zeros, not an error. So "no bars" has at least four indistinguishable causes. Build a probe that names which one.

Following one sink instead of the default sink gives a visualizer that is silently, convincingly flat whenever the output is switched.

Rendering

Undisposed SkiaSharp objects leak with zero GC pressure. Native memory the collector cannot see. ~192 objects/second in one per-frame path eventually OOM-killed the editor. Detach() does not dispose the builder.

SKBitmap.SetPixel per pixel misses the frame budget. 30720 managed→native calls per frame measured 27.7 fps against a 30 fps target. Compose into a byte[], push once.

Drawing a bitmap onto its own canvas is undefined, and the obvious fix — snapshotting with SKImage.FromBitmap every frame — allocates a native image in the hottest path. Ping-pong two buffers instead.

Full-screen effect constants are wrong at 48 rows. Fire's classic 1–2 per row decay leaves a full-scale seed near white after 48 rows: every pixel lit, no flame tip, no structure. Derive falloff from the height.

A fixed chart scale renders real movement as a flat line at this height — four degrees on a 20–95 range is 1.4 px. Auto-range, with a floor on the span.

Software structure

An unimplemented enum value that falls through to a default silently renders the wrong thing while reporting the name that was asked for. Keep an explicit "implemented" list and reject unknown names, rather than letting the enum imply capability.

A change handler that repopulates its own controls is an infinite loop — populating a panel raises the same events a user edit does. Guard it, and note the bug usually has more than one path (a text-changed and a selection-changed); fixing one leaves the other live.

Never block the UI thread at startup. A window that renders nothing and will not close is a blocked UI thread, not a rendering bug. No discovery, subprocesses or device I/O in constructors, field initialisers or timer ticks.

A file referenced by the build but never committed ships an application with that feature dead in every fresh clone, while the build stays green. Two icon trees in this project were referenced by the csproj and the installer and had never been git added. Clone fresh and diff before releasing.

Shell and tooling

set -o pipefail plus grep -q reports success as failure. grep -q exits on first match; the writer takes SIGPIPE and returns 141; pipefail surfaces it. Intermittent, because it races the writer. Capture output to a file first, then match.

Piping a program's output through a filter hides its exit code. $? after cmd | tail is tail's status. Capture, then filter.

.NET buffers stdout when redirected, so a backgrounded process that is killed rather than exited loses its report entirely and reads as "it printed nothing". Run in the foreground under timeout so it exits normally and flushes.

Environment.ExitCode is dead in a top-level-statements program whose file ends with return 0; — that compiles to Task<int> Main, and the final return overwrites it. A self-test that prints FAILED and exits 0 is not a self-test.

pgrep -x silently matches nothing when a process name exceeds 15 characters. And pkill -f <pattern> will match the shell running it.

Packaging

A copy that selects files by name ships silently incomplete. The moment the payload gains a file class nobody listed, it is dropped — and the build, the package step and the install all still report success. Copy wholesale, then verify the product by launching it.

A .NET publish is not byte-reproducible, so a package hash must come from the artifact actually published, not from a local rebuild.

Clone this wiki locally