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.
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.
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?
Green exit codes are a story the job tells about itself. The side-effect is the only witness that doesn't lie.