Day 30 of 31 · Monday · Learning

Automation hygiene — the five rules that keep unattended jobs honestReview

The five load-bearing rules from CLAUDE.md that separate an automation that works from one that only looks like it works. You've spent three mornings this week proving rule #1 the hard way.

Catch-up progress
30/31
Why this matters to you

Right now your Things Today list is ~40 tasks, almost all of them 🚨 automation-failure alerts going back to 6/17 — learning email, plan-day, language pre-render, Plaud ingestion, relay, JobHunt sweep, media-garden vocab. The 06-26 folder move (Personal Daily Briefing/ → PDB/) snapped hard-coded paths, the jobs kept exiting 0, and nobody noticed until the surfaces went blank. Every rule below is a rule you watched break this week.

An unattended job has two outcomes that look identical from the outside: it did the work, or it started, threw, and exited cleanly. A cron line, a LaunchAgent's last_fired_at, a green exit code — all of these prove the runner woke up. None of them prove the work happened. This gap is the single most expensive thing in your whole automation layer, because a job that fails silently is worse than no job at all: you stop checking, trust builds on nothing, and a week later the language lessons have been dark since the 17th.

Rule 1 — verify the side-effect, not the trigger. After the job claims success, query the thing it was supposed to change: does the Resend API show the email? Is there a new commit? Does PDB/output/languages/snippets/<today>.html actually exist? Build that check into the job itself. Rule 2 — every long job has a watchdog you have personally watched kill something. Rule 3 — failures surface where you read: a 🚨-tagged Things task, not just a log line. (Your 🚨 backlog proves this rule at least works — you can see the failures. The other four didn't.) Rule 4 — every cascade is upstream-aware: if job B reads job A's file, B checks for the file and notifies on absence instead of silently exiting 0. Rule 5 — the LLM runtime is the wrong layer for critical orchestration; reserve claude -p for content that needs judgment, and let a deterministic script handle the verify-and-send leg.

The 06-26 cascade is a textbook rule-4 failure stacked on a rule-1 failure. The path move broke the renderers (rule 1: nobody verified the snippet file landed). Then plan-day tried to embed snippets that weren't there and the language email tried to send a body that didn't exist (rule 4: the downstream jobs didn't check for their input, they just failed). One broken link, seven dark surfaces.

Worked example

The difference between a trigger check and a side-effect check, in your own language pipeline:

# WRONG — trusts the trigger (this is what bit you)
launchctl list | grep pdb-language-lesson    # shows it's loaded. proves nothing.

# RIGHT — verify the side-effect
ls -la /Users/tom/Claude/PDB/output/languages/snippets/$(date +%F).html
# ^ did today's snippet actually get written? if this file is missing,
#   the lesson did NOT render, no matter what the exit code said.

tail -5 /Users/tom/Claude/PDB/logs/language-lesson.log
# ^ and did the email actually POST to Resend, or just attempt to?
▶ Do it now
  1. Open ~/Claude/CLAUDE.md, find the 'Automation hygiene' section, and read the five numbered rules. Name out loud which one the 06-26 empty-surface cascade violated first (answer: rule 1 — the path move was never side-effect-verified), and which one turned one break into seven (rule 4 — no upstream-aware fallback).
  2. Run the three commands above for today's date. The snippet should now exist — you (well, plan-day) just rendered it this morning. Confirm the file is there and non-empty.
  3. Now the real win: bulk-clear the dead 🚨 backlog in Things. Every alert dated before today is noise once the spine is fixed. Knock them out so tomorrow's Today list shows real work, not a week of tombstones — that decluttering IS Big Three #1's payoff.

Gotchas

Go deeper: CLAUDE.md — Automation hygiene section
One-card takeaway

Green exit codes are a story the job tells about itself. The side-effect is the only witness that doesn't lie.