Five briefings are on the device untagged, holding 23 leads with no go/no-go. The one you returned this week (9-7) became two packages by the next morning. This lesson traces the loop so the number stops being abstract.
JobHunt/leads/briefing-state.json has 28 leads presented since 9-7; 5 carry a decision, all inked on 9-7 and applied by 13:28 that day. The other 23 (9-8, 9-9, 9-10, 9-12, 9-13) are decision: null. Meanwhile the postings age: Synthesia was delisted while packaged, and Change.org (marked HIGH PRIORITY TARGET on 9-6) has sat packaged since 9-7. The jobhunt-briefing-return alert opened 9-11 and is at count 4.
The nightly loop is a conveyor with one manual station. 05:15: sweep writes leads/findings-<date>.md. The content leg picks 3-5 and writes briefings/<date>.md; the render leg makes the PDF and sends it to the Job Applications folder as 'M-D JobHunt Briefing - FOR REVIEW'. Every presented lead is written to briefing-state.json with decision: null. That null is the manual station.
When you tag the PDF done, rm_pull.py (every 5 minutes) pulls it, composites your ink, and hands it to ink_apply.py. Each inked box becomes decision: go or no with a decided date; GOs go to the pursuit queue, which pursuit.py drains two per night into full packages (research, resume, cover, prep, fit) sent to Job Applications/<Org>/. NOs with a written reason feed leads/refinements.md; NOs with no reason teach the sweep nothing.
Two rates, then. Production: 4-5 leads a night, every night, set by launchd. Decision: however many briefings you tag in a sitting. This week that was one sitting. Leads do not expire in the state file - the nightly re-verifies and carries them as backfill rather than re-presenting - but the postings behind them do expire. The alert is not saying the machine broke; it is measuring the distance between the two rates.
Count the undecided leads by the date they were presented.
python3 - <<'EOF'
import json
from collections import Counter
d = json.load(open('/Users/tom/Claude/JobHunt/leads/briefing-state.json'))['presented']
open_ = Counter(v['date'] for v in d.values() if v.get('decision') is None)
for day, n in sorted(open_.items()):
print(day, n, 'undecided')
print('total undecided:', sum(open_.values()))
EOF
The alert counts the gap between a conveyor that never stops and a station that runs when you sit down.