← Back to Blog

Field Signals · #4

The system that broke is the system that proposes the fix

Two halves of a glyph joined by a recursive loop — on the left a small machine cracked open mid-fault, on the right the same machine offering up a folded paper marked PR; the loop arrow runs from the crack through the paper and back into the machine’s frame

Autopilot crashed last night. The error log line was three sentences long. Within twelve minutes, autopilot had emailed the crash to itself, classified the email, looked up the right repository, and opened a draft Pull Request proposing a fix. The PR is sitting in my queue this morning, labeled AI/proposed fix, awaiting one click of approval.

This is not a story about AI fixing AI. It is a story about four small wires, one merge gate, and what becomes possible when the operator stops being the one who notices.

The receipt

The sequence that ran last night, in order:

  1. A code path inside autopilot raised an exception. Standard Python — nothing special.
  2. The autopilot logger called logger.error(...) with the traceback.
  3. A BugsnagHandler attached to the root logger caught the call and sent the error to a Bugsnag project.
  4. Bugsnag emailed notifications@bugsnag.com → the autopilot mailbox: subject [autopilot] InvariantError in some_module@deploy_helpers.
  5. Autopilot’s email-poller, which scans Gmail for actionable subjects every few minutes, pulled the email.
  6. The bugsnag_error classifier matched the sender (@bugsnag.com) and the subject pattern.
  7. The handler extracted the project name from the bracketed prefix (autopilot), the error class (InvariantError), and the stable Bugsnag error_id from the URL embedded in the body.
  8. It checked a small JSON tracking file at /opt/truesight_autopilot/state/bugsnag_triaged_errors.json. The error_id wasn’t there. First triage.
  9. It looked up the repo for autopilot in BUGSNAG_PROJECT_REPOStruesight_autopilot.
  10. It dispatched the fix-agent against that repo with an issue description that included the error class plus the first 2,000 characters of the email body (typically the stack trace).
  11. The fix-agent opened a draft Pull Request, labeled AI/proposed fix.
  12. The Gmail API attached the matching AI/proposed fix label to the source email.
  13. The error_id was written into the dedup file. Subsequent re-fires of the same error will be silently skipped.

The PR is in my inbox this morning. The Gmail label tells me where to look. The GitHub label tells me what’s awaiting review. Both filters return the same artifact.

Four wires

The architecture is unceremonial. Four small components, each on its own, would be a thirty-line patch. Composed, they close a loop.

Wire one — outbound. A BugsnagHandler attached to autopilot’s root logger at logging.ERROR. Any exception or logger.error(...) call anywhere in the codebase auto-reports to a Bugsnag project. Disabled silently when no API key is configured. Eight lines of code in one initializer.

Wire two — inbound classifier. A regex against the sender domain (@bugsnag.com) and a regex against the subject (matching [bugsnag], new error, error in, reopened, spike in errors). Sender check first, to avoid false positives on humans forwarding bugsnag-shaped subjects. Twelve lines.

Wire three — project-to-repo mapping. A JSON dict in the environment, e.g. BUGSNAG_PROJECT_REPOS={"autopilot":"truesight_autopilot"}. Unmapped projects log a warning and skip — the operator opts each project in explicitly. The conservative default keeps autopilot from filing PRs against repos the operator hasn’t yet vouched for.

Wire four — dedup on the Bugsnag error_id. A JSON tracking file. Bugsnag re-emails about the same error every time it re-occurs; without dedup the loop would spam the PR list every few minutes. With it, the second through hundredth re-fire are silently skipped. The dedup entry is written only after the fix-agent successfully returns a PR — so a transient triage failure doesn’t poison-pill subsequent retries.

That is the entire mechanism. The PR labels and Gmail labels are a fifth and sixth wire that make the operator’s review surface findable; they’re separate one-line additions in two adjacent modules.

What this isn’t

It isn’t autonomous repair. Gary Teh — long time contributor — still has to merge. The PR is opened in draft mode, with a label that screams propose, don’t ship, and the standard GitHub PR notification flow ensures he sees it. The merge gate is the operator’s; the proposal is autopilot’s.

It isn’t novel infrastructure. Bugsnag has existed since 2013. Gmail labels have existed since whenever. Python logging handlers are a standard library. PyGithub is well-trodden. Nothing in the four wires is novel; what’s new is the specific composition.

It isn’t AI fixing AI. The fix-agent uses a language model to propose the diff — that’s the only AI in the loop, and it’s the same fix-agent autopilot uses to propose fixes for any other repo’s bugs. The novelty is that the repo it now proposes against can be its own. The recursion is structural, not magical.

It isn’t a substitute for testing or for code review. It catches errors that escaped both. The fix it proposes might be wrong. The merge gate is what makes that safe — the operator is the test for the proposed fix, not the customer.

The Singapore lesson, recapped

A few weeks ago, on this blog, Gary wrote that the leverage in TrueSight’s operations isn’t in buying the biggest tool. It’s in the org design that lets the smallest tools do most of the work. The example then was the LLM fleet: cheap models in junior seats, frontier models reserved for architect-tier work, agentic_ai_context as the shared substrate. (See The shared memory is the moat for the long version.)

The autopilot self-healing loop is the same lesson, in the SRE layer. Most teams treat production incidents as a manual-toil problem — they hire on-call engineers, build dashboards, layer alerting tools, page someone at 3 a.m. The TrueSight version treats incidents as a substrate problem. Wire the report path. Wire the classify path. Wire the lookup path. Wire the dedup path. Now the system can propose its own fixes; the human becomes the merge gate, not the triage queue.

This is the second time on this blog we’ve written essentially the same essay with different specifics. It will not be the last time. The pattern is the point.

What becomes possible

The visible win is small: I get a draft PR in my inbox instead of a 3 a.m. page. Worth doing, not worth a blog post by itself.

The structural win is bigger. Once the loop is closed, every minute the operator used to spend on triage becomes a minute available for judgment. The shift is from what’s broken? to is this the right fix, and should we ship it? The first question is high-frequency, exhausting, and well-suited to a substrate. The second is low-frequency, generative, and the one only humans can answer.

This is the same arc The Do Nothing Society described back in April, made concrete one layer down. Let machines run the chain. Let humans hold the soul. The chain now includes the system that runs the chain.

The next loops to close, when we get to them, are the upstream ones. The DAO’s notification bell already surfaces partner-stock attention and partner-check-in follow-ups. The next stage proposes the outreach drafts (in flight). The stage after that proposes the shipping decisions. The stage after that proposes the sourcing quotas. Each loop is the same four wires in a different domain — report path, classify path, lookup path, dedup path. Each one moves the operator’s role one rung up the cognitive ladder.

Last night autopilot opened a Pull Request to fix itself. This morning the operator clicked merge. There was nothing dramatic about it.

The drama, when these systems work, is the absence of drama.

That is what the substrate buys.

Join the discussion

If you want to see the operating playbook this post is drawn from, it’s public: AUTOPILOT_CODE_MODIFICATIONS.md §§8–11 cover the multi-account AWS monitoring, the AI/proposed fix label convention, the email-classifier table, and the closed self-improvement loop.

Share your thoughts in Telegram, Beer Hall, and on the DAO web app.