ONLINEREV · 2026-07-21§ BLOG · 2026-07-20-TEACHING-MY-OWN-TOOLS-TO-FIX-THEMSELVESPUBLISHED · 2026-07-20
All Posts
§ Journal2026-07-20

Teaching My Own Tools to Fix Themselves

By Corey SlickPublished

This week I closed the loop between finding a problem and fixing it — an automated pipeline that turns a flagged issue into a reviewed pull request, plus deep dives into signal-processing parity and self-healing firmware.

Most weeks in this lab notebook I write about one specific investigation — a DSP bug, a sensor calibration quirk, a firmware recovery mechanism. This week I want to zoom out one level, because the thing I actually spent the most engineering effort on wasn't a single measurement problem. It was building the machine that finds and fixes those problems for me.

I run a portfolio of measurement and instrumentation products — mobile apps that do real signal processing (FFT analysis, radiometric imaging, photometric compliance), a couple of web services, and an embedded device with its own firmware update system. Across all of them, I maintain a single backlog of flagged issues: crash reports, cross-platform inconsistencies, competitive intel, security bulletins. The interesting shift this week is that a meaningful chunk of that backlog now gets closed by an automated pipeline instead of by me sitting down and writing code.

The "Run" button: closing the loop from finding to fix

I built a small internal dashboard a while back that aggregates flagged issues across the whole portfolio — automated code scans, TestFlight crash reports, API-change alerts, that kind of thing. This week I finished the piece that was still manual: a "Run" button that takes a flagged item and actually produces a fix.

Here's the pipeline once you press it: a fresh, isolated clone of the relevant repo gets checked out (never the working copy I'm actively developing in). A contained instance of Claude — restricted to file-editing tools only, explicitly denied shell and network access — gets the issue description and goes to work. When it's done, the change gets compiled against a pinned build command for that repo (not something the AI gets to choose), so a fix that doesn't actually build never reaches a human. Before anything gets pushed, the staged diff runs through a secret scanner, because an automated agent operating on hint text sourced from external reports should be treated as if that text could be adversarial. Only then does it open a pull request — and a second, independent AI model (a different vendor entirely) reviews that PR before I ever look at it.

The part I like most about this isn't the code generation — that's the commodity layer now. It's the guardrails: isolation, pinned verification, secret scanning, cross-model review. Building an automated fix pipeline is easy. Building one you can trust not to quietly do something dumb or dangerous is the actual engineering problem, and it looks a lot more like designing a test harness than writing a feature.

When two platforms disagree, believe neither

A good chunk of this week's hands-on work was cross-platform parity — the kind of bug class that's genuinely hard to catch by inspection because each platform looks correct in isolation. In one measurement app that does live radiometric/thermal capture, the Android build was computing a temperature statistic as a min/max midpoint instead of the SDK's true average — subtly wrong, never obviously broken. In the same app, emissivity input handling diverged between platforms until I added matching clamp-and-reset logic on both sides.

The more interesting one was in an FFT-based measurement pipeline that renders differently on CPU and GPU paths. The two paths agreed on the math but disagreed on the display — zoom level and frequency-axis mapping drifted apart because one path resampled against a canonical bin axis and the other against physical frequency. The fix required tracing the rendering pipeline back to first principles (what does "the same zoom level" even mean across two different resampling strategies?) rather than patching symptoms. That's the kind of bug where AI-assisted implementation genuinely helps — I can describe the invariant I want ("CPU and GPU views must agree pixel-for-pixel at any zoom") and iterate fast on the fix — but the diagnosis is still 100% "sit down and think about the signal chain like an engineer."

Firmware that heals itself

On the embedded side, I shipped an over-the-air auto-apply update engine for a small networking device — the kind of feature where a bug doesn't just annoy a user, it can brick hardware that's not sitting on your bench. The design goal: updates apply automatically, but if anything goes wrong mid-apply, the device has to recover to a known-good state without human intervention.

This is exactly the kind of surface where I lean hard on adversarial AI review rather than my own read-through. Two separate review passes caught real issues: an interrupted-apply marker that needed to be a persistent file (not just an in-memory flag) so a power-loss mid-update couldn't silently bless a half-written state, a rollback routine that only restored snapshotted files but didn't remove newly-created ones, and a timestamp scheme that assumed stat -c and date -r flags that don't exist on the device's minimal BusyBox shell. None of these are things you find by reading the happy path. They're things you find by having a second reviewer — ideally one from a different model family with different failure modes — actively try to break the design.

The analyst team that never sleeps

The other half of this week's story is what the automated monitoring layer caught without me asking it to look for anything specific. An API-change scanner flagged that a government data API I depend on is switching a date field to a different format in a production release landing in two days — plenty of lead time to verify the parser tolerates it before it breaks. A security-bulletin scan caught that my VPN client library shipped a fix for a high-severity denial-of-service bug, which got queued straight onto the test fleet. A competitive-intelligence scan noticed that a regulatory enforcement deadline I'd been tracking as "upcoming" had quietly flipped to "now live, city issuing removal notices" — the kind of tense-change in messaging copy that's easy to miss if you're not re-checking weekly.

And a beta-feedback scanner flagged a single, thin crash report — one tester, no stack trace — and correctly refused to let it slide, tagging it launch-blocking until I pull the symbolicated log. That's a useful discipline: the volume was low enough that a human triager might reasonably deprioritize it, but the automated report applied the same bar regardless of how quiet the week was.

None of these individually are dramatic. What's notable is the aggregate: a standing intelligence function running in the background across a dozen-plus products, surfacing exactly the two or three things worth a human's attention out of dozens of monitored signals, every single week, without me having to remember to go check.

What this adds up to

The common thread across all of this — the fix pipeline, the parity bugs, the self-healing firmware, the monitoring layer — is that the work that actually requires me is shrinking to problem-framing, invariant-setting, and judgment calls about risk. Implementation, first-pass review, and continuous monitoring are increasingly things I design rather than things I do. That's not a small distinction. It's the difference between running one product and running a portfolio that spans mobile signal processing, embedded firmware, and web services, solo, without any of them going quiet for lack of attention.