Day 2 of 16 · Monday · Learning

Reading your own system's stateConcept

Your system narrates everything it does into a daily event log. Today you learn to read that log — and to tell the difference between a card that's politely *waiting on you* and one that actually *broke*.

Catch-up progress
2/16
Why this matters to you

On 5/27 and 5/28 the language-lesson RemoteTrigger silently failed and you only found out because an email didn't arrive. The fix wasn't a smarter trigger — it was learning to look at the side-effect log instead of trusting that 'the job ran.' Every JARBUS action already writes itself down; the skill is knowing where, and how to read 'blocked' vs 'error' so you chase the right problems.

JARBUS keeps a running diary. Every time the engine does something meaningful — classifies a dropped file, fires a build, hands you a card to review — `reporter.py` appends one line to `PDB/data/jarbus-events/YYYY-MM-DD.jsonl`. The `.jsonl` extension means 'JSON Lines': one self-contained JSON object per line, so you can read the file top-to-bottom as a timeline and `tail` it live. This is the single source of truth for *what the engine actually did today*, as opposed to what you assume it did.

A review card has a lifecycle, and the folder it lives in IS its status. It's born when Claude drops an HTML into `FOR TOM/TOM TO REVIEW/` (the 'Your move' column). It lives there while it waits on you. When you mark it up and drop it back into `FOR TOM/DROP ZONE/`, the outbox handler processes it and moves it to `FOR TOM/_archive/YYYY-MM-DD/`. So 'where is the file' answers 'what state is this work in' — no database needed. A card still sitting in TOM TO REVIEW after a week isn't broken; it's just waiting on you (and the hygiene rule sweeps it to `_archive/.../_stale/`).

'Blocked' and 'error' are not the same word, and conflating them wastes your time. **Blocked** = the system is working correctly and is *deliberately* waiting — for your decision, for a PRD, for an input placeholder like `[INPUTS: business name]` to get filled. Nothing is wrong; the ball is in your court. **Error** = something the system expected to succeed did not — a script threw an exception, an API returned a non-2xx, a file that should exist is missing. Blocked is resolved by *you acting*; error is resolved by *something getting fixed*. When you scan the log, the first question is always 'is this thing stuck on me, or is it actually broken?'

Worked example

Walk one day of engine activity, then watch a single card move through its lifecycle by where the file lives:

# 1. Read today's event timeline (pretty-printed, newest last)
cat "PDB/data/jarbus-events/$(date +%F).jsonl" | python3 -c 'import sys,json;\nfor l in sys.stdin:\n  e=json.loads(l); print(e.get("ts","?")[11:19], e.get("event","?"), e.get("slug",""))'

# 2. What is currently waiting on YOU (the 'Your move' column)?
ls -1 "FOR TOM/TOM TO REVIEW/"

# 3. What got processed and filed away today?
ls -1 "FOR TOM/_archive/$(date +%F)/" 2>/dev/null

# 4. Watch the log live while you drop a file into DROP ZONE
tail -f "PDB/data/jarbus-events/$(date +%F).jsonl"
▶ Do it now
  1. Run block 1 above against today's event log. Read the timeline out loud — you should be able to narrate your morning's automation from it (plan-day fired, language lesson rendered, etc.).
  2. Run `ls -1 "FOR TOM/TOM TO REVIEW/"` and for each file ask the blocked-vs-error question: is this waiting on my decision (blocked), or does its name/age suggest something failed (error)?
  3. Pick ONE card, open the matching event line in the log, then check whether its sibling exists in `_archive/`. You've now traced one piece of work from 'engine created it' → 'where it lives now' — the whole lifecycle in three files.

Gotchas

Go deeper: Why the RemoteTrigger silent-failure pattern matters (Automation hygiene Rule 1)
One-card takeaway

Trust the log, not the trigger: every action writes itself down, and 'where the file lives' tells you whether the ball is in your court (blocked) or something broke (error).