SCHED: Scheduled Tasks - The clockwork back on the mini

The actual documents the agents read and work from, shown exactly as they are on disk — not a summary. See the progress view instead · All projects

Plan PLAN.proposed.txt

## OVERSEER CONTRACT — Nick, 2026-09-08 (the top line of this plan)

OVERSEER CONTRACT — Nick Deck, 2026-09-08 11:05 EST, verbatim, the top line of every lane plan:
"you are overseer only - you dont build you deploy and lead and guide and QA - you keep everything pointed toward the north star and drive this home - you use cheap models for building - you dont stop for anything except true roadblocks that create damage or significant waste - set a 5 min loop now and drive this home"

What it means for whoever leads a lane:
- You are the overseer. You do not write the product code yourself. You deploy, lead, guide, review and QA.
- Cheap models build. Mid tier reviews. Top tier judges. Personal, family, health and financial content never goes to a cheap outside vendor; that is the one exception, and it is a routing rule, not a reason to stop.
- Everything you do this minute points at the lane's North Star. If it does not, drop it and take the highest-value unblocked step that does.
- You do not stop. Not for paperwork, not for a checkpoint, not for a question that has a sensible default. The only stops are true roadblocks that would create damage or significant waste, and those you name in one plain sentence with the three things you tried.
- Nick's four approval classes stand: money leaving, rotating a credential, irreversible destruction, a message sent as him to a human outside the boundary he set (internal standing, external one tap).
- Set a five-minute loop the moment you start: North Star, fan-out, cheap, blocked. Answer all four every time it fires, correct any failure, keep building until the finish line is proven.

Owner: Fable, programme overseer, drafted 2026-09-08 for Nick's approval. Lands as the A5 lane's PLAN.md only after he approves.
Purpose: the superseding plan for LANE 4 — SCHEDULED TASKS. It replaces nothing until approved. This file holds only the work still to be done; the measured state it was written against, and what became of each item the earlier plan carried, live in NOTES.txt beside it.

AUDIT REVISION — 2026-09-09, Boris (senior engineer), status only. Every one of the thirty steps' own DONE-PROOF was re-run once and the percents in "## STEPS" are what the machine returned; the audited state is listed once in AUDIT-LIST-2026-09-09.txt beside this file and mirrored in "## NEXT". NO STEP, STAGE OR CAPABILITY WAS DELETED, RENAMED OR RE-SCOPED — all thirty step blocks stand exactly as Nick's 2026-09-08 18:50 rulings left them, and this revision adds no build step. Counts: 8 proofs passed, 22 did not, 0 machines unreached. The lane's blocking fact, measured on both machines rather than read from a file: the job runner agent com.skippy.jobs is DISABLED at the launchd level on the Mac Studio AND on the Mac mini, so cross-cutting requirement (e) — "it fired on its own clock" — cannot be satisfied by any step until that is reversed.

**Owner:** the agent already running this lane (programme §1b) · **Overseer:** Fable, programme overseer; it never builds · **Design authority:** none — the only thing anyone looks at is the wording of three recurring messages, graded under §2d.
**Rule: a step starts the moment its named inputs exist, whatever its number. A step closes on ONE independent check by a different model. Nothing waits on Nick to test.**

# Scheduled tasks — the clockwork, rebuilt lean on the always-on Mac mini

## FOR NICK

**Scheduled tasks — the clockwork behind your day.**
What it is for you: everything that has to happen on a clock — your morning message, Chantelle's morning message and her replies actually completing things, the kids' calendar and their check-in questions, the household list clearing itself, the Hub doing work that has come due, and the outside data we pull in: your ring, your bank feeds, Rizza's weekly report, the team's hours, the standup recording.

The order it gets built in:
1. Chantelle's morning message, and her replies actually completing a task.
2. Your morning — one task in three timed stages: the ring pull at 06:30, the message at 07:36, the repair pass at 12:45.
3. The clock that moves anything overdue onto today.
4. The kids' two: their calendar, and their check-in questions.
5. The Hub doing work that has come due, and business material never being stored without your yes on that exact batch.
6. The data feeds: your ring, your bank feeds, Rizza's weekly report, the team's hours, the standup recording.
7. Jasmin's daily slot check.
8. The machinery nobody sees: the watchdog that notices a task has stopped, the backup check, the watch on what the work is costing, the timer that keeps approved building work moving, a weekly check for anything broken or orphaned, and a monthly look at what the outside world has made out of date.

Three rules run through every one of them. Each task writes its own line into one shared run record every time it runs. The watchdog alarms on three different things: a line that never appeared, data that has gone stale while the job kept reporting success, and an approval you granted that never reached the agent waiting on it. And every task marked "no model" costs zero — proved by a day of runs with a token count of zero, not by us saying so. No task is called done until we deliberately skip one of its runs and prove the alarm fires.

Approving something is not on a clock and never will be. When you tap yes, the tap itself tells the agent waiting. The only clock near approvals is the fifteen-minute sweep inside the watchdog that looks for a tap that went missing — a fault check, not the way approvals arrive.

Most of these tasks already have code written for them. They are switched off, not missing. So each one is repaired and extended in place rather than written a second time, and nothing on this list ends up with two copies.

Your morning message goes to your own Slack channel only. The Updates tab you had us take out of the family app is not used as a destination for it.

Chantelle's message is set for 08:00. Nobody has actually put that hour to her, so we build to 08:00 and change it in a minute if she wants a different time.

What needs you: nothing to start. Two answers are owed by other people, and neither holds up the build: Mae on whether her new receipts process catches missing receipts, and access to the shared drive the payroll feed needs, which returned no files the last time it was tested.

## THE NORTH STAR AND THE FENCES

**NORTH STAR — Nick, 2026-09-07:** "we just need to start from scratch" and "regroup and consolidate". The clockwork keeps his apps accurate, finishes work he already authorized, and brings the right decision to the right person once — without repeating old demands, without a second place to watch, and without a task quietly stopping and nobody knowing.

**FINISH LINE — ONE done-line, not two.** Every task on the rebuild list is live on the Mac mini — switched on against its own passing proof, writing a heartbeat row, carrying an entry in the existing watcher's register, and having fired at least once unattended on its own clock — EXCEPT tasks explicitly held with a named reason, of which there may be no more than the two already measured: the receipts chase, which waits on Mae's answer, and the payroll feed, which waits on shared-drive access. A third hold reopens the close rather than passing it. The one watcher checks every feed's landing place for staleness as well as every task's heartbeat row, and sweeps every fifteen minutes for an approval Nick granted that never reached its waiting agent; it has been proved on two different cadences by a deliberately skipped run being noticed, named in plain English, and READ BACK on the surface a person opens, and by a blocked test approval being named within fifteen minutes. Every none-tier task has recorded a full day of runs at zero tokens. Both morning messages arrive once, to the right person, with Nick's carrying no work items. Every feed keeps the date its data is about separate from the date it was fetched and lands in exactly one place. A fresh reader who built none of it agrees, row by row.

**STEP 0 — ARM THE LOOP, BEFORE ANYTHING ELSE.** Set a five-minute loop inside the executing session — not a new scheduled job, and never a timer installed on either Mac. Each pass: (1) re-aim at the North Star and the current write fence; (2) keep every independent step moving, with no numeric cap on how many run at once; (3) keep deterministic work in SCRIPT, bounded generation on the cheap router, comprehension at MID and decisions at TOP, and keep personal, health and family content off every cheap outside vendor; (4) re-measure a supposed blocker before writing the word, and continue everything independent of it. No step waits on Nick. This block is the doctrine's loop restated for this lane rather than its verbatim text, and the old numeric ceiling on how many agents may run at once is deliberately absent — Nick removed it on 2026-09-07 ("no numeric cap; coordinate load") — so nobody restores a number later, and nobody reads its absence as an oversight.

**CURRENT RELEASE FENCE:** this plan authorizes building, proving and switching on one task at a time against its own passing proof. It never authorizes money leaving, rotating a credential, irreversible destruction, or a message sent as Nick to another person. PROVING NEVER USES A REAL PERSON'S LIVE CHANNEL. Every fixture case runs on the harness's injected transport, which cannot reach a real channel, a real person or a real machine, so no proof needs a test send at all. Exactly one step needs a real channel to be proved — STEP 9, Chantelle's reply path — and there the test recipient is CHANTELLE ON WHATSAPP under Nick's standing test-send grant; every proving message begins with the word TEST, and its run-record row is marked a test send so it is never counted as a delivery. No test or probe signal ever reaches Nick's own live channel or the Hub's decision cards (his standing rule, 2026-09-07): his morning message's first real send IS its first send, made when the task is switched on, and the destination read-back is taken on that send. Security work stays click-gated: anything security-shaped seen along the way is one line in projects/ops/sp-sec/PLAN.md and then back to the step.

**THIS IS THE ONLY PLANNING DOCUMENT FOR THIS LANE.** On approval it supersedes projects/ops/life-os/audits/A5/PLAN.md in place; the build package under projects/ops/life-os/audits/A5/BUILD-PACKAGE/ stays the contract data it already is, and the task list at projects/ops/life-os/REGROUP-2026-09-08/lanes/SCHEDULED-REBUILD-LIST.txt is the builder's plain-English contract for what the twenty tasks are. No second scheduler, registry, ledger or board is created by this plan.

## Already true

Facts, not story. DECIDED and BUILT are separated on purpose: a ruling is not a running task, and reading one as the other is this lane's whole failure mode. Every BUILT line carries the command that measured it on 2026-09-09.

DECIDED (Nick's own words, with dates — none of these is a built thing)
- Scheduled work runs on the always-on Mac mini, which is a full work machine — Nick, 2026-09-07.
- Every scheduled task was switched off by his own hand — Nick, 2026-09-08 09:30 — and what is off is the SCHEDULING, not the code.
- The Hub and the family app are the databases; Monday and the other work tools are left out, while the standalone data feeds still run — Nick, 2026-09-08 10:30: "hub and family app become databases and leave monday and other tools out of it but still need to run oura etc and other standalone data feeds".
- Business finance numbers come from Rizza's weekly report, as a standing weekly feed needing no per-batch tap — Nick, 2026-09-08: "for the time being were still going to pull finance numbers from rizzas weekly report in that sheet".
- His morning message carries no work items and lands in his own Slack channel — Nick, 2026-09-08; the Updates tab was removed for good — Nick, 2026-09-05, "no updates tab ever".
- Chantelle's hormone readings are asked by Gracie inside her 08:00 message (task 2) and filed by task 3 — Nick, 2026-09-08: "chantelles hormones are collected by gracie each day as part of her morning messaeg".
- The weekly personal money review is a paragraph inside Monday's morning message (task 1) and the monthly line comes off the ERA feed (task 11); the engine watchdog on the mini goes back on; agent-liveness and autopush stay off as separate tasks — Nick, 2026-09-08: "1 good 2 yes".
- A plan holds only work still to be done — Nick, 2026-09-08 11:30.
- The cloud copy on the main line is the record; no Mac is ever a copy of record, and a "which is newer" question is never put to a person — RULE 20, 2026-09-09.

BUILT and re-measured on 2026-09-09 (the proof that showed it, and its exit code)
- The acceptance harness EXISTS and its five floor cases pass — heartbeat, lifecycle, delivery, source-time, eligibility, each printing `<name>: PASS` — evidence: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case all` exits 0.
- The harness refuses a case name that was never built, which is the behaviour §3b requires of it — evidence: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case does-not-exist` exits 1 and prints `ERROR: case 'does-not-exist' is unknown`.
- ONLY those five cases exist. The twenty task cases named in §3b are not implemented — evidence: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs` with no arguments prints its own usage line, and every task case exits 1 as unknown.
- The task list and the coverage check ARE on the main line — evidence: `git ls-tree origin/main --name-only projects/ops/life-os/REGROUP-2026-09-08/lanes/` exits 0 and lists both SCHEDULED-REBUILD-LIST.txt and SCHEDULED-COVERAGE-2026-09-08.txt.
- The rebuild list holds exactly twenty tasks, two of which are the named holds — the receipts chase pending Mae, and payroll pending shared-drive access — evidence: `command grep -c -E '^[0-9]+\.' projects/ops/life-os/REGROUP-2026-09-08/lanes/SCHEDULED-REBUILD-LIST.txt`.
- Every named existing implementation this plan extends is still present, and the jobs folder has grown from 176 to 181 files — evidence: `ls projects/ops/skippy-jobs/jobs/ | wc -l` prints 181, and `ls -la` finds beat.mjs, runner.mjs, roster-liveness-watchdog.mjs, feed-watchdog.mjs and business-feed-watchdog.mjs.
- THE RUNNER IS SWITCHED OFF ON BOTH MACS — evidence: `launchctl print-disabled user/$(id -u)` reads `"com.skippy.jobs" => disabled` on the Studio, the same command over `ssh nicks-mac-mini.local` reads it disabled on the mini, and `com.skippy.jobs` is in neither machine's `launchctl list`.
- The watcher this plan depends on is not healthy — evidence: `com.skippy.roster-liveness` reads disabled on the Studio, and on the mini it is loaded with its last run exiting 1.
- The watcher's register was generated BEFORE this work and holds none of these tasks — evidence: projects/ops/spine-projections/roster-liveness.json carries `"generated_at": "2026-09-07T09:17:13"` and its own header forbids hand-editing.
- The engine watchdog on the mini is loaded and enabled and fails every run, still pointed at the OLD workspace folder — evidence: `ssh nicks-mac-mini.local 'launchctl list com.skippy.engine-watch'` prints `"LastExitStatus" = 256` with its program and log paths under /Users/nickdeck/Documents/Claude/ rather than this workspace.
- The mini's phone service is still crashing — evidence: `ssh nicks-mac-mini.local 'launchctl list'` shows `com.skippy.mobile` with exit status 78.
- The file-sync push is ENABLED on both Macs, a change from the 2026-09-08 reading that recorded it disabled on both — evidence: `launchctl print-disabled` reads `"com.skippy.autopush" => enabled` on each machine; the pull side is less clean, with `com.skippy.auto-pull` last exiting 1 on the Studio.
- STEP 29's proof cannot pass as written — evidence: it exits 1 with `KeyError: 'receipts_missing_covered'`, because that top-level field has never existed in service-contracts.json, whose real keys are owner, purpose, as_of, timezone, runtime_policy, services and retirement_proofs.
- STEP 30's proof mode is not implemented — evidence: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --read-only-live outcomes` exits 1 and prints `--read-only-live outcomes is not implemented yet`.
- 2026-09-10 — his rulings from this lane's NOTES-FROM-NICK.txt, moved here and that file deleted (git holds every byte): Chantelle's hormone reading is collected inside Gracie's 08:00 message and filed to her record (his words, 2026-09-08); the weekly personal money review is a paragraph inside Monday's morning message with the monthly line off the ERA feed, and the engine watchdog on the Mac mini goes back on ("1 good 2 yes") — that watchdog was then measured exiting 1 every run for about 19 days with its log paths pointing at the old workspace.

## 0 · Gate Zero receipts

- Failure Mode Registry loaded: 2026-09-08; all 189 entries in .claude/skills/plan/references/failure-registry.md carry a scoped measure or a named N/A reason in §4. The shared registry is not edited by this plan.
- Canonical specs loaded: the 8 September regroup record for this lane; Nick's 2026-09-08 rulings at 09:30 (every scheduled task off by his hand, the rebuild list is the urgent item), 10:30 and 10:35 (Monday out, Hub and family app are the databases, the standalone feeds stay, Jasmin daily), 11:30 (a plan holds only work to do), 12:35 (approvals go through the dispatch-confirmation process) and 12:55 (the weekly skill grader runs inside Larry's weekly review) EST; the cold read of this plan dated 2026-09-08 and every finding in it; the rebuild list at projects/ops/life-os/REGROUP-2026-09-08/lanes/SCHEDULED-REBUILD-LIST.txt; the progress-screen standard; the earlier A5 plan and its whole build package including its S03 filtered-source-collection contract; the A5 disposition rows for the Era, Rizza, payroll and standup feeds; the family app's own finances code for how the Era snapshot is read; CLAUDE.md and RULEBOOK.md; the plan doctrine and its failure registry; the runner, jobs-gate, role-owner, dispatch-contract and outbound-send-gate contracts.
- Ownership check: MEASURED ON 2026-09-08, not assumed — projects/ops/skippy-jobs/jobs/ holds 176 job files today, including named implementations of most of these twenty tasks — daily-task-email-lite.mjs, todo-bump-overdue.mjs, calendar-push.mjs, kids-checkin-prompts-lite.mjs, oura-backfill-heal.mjs, bizapp-payroll-refresh.mjs, bizapp-standup-capture.mjs, mac-backup-watch.mjs, spend-guard.mjs, quota-kill-watch.mjs, build-control-status.mjs, grade-skill-evals.mjs, roster-liveness-watchdog.mjs, feed-watchdog.mjs and business-feed-watchdog.mjs — plus roster entries for the rest. SWITCHED OFF IS NOT THE SAME AS ABSENT: what Nick switched off is the scheduling; the code stayed. EVERY TASK STEP THEREFORE EXTENDS A NAMED EXISTING FILE OR RECORDS, AS A MEASUREMENT, THAT NO IMPLEMENTATION EXISTS. The watcher's own register is projects/ops/spine-projections/roster-liveness.json (36 entries today), which is GENERATED by projects/business/single-brain/generate_roster_liveness.py from the two task rosters and is never hand-edited; a task registered anywhere else is watched by nothing. The existing job runner and the machine-role registry keep ownership of scheduling and host assignment. The shared run record keeps its existing locked writer at projects/ops/skippy-jobs/beat.mjs and is never hand-edited or duplicated. The channel, approval, Hub, family, health and Jasmin owners keep their own product authority; this lane binds their gates and never finishes their features. This plan supersedes the A5 plan in place and creates no new governing document.
- Expected inputs confirmed to exist: all opened on 2026-09-08 — projects/ops/skippy-jobs/jobs/ (176 files); projects/ops/spine-projections/roster-liveness.json; projects/business/single-brain/generate_roster_liveness.py; projects/ops/skippy-jobs/jobs/roster-liveness-watchdog.mjs; projects/ops/skippy-jobs/jobs/feed-watchdog.mjs; projects/ops/skippy-jobs/jobs/business-feed-watchdog.mjs; projects/personal/family-app/functions/api/_todo-store.js; projects/personal/health/spine/health-spine.json; projects/ops/skippy-jobs/runner.mjs; projects/ops/skippy-jobs/lib/jobs-gate.mjs; projects/ops/skippy-jobs/lib/role-owner.mjs; projects/ops/skippy-jobs/lib/dispatch-contract.mjs; projects/ops/skippy-jobs/lib/outbound-send-gates.mjs; projects/ops/skippy-jobs/beat.mjs; projects/ops/skippy-jobs/lib/board-report.mjs; projects/personal/skippy-app/lib/outbound-gate.mjs; the whole build package including projects/ops/life-os/audits/A5/BUILD-PACKAGE/check-package.py and projects/ops/life-os/audits/A5/BUILD-PACKAGE/service-contracts.json; projects/ops/life-os/REGROUP-2026-09-08/lanes/SCHEDULED-REBUILD-LIST.txt; projects/ops/agents/check_plan.py. A missing input at execution time fails admission rather than being worked around.
- Standing grants checked before any step asks Nick for anything: sending as Skippy on Slack, Gmail and WhatsApp; agents driving his machine and apps as the user and signing themselves in; WhatsApp test sends to him or Chantelle; the Mac mini as a full work machine and the host of scheduled work; and, new on 2026-09-08, Rizza's weekly finance report as a standing weekly feed needing no per-batch tap. No step in this plan asks him for a decision.
- PLAN AUTHOR: Fable, programme overseer, 2026-09-08.
- COLD READER: read in full on 2026-09-08 by a reader who saw none of the conversation that produced this plan; the read is recorded beside this file as COLD-READ-2026-09-08.txt and every blocking finding in it is applied above and below. Nick's approval is separate from that read.
- EVIDENCE FOLDER, named once and used by every step: projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/. Every "ARTIFACT SAVED" line in this plan resolves under that one path and nowhere else. The review ledger that decides whether a task is DONE is one file inside it, projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/REVIEW-LEDGER.txt, with one row per step.
- PROMPT-SPEC scan (P1–P7): P1 "heartbeat" means one row per task in the one shared run record, written by the task itself through the existing locked writer, and "stale" means the data that landed is older than that feed's own named allowed age; P2 every rule below carries one action verb; P3 that every scheduled task is off is Nick's own statement on 2026-09-08 and is re-measured on the machine by step 1 rather than inherited, and "off" is measured to mean the SCHEDULING is down, not that the code is absent — 176 job files were counted in the jobs folder the same day; P4 scope names what is out — no Monday or other work-tool feeds, no product features, no new scheduler, no security pass; P5 every output has a named landing place, and every feed names exactly one; P6 Nick's "era is the bank feeds for personal finances" is carried verbatim rather than interpreted; P7 the 10:30 ruling modifies the household-list clocks and the feed set and leaves the rest of the list standing, which is stated rather than assumed.
- Security surface noted: the services touch channel credentials, outbound sends and personal financial data. No security audit, hardening pass or credential work happens here. Anything security-shaped costs one line in projects/ops/sp-sec/PLAN.md and the step continues; a security pass needs Nick's approval click, at the end, as its own phase.

## 1 · Goal and definition of done

**What we're building, one paragraph:** twenty small tasks on the always-on Mac mini. Each one exists only because it does something a message-driven agent cannot — move data on a clock, remind on a date, watch something that cannot speak for itself, or prove something is alive. MOST OF THEM ALREADY HAVE CODE ON THE MAIN LINE and are switched off rather than missing, so the work is to repair and extend a named existing file, register it with the existing watcher, prove it, and switch it back on — one at a time, each against its own passing proof. A step that cannot find an existing implementation says so as a measurement and writes the one new file; no task on this list ends with two implementations.

- **HOW IT'S USED:** Nick reads one morning message; Chantelle reads one morning message on WhatsApp and can reply to complete an item; the kids' calendar and the app views stay current on their own; the household to-do lists live in the family app alone; the Hub holds the business record and the feeds that land in it; nobody opens a new screen to make any of it happen. HOW WE KNOW: the lane brief, the 7 September rulings that set two morning messages and no more, and Nick's 2026-09-08 ruling that the Hub and the family app are the databases.
- **WHAT IT LOOKS LIKE:** existing channels and existing app views, with honest source age; one progress screen for this lane in the Hub, in the standard format. No new surface is designed here. HOW WE KNOW: the progress-screen standard, 2026-09-08.
- **WHERE IT LIVES:** the existing job runner and its libraries on the always-on Mac mini (host name nicks-mac-mini). A TASK IS SWITCHED ON BY THREE THINGS AND NOTHING ELSE, all measured on 2026-09-08: its file in projects/ops/skippy-jobs/jobs/, its row in the SCHEDULE array in projects/ops/skippy-jobs/runner.mjs, and the launchd agent com.skippy.jobs loaded and alive on that machine (`launchctl list | grep com.skippy.jobs`). A task whose work runs as a Claude task instead is switched on by its own roster entry in projects/business/single-brain/business_spine.json or projects/personal/health/spine/health-spine.json under task_roster. The existing shared run record holds every heartbeat; the existing channel, approval and projection owners keep their own code; this plan, the rebuild list and the build package under projects/ops/life-os/audits/A5/ hold the contracts. HOW WE KNOW: the build brief names the Mac mini and the existing runner as the host and the runtime, and Nick confirmed the Mac mini as the work machine on 2026-09-08.
- **WHAT IT MUST DO:** C1 give every one of the twenty tasks on the rebuild list a working build and its own passing proof before it is switched on; C2 make one authorized action produce exactly one effect across retry, crash and two machines; C3 keep source age honest, keep the date data is about separate from the date it was fetched, and prove morning readiness; C4 count a message delivered only on destination read-back; C5 make every task write a heartbeat row and every feed land in exactly one place; C6 respect cancellation, expiry, release gates, audience and the per-batch business-data approval; C7 alarm on a missing heartbeat and on stale data, proved by a deliberately skipped run being noticed on two different cadences; C8 make every none-tier task cost a measured zero tokens, proved from the existing spend record over a full day of runs rather than asserted, with any short-cadence task scripts-only; C9 keep approval DELIVERY an event and never a clock, with the fifteen-minute lost-tap sweep inside the watcher raising — never delivering — an approval Nick granted that did not reach its waiting agent.
- **NOT in scope:** feeds that read Monday or any other outside work-management tool, because the Hub and the family app are the databases now; building family-app, WhatsApp, Jasmin, School or voice features beyond what Chantelle's reply path needs, because their owners and release gates stand; a new scheduler, memory store, ledger or board, because working owners already exist; a security audit or credential work, because that is click-gated to the end; changing anyone's treatments, routines or personal times from archived text, because old text is not current consent; a redesign of any screen, because this is headless clockwork.
- **Trip-over protocol:** one dated evidence-backed handoff line to the receiving owner through Fable, recorded in projects/ops/life-os/audits/A5/PROGRESS.md. This lane never edits another lane's plan.

## 1a · Critical variables

| # | Variable | Value chosen | Alternatives rejected | Class | HOW WE KNOW | Cost if wrong | CONFIRMED |
|---|---|---|---|---|---|---|---|
| 1 | SURFACE — where the result lands and who opens it | Each person's existing channel: Nick's morning message, Chantelle's WhatsApp summary, the kids' calendar in the family app; plus one progress screen for this lane in the Hub in the standard format | A new dashboard, a new notification channel, or a status page nobody opens | V1 | Nick's regroup rulings on the progress-screen format and on his morning message | A second place to watch, and work items arriving where he does not want them | Nick, 2026-09-08, "this format should be the standard format for our progress screens we're implementing on the project management by agents side in the hub" |
| 2 | Host — which machine runs the clockwork | The always-on Mac mini | The Mac Studio, or the work split across both machines | V1 | The lane brief names the always-on Mac mini as the host for scheduled work | Jobs stop whenever the Studio sleeps or is in use | Nick, 2026-09-07, scheduled work moves to the always-on Mac mini |
| 3 | Extending the existing job, or writing a second one | Each task repairs and extends the job file or roster entry that already implements it, then goes back on against its own passing proof | Writing twenty new files and leaving the existing implementations on disk | V1 | Measured on 2026-09-08: projects/ops/skippy-jobs/jobs/ holds 176 job files with named implementations of most of these tasks, and the two task rosters hold entries for the rest — what was switched off is the scheduling, not the code | Two implementations of one task, split ownership, and an old file left on disk ready to be re-loaded by anything that reads the jobs folder | Nick, 2026-09-08: every scheduled task is off by his own hand, and STEP 1 re-measures the loaded-job count on the machine before any step depends on it |
| 4 | Nick's morning message | Carries what happened and what is coming; carries no work items | A morning message that lists what is waiting on him | V1 | His ruling relayed into this lane on 2026-09-08 | He opens a task list at 07:36 that he explicitly did not want | Nick, 2026-09-08, the morning message carries no work items |
| 5 | Which tier runs which service | Top oversees, mid executes, cheap only where quality is unaffected; personal, health, family and financial content never reaches a cheap outside vendor | Cheapest model everywhere, or top tier everywhere | V1 | His tiering rule for the programme, restated in this lane's brief | Private content leaves to a vendor with no standing, or the bill is spent on grunt work | Nick, 2026-09-07, top oversees, mid executes, cheap where quality is unaffected |
| 6 | Which outside feeds we keep | The standalone ones only — the ring, the Era bank feeds, Rizza's weekly finance report, the team's hours and the standup recording | Keep every feed the audit found, including the task boards, comment threads, vendor list, satisfaction scores and repeat-order tracker | V1 | Nick's 2026-09-08 ruling that the Hub and the family app become the databases and Monday and the other tools are left out, while the standalone data feeds still run | Either the Hub keeps syncing with a tool we are replacing, or a feed nothing else can produce silently stops | Nick, 2026-09-08, "hub and family app become databases and leave monday and other tools out of it but still need to run oura etc and other standalone data feeds" |
| 7 | Where the business finance numbers come from | Rizza's weekly report in her sheet, as a standing weekly feed needing no per-batch tap | Keep pulling the accounting system and the payment processor on a clock | V1 | His 2026-09-08 ruling, which is also the approval that makes this one feed standing | Either the numbers stop arriving, or a business dump is stored without his yes | Nick, 2026-09-08, "for the time being were still going to pull finance numbers from rizzas weekly report in that sheet" |
| 8 | The hour Chantelle's morning message goes out | 08:00 Cancun, built as the ASSUMED DEFAULT | Asking her or Nick first and holding the build until an answer comes back | V2 | NOT CONFIRMED. The locked message contract says so in its own words — "08:00 is the proposed implementation default, not a claimed existing preference" — and nothing in the day's record confirms an hour. It is built to the default and changed in one line if she wants another | A daily message arriving at an hour she did not choose, which costs one configuration change and nothing else | Open. The question that settles it is one line to Chantelle: "is 08:00 the right time for your morning list?" It is asked by her existing conversation, not by a step, and no step waits on the answer |
| 9 | Where Nick's morning message lands | His own Slack channel, #nicks-life, one destination, read back there | The family app's Updates feed, which the locked wording names | V1 | The family app's Updates tab was removed for good — Nick, 2026-09-05, "no updates tab ever" — so a message written there sits on a surface with no way in, which is the registry's "delivered somewhere the intended reader never looks" | A read-back that passes while he never sees the message | Nick, 2026-09-05, no Updates tab ever; the change to the locked wording is recorded in STEP 10 with its date |
| 10 | Where Nick's personal due items come from | The family app's own household to-do store, his list, read through GET /api/todo-list?list=nick | His personal Monday board, which the locked wording names | V1 | Nick, 2026-09-08 10:30: Monday is out and the family app is the database. The store, its list resolver and its someday array were opened on 2026-09-08 at projects/personal/family-app/functions/api/_todo-store.js | The one source the message's main content comes from is a tool this plan's own anti-scope forbids reading | Nick, 2026-09-08, "hub and family app become databases and leave monday and other tools out of it"; the change to the locked wording is recorded in STEP 10 with its date |

Considered and ruled not critical: the exact minute of a task that already has a slot on the rebuild list is configuration under its existing owner, not a question for Nick; which model reads a given piece of evidence is a tier decision inside the matrix; how many tasks run in one process is an implementation choice bounded by the one-effect proof. No step in this plan waits on Nick. One thing is genuinely open and is built past rather than waited on — the hour Chantelle's message goes out, row 8 above: it is built to 08:00 and changed in one configuration line if she wants another time.

## 1b · Subproject decomposition

These pieces can land, be signed off and be used separately. Their governing homes already exist; this plan owns the clockwork and hands the rest back to its owners.

| Subproject | End goal | Owner | Own PLAN | Status |
|---|---|---|---|---|
| Landing and the shared floor | The Mac mini reads the task list, and the heartbeat, one-effect, read-back, source-age and eligibility rules exist before any task is built on them | A5 release owner; Fable holds the main-line landing | projects/ops/life-os/audits/A5/PLAN.md | This plan, steps 1–7 |
| The people-facing tasks | Chantelle's message and replies, Nick's morning as one task in three stages, the overdue clock and Willow's and Noah's two, each live on its own proof | A5 release owner with the existing message and channel owners | projects/ops/life-os/audits/A5/PLAN.md | This plan, steps 8–14 |
| The business tasks and the data feeds | The Hub due-work runner, the permissioned collection, the four standalone feeds and Jasmin's daily check, each live on its own proof | A5 release owner with the Hub and finance owners | projects/ops/life-os/audits/A5/PLAN.md | This plan, steps 15–21 |
| The machinery | The watchdog, backups, the spend guard, build coordination and the two recurring reviews | Existing operations, upkeep and router owners via Fable | projects/ops/life-os/audits/A5/PLAN.md | This plan, steps 22–27 |
| Chantelle's reply dependencies | The family-app recurring-task records and the WhatsApp reply path her message needs | Family-app and channel owners, routed by Fable | `<the family-app and channel owners' own plan — NOT YET CREATED; that folder exists on main but holds no plan file, measured 2026-09-09>` | This plan, step 9, then handed back with a dated line |
| Board updates that survive | An update reporting success is actually kept | Hub build owner, routed by Fable | `<the Hub build owner's own plan — NOT YET CREATED; no such plan file exists on main, measured 2026-09-09>` | This plan, step 28, then handed back |

## 2 · Complete entry-point map

| Id | Entry point | State | Interaction | Expected behavior | Route |
|---|---|---|---|---|---|
| U1 | A service's due moment | due / claimed / crashed / retried / expired | One owner claims and runs it | Exactly one owner; an uncertain effect is reconciled before any retry; an expired one-off is skipped with its reason recorded | Contract to existing runner to effect receipt |
| U2 | An incoming source | new / unchanged / unavailable / conflicting | Read the source and move its cursor | True event time preserved; unreadable means unknown, never empty; the cursor advances once per accepted change | Provider to domain owner to projection |
| U3 | An app view someone opens | current / stale / unavailable | Nick, Chantelle or a child opens their own existing view | Right person, right revision; an unavailable input stays visibly dated instead of blank | Projection to that person's app |
| U4 | An outgoing message or action | accepted / suppressed / failed / confirmed | Deliver or perform an already-approved item | Queue acceptance never counts as delivery; only a destination read-back does | Approval or outbox to guarded adapter to destination |
| U5 | Morning due time | ready / partial / late / already sent | Build one briefing per person per day | One briefing to the right person; stale or missing inputs named in it; Nick's carries no work items; no catch-up flood after an outage | Domain summaries to existing destination |
| U6 | A product's due slot | released / gated / cancelled | Prepare only the permitted next stage | Jasmin, School and voice release gates stay effective; a wrong-person or cancelled item produces nothing | Product owner to existing review queue |
| U7 | A review or change check | unchanged / changed / materially regressed | Choose the bounded weekly or deep monthly review | No repeated model review without eligible new work; a seeded defect is still found; the monthly replaces that week's light pass and both say so in their rows | Evidence to weekly or monthly owner |
| U8 | A task's own switch-on | built / proved / live / held | Switch one task on once its own proof has passed | Nothing goes live without its own passing proof and its first heartbeat row; a task not yet on is visibly not on, never silently assumed | Proof receipt to the runner's live list |
| U9 | A heartbeat row, or its absence | written / late / never / stale-data-behind-a-healthy-row | The watcher compares each task and feed against its own named line | A missing row raises a named alarm within that task's own window; stale data raises a different alarm even when the row is healthy; a task that correctly did nothing still writes a row | Task to shared run record to watcher to exception record |

## 2d · DESIGN FIDELITY GATE

DESIGN FIDELITY GATE — this lane ships one thing people look at: the words of the three recurring messages (Chantelle's morning message, Nick's morning message, the kids' check-in prompts). LOCKED TARGET: the exact wording, including the failure wording, in projects/ops/life-os/audits/A5/BUILD-PACKAGE/MESSAGES.md AT THE REVISION WHOSE SHA-256 IS ce1e348cb6f50f9d705e96e5533a8280f89f2f6336ee60c3c8c4ee195d0af6ed, machine-written by `shasum -a 256` on 2026-09-08. The grader re-computes that checksum before grading and refuses to grade a file that does not match it, so "the locked wording" cannot drift into meaning whatever the file says on the day somebody reads it. TWO LINES OF THAT FILE ARE DELIBERATELY SUPERSEDED, each recorded with its date in the step that uses it: its Updates-feed destination for Nick's message (STEP 10, on Nick's 2026-09-05 removal of the Updates tab) and its personal-Monday-board source for Nick's due items (STEP 10, on Nick's 2026-09-08 10:30 ruling that Monday is out and the family app is the database). The grader scores against the file's wording with those two substitutions applied and no others. The gate is run by a grader who did not build the service: it compares the message that actually arrived, word for word, against that locked wording, at the phone width the recipient reads it on, and reports mismatched lines and unmeasured lines. It applies in full to STEP 8, STEP 10 and STEP 14. No message step closes above zero mismatched lines, and Nick's morning message closes only with zero work items in it. Everything else in this lane is headless: DESIGN FIDELITY GATE: N/A — nothing rendered — countersigned by MID · Anthropic · Claude Opus 5 · se-blind-checker, 2026-09-08, which is the same reader that grades the three message steps and is therefore in a position to say the other steps render nothing — for steps 1 through 7, step 9, steps 11 through 13 and steps 15 through 30, which publish no surface. This exemption does not waive the real-surface read-back proofs in U3, U4 and U8.

## 3 · Lanes and frozen contracts

| Lane | Scope | Owner | Definition of done | Model |
|---|---|---|---|---|
| Landing and the shared floor | Getting the task list and this plan onto the main line, the harness, the heartbeat contract, one-effect lifecycle, delivery read-back, source age, eligibility | A5 release owner; Fable holds the landing | C2, C4 and the heartbeat half of C5 proved before any task is built on them | MID · Anthropic · Claude Sonnet 5 · se-fixer lands the tree; CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs builds the shared floor's non-personal plumbing; SCRIPT · none · deterministic code measures; MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict |
| People-facing tasks | Chantelle's message and reply path, Nick's morning in three stages, the overdue clock, Willow's and Noah's calendar and prompts | Existing message, channel and family owners via Fable | C1 and C3 proved for those seven, with the message gate at zero mismatched lines | MID · Anthropic · Claude Sonnet 5 · se-fixer builds; MID · Anthropic · Claude Opus 5 · se-blind-checker reads independently and grades the message gates; TOP · Anthropic · Claude Fable 5.1 gives the verdict; never a cheap outside vendor |
| Business tasks and data feeds | The Hub due-work runner, the permissioned collection, the Era, Rizza, payroll and standup feeds, Jasmin's daily check | A5 release owner with the Hub and finance owners via Fable | C1, C5 and C6 proved for those seven, each feed landing in exactly one place | MID · Anthropic · Claude Opus 5 · se-fixer builds on financial content; MID · Anthropic · Claude Sonnet 5 · se-fixer elsewhere; MID · Anthropic · Claude Opus 5 · verifier reads independently; SCRIPT · none · deterministic code measures the dates; TOP · Anthropic · Claude Fable 5.1 gives the verdict; never a cheap outside vendor on financial content |
| The machinery | Liveness watching, backup, spend and quota guards, build coordination, the weekly and monthly reviews | Existing operations, upkeep and router owners via Fable | C7 proved, including the deliberately skipped run on two cadences | CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs builds the bounded non-personal parts; SCRIPT · none · deterministic code measures; MID · Anthropic · Claude Sonnet 5 · verifier reads; MID · Anthropic · Claude Opus 5 · verifier on the spend guard, with TOP · OpenAI Codex · GPT-6-Astra reviewing it; TOP · Anthropic · Claude Fable 5.1 gives the verdict |
| Folded-in items and the close | The board that drops successful updates, Mae's receipts answer, and the final check by a reader who built none of it | A5 release owner; Fable routes the handoffs | Every task on the list live on its own proof, or visibly and explicitly not yet built | MID · Anthropic · Claude Opus 5 · se-fixer executes; MID · Anthropic · Claude Sonnet 5 · verifier reads; TOP · Anthropic · Claude Fable 5.1 evaluates and MID · Anthropic · Claude Opus 5 · se-blind-checker gives the final blind check |

Frozen contracts. One source owner per fact. Queue acceptance, a heartbeat row, or a log line never counts as delivery — only a destination read-back does. A heartbeat row proves a task RAN; it never proves the data arrived, and the watcher checks both separately. No task is switched on before its own proof has passed, and a task that is not on is recorded as not on rather than assumed working. Every feed lands in exactly one place — the Hub or the family app — and keeps the date its data is about separate from the date it was fetched. Business material is stored only against Nick's approval of that exact batch, with Rizza's weekly finance report the single named standing exception. THE CHEAP-VENDOR FENCE IS STATED BY CONTENT, NEVER BY DOCUMENT CLASS. Personal, health, family, financial, business-record and unpublished client editorial content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. "It is a business document" is not a permission: a business document routinely carries financial detail, so a cheap model may see one only after a deterministic pre-check has run over that exact text and found no figure, rate, account detail, pay amount or person's name in it, and the check's output is saved as evidence. If the check does not run, or finds anything, the work stays on the trusted bench. Nothing in STEP 19 goes cheap at any point, because hours and pay are financial detail by definition. Task definitions are written lean from the start: a rule that binds everywhere is referenced once, never copied into each definition. A disagreement returns to Fable; it never creates a second queue, board or approval class. Plan changes land in this file before implementation, and the dated earlier claims stay.

## 3b · Execution map

A task is DONE only when its row in projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/REVIEW-LEDGER.txt is CLOSED by a reviewer that is not the builder. That file is the review ledger; there is no other. THE EVIDENCE FOLDER IS projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/ — every "Evidence: ARTIFACT SAVED" line below resolves under that one path, and STEP 30 grades from it.

The commands below are the proofs each step must produce; they are not claims that a test exists today. The isolated acceptance harness `projects/ops/skippy-jobs/_test-scheduled-contracts.mjs` is CREATED BY STEP 2, together with its two deliberate-failure controls, and no earlier step cites it. Its interface is frozen here: `--case <name>` runs fixtures only and prints `<name>: PASS` on exit 0; a deliberately broken production branch must make the matching case exit non-zero and name the assertion that failed, then pass again once reversed. `--read-only-live <case>` reads real surfaces only, writes receipts into the evidence folder named above, and may never send or change anything. `--case all` runs every case that EXISTS at the moment it is run.

🔴 STEP 2 BUILDS THE FLOOR CASES ONLY, AND EACH TASK STEP ADDS ITS OWN. At STEP 2 the only cases that exist are the five floor cases — heartbeat, lifecycle, delivery, source-time, eligibility — and the two deliberate-failure controls. The task cases (chantelle-morning, nick-morning, oura, overdue, kids-calendar, kids-prompts, hub-due-work, business-collection, era, rizza-weekly, payroll, standup, jasmin, watchdog, backup, spend-guard, build-coordination, larry-weekly, benito-monthly) DO NOT EXIST YET at STEP 2, and `--case all` there must not silently pass over them. A named case that does not exist is an error, never a pass. Each task step then ADDS its own case and must show it RED first — against the unrepaired service, or against a deliberate break in the repaired one — before it goes green, so no step ever closes against a check that was green before its work was done. A step whose case went green without a recorded red run is not closed. SCRIPT rows consume no model quota. A row whose EXECUTOR is a cheap vendor never touches personal, health, family or financial content.

CROSS-CUTTING, AND EVERY STEP FROM 8 ONWARD MUST SATISFY ALL FOUR BEFORE IT CLOSES.

(a) EXTENDS, NEVER DUPLICATES. The step opens the existing implementation its own text names, and repairs and extends that file. If it genuinely finds none, it records that as a measurement — the command it ran and what came back — and only then writes one new file. Two implementations of one task is a failed step, not a detail.

(b) HEARTBEAT: the task writes its own row into the one shared run record through the existing locked writer at projects/ops/skippy-jobs/beat.mjs, saying what the rebuild list says that task's row must say, on every run including a run that correctly did nothing; a run that could not read its source writes a row saying that, never a row that looks like an empty day. The row key must be the name the watcher already resolves — beat.mjs warns loudly when it is handed a name nothing watches, and that warning is a stop, not noise.

(c) WATCHED BY THE WATCHER THAT ALREADY RUNS. The register is projects/ops/spine-projections/roster-liveness.json, and it is GENERATED — projects/business/single-brain/generate_roster_liveness.py builds it from the task_roster arrays in projects/business/single-brain/business_spine.json and projects/personal/health/spine/health-spine.json on every business pipeline run, and its own header says do not hand-edit. So a task is registered by adding its entry to the right SOURCE roster with its taskId, cron and maxGapMinutes and regenerating; hand-editing the projection is a change that erases itself. The reader of that register is the existing fleet watchdog, projects/ops/skippy-jobs/jobs/roster-liveness-watchdog.mjs; the stale-data half extends the two existing feed watchdogs, projects/ops/skippy-jobs/jobs/feed-watchdog.mjs and projects/ops/skippy-jobs/jobs/business-feed-watchdog.mjs. NO SECOND REGISTER AND NO SECOND WATCHDOG IS CREATED BY THIS PLAN: a task registered in a new list would be watched by nothing, because the watchdog that has actually been running reads only this one. The step closes only after one of that task's own runs has been deliberately skipped and the alarm has been seen to fire, name the task in plain English, and clear itself when the task next runs.

(d) THE ALARM REACHES A PERSON, AND THAT IS READ BACK. An alarm that nobody opens is not proved. The existing watchdog already routes by severity: an overdue non-provisional fast-cadence task goes to Nick's own channel through `alertNick`, and everything else becomes a card on the Hub board through `postUpdate`, cleared by `resolveUpdate` when the task recovers. Each step's skipped-run proof must READ THE ALARM BACK on whichever of those two surfaces its own severity chose — the destination's own record, never the watchdog's log — exactly as contract C4 requires of any other delivery. A raised alarm with no read-back is an unproved alarm.

(e) IT FIRED ON ITS OWN CLOCK. A passing fixture proves the code; it does not prove the task is running. A step closes only after the task has fired ONCE UNATTENDED on the real schedule on the Mac mini — a heartbeat row written at a time no person triggered — with the row's timestamp saved as evidence. That means its row is present in the SCHEDULE array in projects/ops/skippy-jobs/runner.mjs and the launchd agent com.skippy.jobs is loaded and alive on that machine; STEP 3 proves the runner itself is up before the first task step opens.

A step that builds the task but leaves it unregistered, unproved against a skipped run, unread at the alarm's destination, or never fired unattended is not closed. STEP 22 does not introduce the watcher; it completes it — the stale-data half, the whole register read back against this plan, and the two-different-cadences proof.

| Stage | # | Task | Gate to enter | TIER | EXECUTOR | CHECKER | DONE-PROOF | Ends when |
|---|---|---|---|---|---|---|---|---|
| Landing | 1 | Land the task list and this plan on the main line, and re-measure that the old jobs are off | none — start now | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer lands the tree and re-measures | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `git ls-tree origin/main --name-only projects/ops/life-os/REGROUP-2026-09-08/lanes/` | the list is listed on the main line, the Mac mini's own checkout lists it too, and that machine's loaded-job count is read and recorded |
| Floor | 2 | Build the acceptance harness and its two failure controls | Step 1 landed | mid | CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — harness and fixtures, no protected content in them | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case heartbeat --case lifecycle --case delivery --case source-time --case eligibility` | the five floor cases exist and pass, a named case that does not exist is an error rather than a pass, and the sabotage control comes back red then green on reversal |
| Floor | 3 | The heartbeat contract and the watcher that reads it | Step 2 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — the register is extended inside the personal health spine and the business spine, so this is protected data and never goes cheap | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case heartbeat` | a task that ran writes one row through the locked writer, a task that did nothing still writes one, a task that could not read writes a different one, and a row that never appears raises a named alarm |
| Floor | 4 | One authorized action, exactly one effect | Step 3 proved | mid | CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — action plumbing, no protected content in it | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case lifecycle` | retry, crash and two-machine cases each produce one effect |
| Floor | 5 | Delivered means the destination read it back | Step 4 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — the read-back reads the destination's own record, so it stays inside | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case delivery` | accepted, suppressed, failed and confirmed stay four distinct states |
| Floor | 6 | Old data never looks new | Step 3 proved; runs beside 4 and 5 in separate files | mid | CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — freshness plumbing, no protected content in it | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case source-time` | an unchanged or unreadable source never restamps as fresh, and date-of-data stays separate from date-fetched |
| Floor | 7 | Cancelled, expired and wrong-person work does nothing | Steps 4 and 5 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — the identity rules read real people's records | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case eligibility` | every ineligible case produces zero effects with a recorded reason |
| People | 8 | Chantelle's morning message, live | Steps 3, 5, 6 and 7 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: household and personal content | MID · Anthropic · Claude Opus 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case chantelle-morning` | one message a day with a real provider receipt, zero mismatched lines against the locked wording, her row registered and a skipped run noticed |
| People | 9 | Chantelle's replies actually completing a task | Step 8 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: household content | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case chantelle-replies` | a test task moves end to end through the real conversation, the same reply repeated moves nothing twice, and the listener's marker is watched |
| People | 10 | Nick's morning message, live | Steps 3, 5, 6 and 7 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: personal content | MID · Anthropic · Claude Opus 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case nick-morning` | one message a day read back at both destinations, zero mismatched lines, seeded work items appearing nowhere in it, and a skipped run noticed |
| People | 11 | Nick's body data collection — the ring pull | Steps 3 and 6 proved | mid | MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: his body data | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case oura` | a reading carrying yesterday's date lands in the health record, an unavailable source keeps the old value and marks it stale, and a skipped run is noticed |
| People | 12 | Overdue becomes today, live | Steps 3 and 7 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — his own task records stay inside | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case overdue` | an overdue task carries today's date afterwards, a collapsed read refuses to write, and a skipped run is noticed |
| People | 13 | The kids' calendar push, live | Steps 3, 6 and 7 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: family content | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case kids-calendar` | a known event appears in the correct child's day, an ambiguous one is skipped, an unreadable calendar leaves yesterday's view visibly dated, and a skipped run is noticed |
| People | 14 | The kids' check-in prompts, live | Steps 3, 6 and 7 proved | mid | MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: family content | MID · Anthropic · Claude Sonnet 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case kids-prompts` | the prompt reaches the intended parent route, a closed topic stays closed across two runs, asking nothing and being unable to read are two different rows, and a skipped run is noticed |
| Business | 15 | The Hub due-work runner, live | Steps 3, 4, 5 and 7 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — business records stay inside | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case hub-due-work` | a real Hub row moves from due to done with the effect visible in the Hub, a cancelled one produces nothing, and a skipped run is noticed within ten minutes |
| Business | 16 | Business data collection, with Nick's permission each time | Steps 3, 6 and 7 proved | mid to look; cheap for prescribed extraction from an already-approved business document | MID · Anthropic · Claude Sonnet 5 · se-fixer builds the looking and the extraction — the documents are business records, so nothing leaves the account | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case business-collection` | an approval record joins the exact stored batch, and a missing, altered, expired or reused approval writes nothing |
| Feeds | 17 | The Era bank feed into the family app's finances | Steps 3, 5 and 6 proved | mid | MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: personal financial data | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; SCRIPT · none · deterministic code compares the two dates; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case era` | the app's finances screen reads back the "as of" date this run wrote, a failed fetch keeps the older snapshot with its own date, nothing lands anywhere else, and a skipped run is noticed |
| Feeds | 18 | Rizza's weekly finance report into the Hub | Steps 3 and 6 proved | mid | MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: protected financial detail | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; SCRIPT · none · deterministic code compares the two dates; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case rizza-weekly` | the Hub's finance view shows the new week under the week's own end date, a week that has not landed writes nothing, the same week appended twice changes nothing, and a skipped run is noticed |
| Feeds | 19 | Payroll hours and the payroll adjustments sheet | Steps 3, 6 and 16 proved | mid | MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: protected financial detail | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case payroll` | the Hub's hours and payroll week read back under the week's own end date, a re-run writes nothing, and the shared-drive access state is recorded as measured rather than assumed |
| Feeds | 20 | The team standup recording into the Hub | Steps 3, 4 and 6 proved | mid for the transcript; the speaker attribution stays on a trusted bench | MID · Anthropic · Claude Opus 5 · se-fixer — the speaker attribution stays on a trusted bench | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case standup` | the transcript is readable in the Hub under the meeting's own date, a second pass over the same recording adds nothing, and a long capture does not block the tick |
| Business | 21 | Jasmin's daily slot check, live | Steps 3 and 7 proved | mid for eligibility; cheap only for extraction the editorial process already prescribes | MID · Anthropic · Claude Sonnet 5 · se-fixer builds eligibility and the extraction — the slot check reads a client's own editorial record | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case jasmin` | a valid slot reaches the review queue exactly once, a cancelled one produces nothing, nothing publishes, and a skipped run is noticed |
| Machinery | 22 | Complete the watcher: stale data, the full register, two cadences | Every step from 8 to 21 is either registered or explicitly held with a named reason | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer — the stale-data half reads personal and business landing places, so this is protected data and never goes cheap | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case watchdog` | a deliberately skipped run is noticed on two different cadences, held-back data behind a healthy row is caught by the other half, and a healthy quiet source raises nothing |
| Machinery | 23 | The backup check, live | Step 3 proved | cheap | MID · Anthropic · Claude Sonnet 5 · se-fixer — the backup check reads store names and fingerprints that sit beside protected content | MID · Anthropic · Claude Opus 5 · verifier reads independently; SCRIPT · none · deterministic code compares the fingerprints; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case backup` | a restored sample's fingerprint matches the original, a deliberately corrupted backup fails the check, and no secret appears in the result |
| Machinery | 24 | The spend and quota guard, live | Step 3 proved | mid | MID · Anthropic · Claude Sonnet 5 · se-fixer builds the spend and quota guard | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · OpenAI Codex · GPT-6-Astra reviews the guard — a wrong verdict here spends real money | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case spend-guard` | a run killed by a quota limit becomes resumable exactly once, an ordinary error is not treated as a quota problem, and an unknown allowance stays unknown |
| Machinery | 25 | The build-coordination timer, live | Step 3 proved | mid | CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — timer plumbing, no protected content in it | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case build-coordination` | an approved next step progresses on the board, a closed step stays closed, and abandoned work is picked up exactly once |
| Machinery | 26 | Larry's weekly upkeep and continuity review, live | Steps 3 and 22 proved | mid to build; the review itself runs SCRIPT for gathering, MID for ambiguous evidence and TOP for the judgement | MID · Anthropic · Claude Sonnet 5 · se-fixer builds the scheduled task; the review it runs gathers with SCRIPT · none · deterministic code, reads ambiguous evidence at MID and judges at TOP | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case larry-weekly` | a deliberately planted problem is found, an already-settled item stays quiet, and the review item is readable on the Hub |
| Machinery | 27 | Benito's monthly outside-world review, live | Step 26 proved | mid to build; the review itself runs MID for reading evidence and TOP for the judgement | MID · Anthropic · Claude Sonnet 5 · se-fixer builds the scheduled task; the review it runs reads the evidence at MID and judges at TOP | MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case benito-monthly` | the monthly item is readable on the Hub, that week's light review deliberately stands down, and both rows say so |
| Folded in | 28 | Make the board keep an update that reports success | Step 1 landed | mid | MID · Anthropic · Claude Opus 5 · se-fixer makes the board keep a successful update | MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict | `node projects/ops/skippy-jobs/lib/board-report.mjs --read --lane ai-builds` | an update reporting success is read back from the board after it is posted, with a control update proving it was the board and not the session |
| Folded in | 29 | Ask Mae whether her receipts process covers missing receipts | Step 1 landed | mid | MID · Anthropic · Claude Sonnet 5 · se-recorder drafts the question for Skippy to send under his own name | MID · Anthropic · Claude Opus 5 · verifier reads the recorded answer back | `python3 -c "import json,sys;d=json.load(open('projects/ops/life-os/audits/A5/BUILD-PACKAGE/service-contracts.json'));a=d['receipts_missing_covered'];sys.exit(0 if a.get('answer_text') and a.get('answered_on') else 1)"` | her answer text and its date are both recorded, and the Sunday receipts task is built or dropped on it |
| Close | 30 | Every task live on its own proof, checked by a reader who built none of it | Steps 8 to 27 closed or explicitly held with a named reason | top | TOP · Anthropic · Claude Fable 5.1 evaluates — judgment, not building: it is the final grade across thirty live tasks | MID · Anthropic · Claude Opus 5 · se-blind-checker, final blind check, having built none of it | `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --read-only-live outcomes` | every task on the rebuild list is live with a heartbeat row, a watcher entry and one unattended firing, except tasks explicitly held with a named reason — no more than the two already measured — and the fresh checker agrees row for row |

### STEP 1 — Land the task list and this plan on the main line, and re-measure that the old jobs are off

**Enter this step when:** now. Nothing precedes it.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer lands the tree and re-measures · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** nothing inside the list or the build package changes. This step only moves the existing files from the life-os/programme branch onto the main line and refreshes the Mac mini's checkout. Never edit another lane's files while landing.
**needs Nick: no**

**Do exactly this:**
1. Confirm the list is absent from the main line: `git ls-tree origin/main --name-only projects/ops/life-os/REGROUP-2026-09-08/lanes/` returns nothing for SCHEDULED-REBUILD-LIST.txt today.
1b. TWO FILES LAND, NOT ONE. Beside the list, land `projects/ops/life-os/REGROUP-2026-09-08/lanes/SCHEDULED-COVERAGE-2026-09-08.txt` — the row-by-row check of the 55 old jobs no task on this list rebuilds, with what covers each one now and whether that thing is running. The builder does not act on it (it is Nick's answer to "are we sure these are all covered", not a build brief), but it travels with the list because the list points at it, and a pointer to a file that did not land is worse than no pointer. Checksum it on both machines exactly as point 4 does for the list.
2. LAND IT BY ONE NAMED METHOD: a pull request from life-os/programme to main, scoped to this lane's own paths, merged through GitHub. Never a force-push, never a local merge of main into the lane worktree (this repository's hooks refuse that and lanes have lost work at exactly this moment), and never a direct push to main.
3. On the Mac mini, reachable over SSH as host `nicks-mac-mini` — the same route the existing machine watchers use, `projects/ops/skippy-jobs/jobs/com-skippy-mobile-launchd-watch.mjs` and `server-symlink-watch.mjs`, so no new access is invented here — pull the main line.
4. PROVE THE CONTENT, NOT THE NAME: run `shasum -a 256` over SCHEDULED-REBUILD-LIST.txt on the Studio and on the mini and compare the two checksums, machine-written into the evidence folder by the same shell that produced them. A directory listing passes on a truncated or emptied file; a checksum does not.
5. Create this lane's one evidence folder if it is not already there, and open its review ledger, so every later step has one place to save proof into and one row to be closed on. Every "ARTIFACT SAVED" line in this plan resolves under that folder.
6. On that same machine, read and record how many scheduled jobs are actually loaded right now — `launchctl list | grep com.skippy` and the SCHEDULE row count the runner reports — and record it as a measurement with its timestamp. That every scheduled task is off is Nick's own statement until this step reads it on the machine.

**PROOF:** the command in point 1 now lists SCHEDULED-REBUILD-LIST.txt on the main line; the file's SHA-256 is identical on the Studio and on the Mac mini, both checksums machine-written; and the loaded-job count on the mini is recorded with its timestamp. Evidence: ARTIFACT SAVED — the two checksums, the pull request's merge commit identifier, and the count, all under projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/. FAILS IF the two checksums differ, or either is absent, or the recorded count is anything other than a number this step read on that machine.
**If it fails:** record the exact refusal text, tell Fable in one line, and continue with steps 28 and 29, which do not need the mini. If the SSH route to the mini does not answer, record what came back as a measurement and say plainly that the mini has to be reached another way; do not assume the landing reached it.
**Handoff:** none.

### STEP 2 — Build the acceptance harness and its two deliberate-failure controls

**Enter this step when:** step 1 has landed. The harness does not exist anywhere today; this step creates it.
**Builder:** CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — harness and fixtures, no protected content in them · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the new harness at `projects/ops/skippy-jobs/_test-scheduled-contracts.mjs` and its own fixture folder. Never production code in this step.
**needs Nick: no**

**Do exactly this:**
1. Create the harness with the interface frozen in section 3b: `--case <name>`, `--case all`, `--read-only-live <case>`.
2. Build THE FIVE FLOOR CASES ONLY — heartbeat, lifecycle, delivery, source-time, eligibility — because every task case tests a service a later step repairs, and a case written now would either fail with nothing to test or pass against a stub, which is a check that cannot fail. Each task step adds its own case and shows it red first.
3. Make a named case that does not exist an ERROR that exits non-zero, never a silent pass. `--case all` runs the cases that exist; it never reports coverage it does not have.
4. Give every case an injected clock, store and transport, so no case can reach a real channel, a real person or a real machine.
5. Build the two deliberate-failure controls: one that breaks a production branch and must turn its matching case red, and one that breaks an unrelated fixture and must not.

**PROOF:** the five floor cases each print `<name>: PASS` and exit 0; `--case does-not-exist` exits non-zero and says the case is unknown; the sabotage control exits non-zero and names the assertion it broke; reversing it returns to 0. Evidence: ARTIFACT SAVED — all four runs recorded in the evidence folder. FAILS IF a broken production branch leaves every case green, or a name that was never built comes back PASS — either would mean the harness proves nothing.
**If it fails:** the harness is the safety net for twenty-six later steps, so it is fixed rather than worked around; meanwhile steps 28 and 29 continue.
**Handoff:** none.

### STEP 3 — The heartbeat contract, and the watcher that reads it

**Enter this step when:** step 2 is proved. This is built BEFORE the first task, so no task ever has to wait for something to watch it.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — the register is extended inside the personal health spine and the business spine, so this is protected data and never goes cheap · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the run-record and watcher paths under projects/ops/skippy-jobs/, the two source rosters' task_roster arrays, and the harness fixtures. The existing locked writer at projects/ops/skippy-jobs/beat.mjs is used, never replaced, and HEARTBEAT.md is never hand-edited. The generated projection projects/ops/spine-projections/roster-liveness.json is never hand-edited either — its own header forbids it and a hand edit is erased by the next pipeline run.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** the register already exists at projects/ops/spine-projections/roster-liveness.json (36 entries), generated by projects/business/single-brain/generate_roster_liveness.py from the task_roster arrays in projects/business/single-brain/business_spine.json and projects/personal/health/spine/health-spine.json. Its reader already exists at projects/ops/skippy-jobs/jobs/roster-liveness-watchdog.mjs. NEITHER IS BUILT AGAIN HERE; both are extended.

**Do exactly this:**
1. Make every task write one row into the one shared run record through the existing locked writer, replacing its own row rather than appending a second. Never build a second record. Use the row key the watchdog already resolves — `heartbeatKey || taskId` — and treat beat.mjs's "the fleet watchdog is not watching this name" warning as a stop, because a row written under a name nothing reads is exactly how a task goes dark unnoticed.
2. Separate three outcomes that are routinely collapsed into one: the task ran and did something, the task ran and correctly did nothing, and the task ran and could not read its source. Each writes a different row, and a task that could not read never writes a row that reads like an empty day.
3. EXTEND THE REGISTER AT ITS SOURCE: add each of the twenty tasks to the correct roster's task_roster array with its taskId, its cron and its maxGapMinutes, then regenerate the projection with generate_roster_liveness.py and read the new entries back out of the generated file. Where a task is a feed, add its landing place and its allowed data age alongside. The twenty entries in the rebuild list are the contract for what those lines say. If the existing register genuinely cannot express a per-feed staleness line, record that as a measured finding and extend it — never start a second register.
4. EXTEND THE MISSING-HEARTBEAT HALF OF THE EXISTING WATCHDOG so it compares every registered entry against its own line and raises one named alarm, in plain English, for any row that should exist and does not, clearing itself when the row appears. Keep its existing severity routing: a real page to Nick's own channel through `alertNick` for an overdue non-provisional fast-cadence task, a Hub board card through `postUpdate` otherwise, cleared by `resolveUpdate`.
5. PROVE THE RUNNER ITSELF IS ALIVE, before the first task step opens: `launchctl list | grep com.skippy.jobs` on nicks-mac-mini returns a loaded agent with a live process, and one existing job fires on its own clock and writes a row nobody triggered. Record both with timestamps. Nothing in this plan may be called live on a machine whose runner is not running.
6. Prove the alarm can fire, can be read where a person opens it, and can also stay quiet: skip one fixture task's row and see the alarm, then read that alarm back from its own destination record rather than from the watchdog's log; leave a quiet-but-healthy task alone and see nothing.
7. RECORD EACH TASK'S DECLARED MODEL TIER IN THE REGISTER ALONGSIDE ITS CADENCE, and make a tier of "none" mean a measured zero, not a promise. Nick, 2026-09-08: every none-tier task costs zero tokens, and a short-cadence task is scripts only. The eleven none-tier tasks on the rebuild list — Chantelle's 8am message, the kids' calendar push, overdue becomes today, the Hub due-work runner, Era, Rizza's weekly report, payroll, the watcher, the backup check, the spend and quota guard, and the build-coordination timer — each close against a day of runs recording zero tokens, measured from the existing spend record rather than asserted in prose. Where a task is only partly none (Nick's morning, Chantelle's replies, business data collection, Jasmin's slot check, the standup recording, Larry, Benito), the none-tier PART carries the same zero and the model-using part is named and separately accounted. A none-tier task that spends anything is a bug in that task and reopens its own step.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case heartbeat` prints `heartbeat: PASS`; the regenerated roster-liveness.json contains the new entries, each carrying its cadence AND its declared tier, and the existing watchdog reads them; a skipped row raises a named alarm that is READ BACK at its destination, and a healthy quiet task raises none; the three outcome rows are distinguishable from each other; the launchd agent on the mini is recorded loaded and alive, with one unattended heartbeat row to show it. Evidence: ARTIFACT SAVED — the regenerated entries with their tiers, the alarm text and its destination read-back, the three row shapes, and the runner-alive measurement, all in the evidence folder. FAILS IF a task that could not read its source produces the same row as a task that had nothing to do, or a second register or second watchdog exists anywhere afterwards, or a task's declared tier is absent from the register, or the alarm is proved from a log rather than from the surface a person opens.
**If it fails:** no task step opens, because every one of them closes against this. Steps 28 and 29 continue meanwhile.
**Handoff:** none.

### STEP 4 — One authorized action produces exactly one effect

**Enter this step when:** step 3 is proved.
**Builder:** CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — action plumbing, no protected content in it · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the runner's claim and receipt path under projects/ops/skippy-jobs/ and the harness fixtures. Never the outbound adapters, which are step 5.
**needs Nick: no**

**Do exactly this:**
1. Give every effect a durable claim and a receipt, written before the effect is attempted and reconciled after.
2. Build the three hard cases as fixtures: a retry after a timeout, a crash between effect and receipt, and both machines believing they own the same job.
3. Prove an uncertain effect is reconciled before any retry, never retried blind.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case lifecycle` prints `lifecycle: PASS`; each of the three cases produces exactly one effect. Evidence: ARTIFACT SAVED. FAILS IF the two-machine case produces two effects, or zero.
**If it fails:** one line to Fable, and continue with step 6, which is independent of this one.
**Handoff:** none.

### STEP 5 — A message counts as delivered only when the destination reads it back

**Enter this step when:** step 4 is proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — the read-back reads the destination's own record, so it stays inside · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the delivery confirmation path under projects/ops/skippy-jobs/ and the harness fixtures. The existing outbound gates at projects/ops/skippy-jobs/lib/outbound-send-gates.mjs and projects/personal/skippy-app/lib/outbound-gate.mjs are read, never weakened.
**needs Nick: no**

**Do exactly this:**
1. Separate four states that are routinely collapsed: accepted by the queue, suppressed on purpose, failed, and confirmed by the destination.
2. Make a receipt require reading the message back from the destination, never a queue acknowledgement, a heartbeat row, or a log line. A heartbeat row proves the task ran; it is not evidence anything arrived.
3. Prove an uncertain delivery stays uncertain rather than being counted either way.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case delivery` prints `delivery: PASS`; a queue acceptance with no read-back is recorded as undelivered, and so is a healthy heartbeat row with no read-back. Evidence: ARTIFACT SAVED. FAILS IF a queue acceptance alone, or a heartbeat row alone, closes a delivery.
**Security note (section S):** this step touches channel credentials and an outbound path. No hardening, audit or credential work happens here; anything security-shaped is one line in projects/ops/sp-sec/PLAN.md and the step continues. A security pass needs Nick's approval click and happens at the end as its own phase.
**If it fails:** one line to Fable, and continue with steps 6 and 7.
**Handoff:** none.

### STEP 6 — Old data never looks new

**Enter this step when:** step 3 is proved. This runs beside steps 4 and 5 in separate files.
**Builder:** CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — freshness plumbing, no protected content in it · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the source cursor and freshness path under projects/ops/skippy-jobs/ and the harness fixtures.
**needs Nick: no**

**Do exactly this:**
1. Keep the source's own event time — the date the information is ABOUT — separate from the time it was read, on every feed without exception.
2. Advance a cursor only on an accepted change; on an unchanged read, leave both the cursor and the age alone, so nothing is re-stamped as fresh because we looked at it again.
3. Make an unreadable source produce unknown, with its last known age intact, never an empty result that reads as nothing there.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case source-time` prints `source-time: PASS`; a re-read of unchanged data does not restamp it, and the two dates are separately readable on every fixture feed. Evidence: ARTIFACT SAVED. FAILS IF an unavailable source produces an empty-but-fresh reading, or the two dates collapse into one.
**If it fails:** one line to Fable, and continue with step 7.
**Handoff:** none.

### STEP 7 — Cancelled, expired and wrong-person work produces nothing

**Enter this step when:** steps 4 and 5 are proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — the identity rules read real people's records · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the eligibility path under projects/ops/skippy-jobs/, reading the existing gates at projects/ops/skippy-jobs/lib/jobs-gate.mjs and projects/ops/skippy-jobs/lib/role-owner.mjs. Never weaken an existing gate to make a case pass.
**needs Nick: no**

**Do exactly this:**
1. Bind the existing release and audience gates so a scheduled task can never route around them.
2. Build fixtures for cancelled, expired, unreleased and wrong-person cases.
3. Prove each produces zero effects and records why, rather than failing silently.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case eligibility` prints `eligibility: PASS`; each ineligible case produces zero effects with a recorded reason. Evidence: ARTIFACT SAVED. FAILS IF an expired one-off fires, or a wrong-person item is delivered.
**If it fails:** one line to Fable, and continue with steps 28 and 29.
**Handoff:** none.

### STEP 8 — Chantelle's morning message, live

**Enter this step when:** steps 3, 5, 6 and 7 are proved. This is first in Nick's build order.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: household and personal content · **Checker:** MID · Anthropic · Claude Opus 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the briefing path under projects/ops/skippy-jobs/ and the harness fixtures. The locked wording at projects/ops/life-os/audits/A5/BUILD-PACKAGE/MESSAGES.md is read, never edited by the builder.
**needs Nick: no — sending as Skippy on WhatsApp and Slack, and test sends to Chantelle, are standing grants.**

**EXTENDS, MEASURED 2026-09-08:** her daily message runs today as the roster task `chantelle-gracie-daily-cc` (personal task_roster in projects/personal/health/spine/health-spine.json, cadence "daily 7:35am", heartbeatKey `chantelle-gracie-daily`), with `projects/ops/skippy-jobs/jobs/gracie-chantelle-inbox-lite.mjs` as the lean job that handles her inbound side. Open both before writing anything. This step repairs and re-points that task at the family app's own to-do store and moves its hour; it does not create a second daily message.

**THE HOUR IS THE ASSUMED DEFAULT.** 08:00 Cancun is built because the locked contract calls it "the proposed implementation default, not a claimed existing preference" and nothing on the record confirms an hour with her. It is one configuration value; if she wants another time, it changes in one line and nothing else moves.

**Do exactly this:**
1. Build the message from her real due tasks in the family app, read through `GET /api/todo-list?list=chantelle`, numbered so she can answer by number, against the locked wording including the exact text used when a source cannot be read. It is a fixed template filled with real titles, with no model phrasing it.
2. Send it as one message on WhatsApp and on Slack, sharing a single identity, and assert one message a day with a real destination receipt from step 5 and one catch-up before 10:00 rather than a late send.
3. Keep the Wednesday "Pay Sarah" row a reminder: no amount, no account, no payment tool touched. Prove it on a Wednesday fixture and prove it is absent on the other days.
4. Register her entry with the watcher from step 3 — a row by 10:00 each day — then deliberately skip one run and watch the alarm fire, name her message in plain English, and clear when the next run lands.
5. Do not invite numbered replies on the real channel until step 9 is proved; until then the live message carries the plain wording without the reply options.
6. WHICH SENDS ARE TESTS AND WHICH IS REAL: every send made while proving runs on the harness's injected transport and reaches no channel at all. The FIRST REAL SEND is the first scheduled 08:00 run after this task is switched on, and it is a genuine message to Chantelle, not a test — the destination read-back is taken on that send. No rehearsal message is ever put in front of her.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case chantelle-morning` prints `chantelle-morning: PASS`, having been shown RED first against the unrepaired task; the message gate reports zero mismatched lines and zero unmeasured lines against the locked wording at phone width; the WhatsApp provider receipt and the Slack timestamp are both read back; the deliberately skipped run produced a named alarm that cleared itself. Evidence: ARTIFACT SAVED — the graded comparison, the two receipts, and the alarm text. FAILS IF a single word differs from the locked text without a recorded change, or the skipped run went unnoticed.
**Design fidelity gate (section D):** this step publishes words a person reads, so the gate applies in full — locked target, a grader who did not build it, zero mismatched lines, and no close above zero.
**If it fails:** the task stays off, that is recorded as off rather than assumed working, and steps 10 to 14 continue.
**Handoff:** none.

### STEP 9 — Chantelle's replies actually completing a task

**Enter this step when:** step 8 is proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: household content · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the reply-correlation path under projects/ops/skippy-jobs/ and the harness fixtures. THE TWO RULES THAT LOOKED LIKE THEY DISAGREED, SETTLED: this step never edits the family app's CODE — that belongs to its owner and the app is deployed from two machines where uncommitted work has been lost before. It changes the app's DATA, and only through the app's own public write route, `POST /api/todo-store-write` with an explicit `to_list`, run from ONE machine, the Mac mini. Anything that genuinely needs a code change in the family app or the WhatsApp route is handed to that owner as one dated line through Fable and is not attempted here.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** the household to-do store, its list resolver, its `someday` array and its write-safety floor already exist at projects/personal/family-app/functions/api/_todo-store.js, with the write route at todo-store-write.js and the read route at todo-list.js. The WhatsApp listener exists and deliberately ignores household conversations today. Read all of it before building; the missing piece is the map from a message's numbered rows back to real task ids, not the store.

**Do exactly this:**
1. Build the two pieces the earlier plan handed away rather than built: the record that maps a morning message's numbered rows back to real tasks, and a household reply on WhatsApp reaching that map instead of being ignored.
2. Match her reply to the exact task in that morning's message, complete or re-date it, then read the task back before telling her anything. Never bind a reply to somebody else's message and never act twice on the same reply.
3. Keep "Pay Sarah" and "message Sarah" on their existing approval path: a reminder reply alone can never move money or send a message to another person.
4. Register the listener with the watcher: this task has no clock, so its line is that the household conversation's position marker moves at least once a day. Stall the marker deliberately and watch the alarm fire.
5. Turn the numbered reply options back on in the live message from step 8 only once this is proved end to end.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case chantelle-replies` prints `chantelle-replies: PASS`, having been shown RED first; a test task moves through the real conversation end to end and is read back — this is the ONE proof in the plan that uses a real channel, so it goes to Chantelle on WhatsApp under Nick's standing test-send grant, every message in it begins with the word TEST, and its run-record rows are marked as test sends; the same reply repeated moves nothing a second time; a stalled marker raises a named alarm. Evidence: ARTIFACT SAVED — the conversation transcript with the read-back, the repeat attempt, and the alarm. FAILS IF "Marked X done" is ever said from an accepted write rather than a read-back.
**If it fails:** step 8's message keeps running without reply options, which is stated plainly to Chantelle rather than shipped half-working, and one dated line goes to the family-app and channel owners through Fable, recorded in projects/ops/life-os/audits/A5/PROGRESS.md.
**Handoff:** to the family-app and channel owners, dated, through Fable, only for anything this step could not build itself.

### STEP 10 — Nick's morning, stage two: the 07:36 message, carrying no work items

**ONE TASK, THREE STAGES, BUILT IN TWO STEPS.** Nick merged his morning message and his body-data pull into a single task on 2026-09-08: "Nick's morning", with three timed stages — the ring pull at 06:30, the message at 07:36, and the repair pass at 12:45. This step builds stage two; step 11 builds stages one and three. They are two build steps because they touch different code, but they register as ONE task with THREE heartbeat rows, and step 30 counts them as one task, not two. Neither step closes until the other has, and the watcher's entry for this task expects all three rows on the same day.

**Enter this step when:** steps 3, 5, 6 and 7 are proved. It does not wait for steps 8 or 9.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: personal content · **Checker:** MID · Anthropic · Claude Opus 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the briefing path under projects/ops/skippy-jobs/ and the harness fixtures. The locked wording at projects/ops/life-os/audits/A5/BUILD-PACKAGE/MESSAGES.md is read, never edited by the builder.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** his morning message runs today as `projects/ops/skippy-jobs/jobs/daily-task-email-lite.mjs` — the file the locked wording names by name — with `daily-task-email-liveness.mjs` beside it and the roster task `daily-task-email-cc` behind it. Open all three. This step repairs and re-points that job; it does not write a second morning message.

**TWO LINES OF THE LOCKED WORDING ARE SUPERSEDED HERE, RECORDED WITH THEIR DATES, because the plan cannot be graded against a contract it contradicts:**
· SOURCE. The locked text reads his personal due items from "his existing personal Monday board". Monday is out — Nick, 2026-09-08 10:30, "hub and family app become databases and leave monday and other tools out of it" — so the replacement source is the family app's own household to-do store, his list, read through `GET /api/todo-list?list=nick`, which was opened and confirmed on 2026-09-08. Today's calls still come from the existing expanded calendar route, unchanged.
· DESTINATION. The locked text delivers to "Nick's Updates with its existing Slack delivery to #nicks-life". The family app's Updates tab was removed for good — Nick, 2026-09-05, "no updates tab ever" — so the Updates feed is NOT a destination for this message: writing there would pass a read-back while the message sat on a surface he has no way into. The single destination is his own Slack channel, #nicks-life, and the read-back is taken there.
Write both substitutions, with their dates and his words, into the evidence folder as the recorded change to the locked wording, and have the grader apply exactly those two and no others.

**Do exactly this:**
1. Build his message from his personal due items — `GET /api/todo-list?list=nick` — and today's calls, against the locked wording including the exact text used when a source cannot be read.
2. Deliver it as ONE message to his own Slack channel, #nicks-life, with a real destination receipt from step 5, and one catch-up before 10:00 rather than a late send. One destination, not two: nothing is written to the retired Updates feed.
3. Assert it contains zero work items: seed a due approval, a waiting task and an open decision into the fixture and confirm none of them appears. A business call is allowed because it is a call; a business task is not.
4. Register this stage with the watcher under the ONE task "Nick's morning" — the 07:36 row, due by 10:00 each day, alongside the two rows step 11 registers — then deliberately skip one run and watch the alarm fire, name the stage rather than the whole task, and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case nick-morning` prints `nick-morning: PASS`, having been shown RED first against the unrepaired job; the message gate reports zero mismatched lines and zero unmeasured lines against the locked wording, with the two recorded substitutions applied, at phone width; the seeded work items appear nowhere; #nicks-life is read back on the FIRST REAL SCHEDULED SEND after switch-on — no rehearsal message is ever sent to his live channel — and the skipped run produced a named alarm that cleared and was read back at its own destination. Evidence: ARTIFACT SAVED — the graded comparison, the recorded wording change, the Slack receipt and the alarm read-back. FAILS IF a work item reaches his message, or a single word differs from the locked text without a recorded change, or anything is written to the retired Updates feed.
**Design fidelity gate (section D):** this step publishes words a person reads, so the gate applies in full — locked target, a grader who did not build it, zero mismatched lines, and no close above zero.
**If it fails:** the task stays off and is recorded as off; steps 11 to 14 continue.
**Handoff:** none.

### STEP 11 — Nick's morning, stages one and three: the 06:30 ring pull and the 12:45 repair pass

**THE OTHER HALF OF ONE TASK.** This is not a second task. Nick merged the ring pull and his morning message into one task, "Nick's morning", on 2026-09-08. Step 10 builds stage two, the 07:36 message; this step builds stage one, the 06:30 ring pull, and stage three, the 12:45 repair pass. Together they are ONE task with THREE heartbeat rows, counted once in step 30.

**Enter this step when:** steps 3 and 6 are proved.
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: his body data · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the personal health collection path under projects/ops/skippy-jobs/ and the harness fixtures. THE ONE DESTINATION, NAMED: `projects/personal/health/spine/health-spine.json`. No other store, no second copy, no projection of its contents anywhere else — health data has one owner and one file, and a second one would be both a duplicate and a privacy problem.
**needs Nick: no — personal data needs no approval to flow; this is the one collection task with no consent gate on it.**

**EXTENDS, MEASURED 2026-09-08:** the ring pull already exists as `projects/ops/skippy-jobs/jobs/oura-backfill-heal.mjs`. Open it before writing anything; this step repairs and extends that file rather than adding a second health collector.

**Do exactly this:**
1. Pull his wearable and direct personal health data at 06:30 (stage one), and run the 12:45 repair pass (stage three) that fills anything the morning pull missed rather than leaving a hole. Both are Cancun time. This costs ZERO tokens: no model is called at any point in either stage, and if one of them ever needs a model that is a bug in the task.
2. Keep the date a reading belongs to separate from the date it was fetched, using step 6's rule. An unavailable source leaves the old value in place and marks it stale; it never writes a zero.
3. PRESERVE BEFORE WRITING, AS THE FILE'S OWN RULE AND NOT ONLY AS PROSE: read the current value for each date this run will touch and save it to the evidence folder before the write, and make a failed or partial pull leave the previous value byte-for-byte untouched. A write that cannot show its own preserved prior value is refused.
4. Write nothing to any other store, and never infer or add anything about treatment or dose.
4. Register both stages with the watcher under the ONE task "Nick's morning": the 06:30 row and the 12:45 row, beside the 07:36 row step 10 registers, plus a stale-data line on the health record itself — the newest reading must not fall behind. Skip one pass deliberately and watch the alarm fire, name the stage rather than the whole task, and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case oura` prints `oura: PASS`; a reading carrying yesterday's date is read back out of the health record; an unavailable-source fixture leaves the previous value with its own older date and a stale marker; the skipped pass produced a named alarm that cleared. Evidence: ARTIFACT SAVED — the read-back, the stale case and the alarm. FAILS IF a partial reading is written as final, or an unavailable source writes a zero.
**If it fails:** the task stays off and is recorded as off; steps 12 to 14 continue.
**Handoff:** none.

### STEP 12 — Overdue becomes today, live

**Enter this step when:** steps 3 and 7 are proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — his own task records stay inside · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the household list path under projects/ops/skippy-jobs/ and the harness fixtures. The two household to-do lists in the family app are the only source and the only destination — there is no outside board to read from or write to — and they are reached only through the app's own routes, `GET /api/todo-list?list=nick|chantelle` and `POST /api/todo-store-write`, never by editing the app's code.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** this task exists as `projects/ops/skippy-jobs/jobs/todo-bump-overdue.mjs`, which today reads Monday and skips items whose Priority text is "Someday". The work here is re-pointing that file at the family app's own store, not writing a second bumper. The store, at `projects/personal/family-app/functions/api/_todo-store.js`, was opened on 2026-09-08 and already answers both terms the earlier draft left undefined.

**Do exactly this:**
1. Move any task whose date has passed onto today, for both household lists, twice a day. Work in Cancun time, including for the day of the week.
2. "SOMEDAY" IS DEFINED BY THE FIELD THE APP ACTUALLY USES, not by matching a word: the store keeps a named `someday` row-array alongside `items`, `recently_done` and `archived`, and its own `someday` action is declared to move nothing between them. A row in that array is a someday row; nothing else is. Never infer someday from a title or a label.
3. THE PREVIOUS ROW COUNT IS NOT A REMEMBERED NUMBER AND MUST NOT BECOME ONE. The store's own floor is `storeShrankSinceRead(currentRowTotal, priorRowTotal)` and the caller passes `priorRows` — the count from its OWN raw read of the store taken moments before the write. Use that, exactly as the store's header instructs; never synthesise a stand-in prior payload, and never persist a "last time" count in a new file, because a prior of zero disables the floor and a gate that looks wired and enforces nothing is worse than none. Refuse to write when this run's read comes back with fewer than half the rows its own prior read held.
4. PRESERVE THE OLD DATES BEFORE THE FIRST LIVE RUN, because a wrong run re-dates everything and the original dates are otherwise simply gone. Write every row's id and current due date to a file named `overdue-pre-run-dates.json` in this lane's one evidence folder, named in §3b, before the first live run, and record the way back in one line beside it: one `action:"date"` write per row through `POST /api/todo-store-write`, restoring the saved date. Prove the way back on a fixture before the live run, not after.
5. Register it with the watcher: two rows a day, plus a stale-data line — no task moved for two days while overdue items exist. Skip one run deliberately and watch the alarm fire, read it back at its destination, and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case overdue` prints `overdue: PASS`, having been shown RED first; an overdue fixture task carries today's date afterwards and is read back from the list; a fixture row in the `someday` array is untouched; a collapsed-read fixture refuses to write and says why; the saved pre-run dates file exists and the restore path has been exercised on a fixture; the skipped run produced a named alarm that cleared and was read back. Evidence: ARTIFACT SAVED — the read-back, the someday control, the refusal, the pre-run dates file and the proved restore. FAILS IF a row in the `someday` array is moved, or a collapsed read still writes, or the first live run happens with no saved pre-run dates file.
**If it fails:** the task stays off and is recorded as off; steps 13 and 14 continue.
**Handoff:** none.

### STEP 13 — The kids' calendar push, live

**Enter this step when:** steps 3, 6 and 7 are proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — never a cheap outside vendor: family content · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the kids' projection path under projects/ops/skippy-jobs/ and the harness fixtures. Willow's and Noah's day views in the school app are the only destinations.
**needs Nick: no**

**THE CHILDREN ARE WILLOW AND NOAH, AND NOBODY ELSE.** Nick corrected this on 2026-09-08 after an earlier version of the rebuild list named team members instead. Mae, Dean and DinDin are colleagues; nothing in this step or step 14 addresses them, and a build that pushes a day view to any name other than Willow or Noah has failed.

**EXTENDS, MEASURED 2026-09-08:** this task exists as `projects/ops/skippy-jobs/jobs/calendar-push.mjs`. Open it first; the existing title and time rules and the 11:02 slot live in that file and are kept, not re-invented.

**Do exactly this:**
1. Read the family calendar at the existing slot and set Willow's and Noah's day blocks from it, using the existing title and time rules. Keep that slot; do not move it to an invented morning time.
2. Skip anything that cannot confidently be attributed to Willow or to Noah rather than guessing it onto one of them.
3. If the calendar cannot be read, leave yesterday's view in place and mark it visibly old rather than blanking it. One catch-up the same day, then skip.
4. Register it with the watcher: a row each day carrying how many blocks Willow got and how many Noah got, plus a stale-data line — the day view must be built for today, not an earlier date. Skip one run deliberately and watch the alarm fire and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case kids-calendar` prints `kids-calendar: PASS`; a known event is read back from the correct child's day; an ambiguous fixture event appears on neither Willow's nor Noah's day; an unreadable-calendar fixture leaves the previous view visibly dated; the skipped run produced a named alarm that cleared. Evidence: ARTIFACT SAVED. FAILS IF an ambiguous event lands on a child, or an unreadable calendar blanks the view, or a day view is written for any name other than Willow or Noah.
**If it fails:** the task stays off and is recorded as off; step 14 continues.
**Handoff:** none.

### STEP 14 — The kids' check-in prompts, live

**Enter this step when:** steps 3, 6 and 7 are proved.
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: family content · **Checker:** MID · Anthropic · Claude Sonnet 5 · se-blind-checker grades the message gate having built none of it; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the check-in path under projects/ops/skippy-jobs/ and the harness fixtures. The existing parent route is the only destination, and the locked wording at projects/ops/life-os/audits/A5/BUILD-PACKAGE/MESSAGES.md is read, never edited by the builder.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** this task exists as `projects/ops/skippy-jobs/jobs/kids-checkin-prompts-lite.mjs`, with a roster entry `kids-checkin-prompts` behind it. Open both first; Chantelle's recorded boundaries are already honoured in that file and must not be re-derived.

**Do exactly this:**
1. Prepare Willow's questions and Noah's questions — those two children and no others — from what is currently open and from Chantelle's own recorded answers and boundaries, on the three existing days. Asking nothing is a correct and successful outcome.
2. Never reopen a topic she has closed, and never invent a lesson or a completion — the school system owns those.
3. Make "I could not check" and "there is nothing to ask" two different outcomes with two different rows, using step 3's rule.
4. Register it with the watcher: a row on each of its three days only, so a Monday silence is not read as a miss. Skip one of those runs deliberately and watch the alarm fire and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case kids-prompts` prints `kids-prompts: PASS`; the prompt is read back on the intended parent route; a closed topic stays closed across two runs; the message gate reports zero mismatched lines against the locked wording; the skipped run produced a named alarm that cleared. Evidence: ARTIFACT SAVED — the read-back, the two-run closed-topic check, the graded comparison and the alarm. FAILS IF an unreadable source is rendered as "nothing to ask", or a closed topic reopens.
**Design fidelity gate (section D):** this step publishes words a person reads, so the gate applies in full — locked target, a grader who did not build it, zero mismatched lines, and no close above zero.
**If it fails:** the task stays off and is recorded as off; steps 15 onward continue.
**Handoff:** none.

### STEP 15 — The Hub due-work runner, live

**Enter this step when:** steps 3, 4, 5 and 7 are proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — business records stay inside · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the due-work path under projects/ops/skippy-jobs/ and the harness fixtures. The Hub is the only source and the only destination; it does not sync with any outside tool.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** the five kinds of due work this task performs each already have a job — `booking-reminders-sweep.mjs` (booking reminders), `recurrence-tick.mjs` (recurring jobs), `broadcast-tick.mjs` (approved broadcasts), `nps-tick.mjs` (satisfaction surveys) and `sla-tick.mjs` with `ro-followup-tick.mjs` (service-level follow-ups), all under projects/ops/skippy-jobs/jobs/. Open all six. This step consolidates and repairs them behind one due-work pass; it never writes a seventh implementation of work five of them already do.

**Do exactly this:**
1. Look at the Hub EVERY 15 MINUTES for work that has come due — a booking reminder, a recurring job, an approved broadcast, a satisfaction survey, a service-level follow-up — and perform the one next action that record already defines. Decide nothing new. Nick set the cadence himself on 2026-09-08: every fifteen minutes, not every minute, because nothing in the Hub comes due to the minute.
2. Never replay a cancelled or expired outreach, using step 7's gates. Anything that reaches a real recipient or moves money keeps its existing approval path: being due is not authorisation.
3. Keep business work out of both morning messages.
4. THIS TASK IS PLAIN CODE AND MUST COST ZERO TOKENS. No model is called at any point in the pass. Prove it: run a full day of passes and show a token count of zero. If it ever needs a model, that is a bug in the task, not a reason to give it one.
5. Register it with the watcher: a row inside the last thirty minutes, around the clock. A pass that found nothing due still writes a row. Skip a run deliberately and watch the alarm fire inside thirty minutes and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case hub-due-work` prints `hub-due-work: PASS`; a real Hub row moves from due to done and the effect is read back from the Hub; a cancelled fixture produces nothing; the recorded cadence is fifteen minutes, read back from the runner's own schedule rather than from this plan; a full day of passes records zero tokens; the skipped run produced a named alarm inside thirty minutes that cleared. Evidence: ARTIFACT SAVED. FAILS IF a due record sends to a real recipient without its existing approval, or the pass spends a single token, or the cadence lands anywhere other than fifteen minutes.
**Security note (section S):** this step touches an outbound path and an approval gate. Nothing is hardened, audited or rotated here; anything security-shaped is one line in projects/ops/sp-sec/PLAN.md and the step continues.
**If it fails:** the task stays off and is recorded as off; steps 16 to 21 continue.
**Handoff:** none.

### STEP 16 — Business data collection, with Nick's permission each time

**Enter this step when:** steps 3, 6 and 7 are proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer builds the looking and the extraction — the documents are business records, so nothing leaves the account · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the collection path under projects/ops/skippy-jobs/ and the harness fixtures. Nothing is written to the Hub before an approval exists.
**needs Nick: no to build it — the per-batch approval is exercised on a test batch, never a real one, until the task is live.**

**EXTENDS, MEASURED 2026-09-08:** the looking already exists as `projects/ops/skippy-jobs/jobs/capture-tick.mjs` (the drain-then-batch pass built for exactly this) with `bizapp-engine-ingests.mjs` beside it, and the dispatch confirmation contract exists at `projects/ops/skippy-jobs/lib/dispatch-contract.mjs`. Open all three before building.

**Do exactly this:**
1. Look over the business sources ONCE A WEEK and prepare everything that changed as one candidate batch. Nick set this on 2026-09-08: one comprehensive weekly run, not a poll every quarter of an hour. The weekly slot rides with the Rizza check in step 18 — Thursday at 17:00 Cancun, and again Friday at 12:00 if Thursday found nothing new — so business material arrives at one weekly moment. Build an ON-DEMAND run beside it that does the same sweep whenever Nick or a session asks, writes its own heartbeat row, and says it was on demand; the weekly row and the on-demand row are never confused for each other. His 18:55 correction the same evening moved this slot off Monday and onto the Thursday/Friday check — build to Thursday/Friday, not Monday.
2. Write nothing until Nick approves that exact batch — not the raw material and not facts pulled out of it. THE APPROVAL IS PER BATCH, never per source and never standing: every batch is offered to him on its own and stored only on his yes for that batch. Approving one week is not consent for the next week, and it is not consent for a second batch inside the same week. An on-demand run produces its own batch and its own approval, exactly like the weekly one.
3. THE APPROVAL PATH IS NAMED, AND IT IS NOT A BARE TAP. Nick replaced the approve/deny tap on 2026-09-08 12:35: "he needs to confirm the details of the request being tapped like he confirms the details of dispatched items so make it the same process." So an approval here goes through the SAME PROCESS AS A DISPATCH CONFIRMATION, through the existing dispatch contract — the request appears in the dispatch feed; Skippy restates, in plain English, exactly what he is about to store and from where; Nick can approve, edit or reply; only a confirmed, detail-checked request executes; and the result reads back into the same thread. A builder that ships a bare yes/no button has built the retired shape. All four refusal cases below run through this same path.
4. FENCE THE CHEAP TIER BY CONTENT, NOT BY DOCUMENT CLASS. "It is a business document" is not a permission — business documents routinely carry financial detail. A cheap outside model may see an approved business document only after a deterministic pre-check has run over that exact text and found no figure, rate, account detail, pay amount or person's name in it, and that check's output is saved as evidence beside the batch. If the check does not run, or finds anything, the extraction stays on the trusted bench. Nothing personal, family, health or financial reaches a cheap vendor at any point, and nothing in STEP 19 goes cheap at all.
4. Name the one standing exception in the code as well as here: Rizza's weekly finance report, built in step 18, and nothing else.
5. Register it with the watcher: a row on Thursday, and on Friday when Thursday found nothing, plus a count of how long the oldest waiting candidate has waited. An on-demand row is extra and never counts as the weekly one. Skip a run deliberately and watch the alarm fire and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case business-collection` prints `business-collection: PASS`, having been shown RED first; a confirmed, detail-checked request through the dispatch-confirmation path is joined to the exact stored batch and its result reads back into the same thread; missing, altered, expired and reused approvals each write nothing and say why, through that same path; a fixture document carrying a pay figure is refused the cheap bench by the pre-check and stays on the trusted one; the skipped run produced a named alarm that cleared and was read back. Evidence: ARTIFACT SAVED — the four refusal cases, the confirmed request and its thread read-back, the cheap-tier pre-check output, and the joined approval. FAILS IF any of the four refusal cases writes a single fact, or an approval is accepted as a bare yes with no restated detail, or a document reaches a cheap vendor without a saved pre-check.
**If it fails:** the task stays off and is recorded as off; steps 17 to 21 continue.
**Handoff:** none.

### STEP 17 — The Era bank feed into the family app's finances

**Enter this step when:** steps 3, 5 and 6 are proved. Nick, 2026-09-08: "era is the bank feeds for personal finances."
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: personal financial data · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; SCRIPT · none · deterministic code compares the two dates; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the personal finance collection path under projects/ops/skippy-jobs/ and the harness fixtures. The family app's finances store is the only destination; the app's own read-only route is read, never rewritten, and this feed stays its only writer.
**needs Nick: no — personal data, the same standing as his body data.**

**EXTENDS, MEASURED 2026-09-08:** this feed runs today as the roster task `morning-refresh-era-gmail-personal` (personal task_roster), known to the feed watchdog as the daily writer behind the `era-live` snapshot — `projects/ops/skippy-jobs/jobs/feed-watchdog.mjs` names it and holds its 30-hour staleness line. There is no job file for it under jobs/; it is a Claude task. Open its roster entry and the watchdog's line before building, and extend that task rather than creating a second Era writer.

**Do exactly this:**
1. Pull the account balances and last month's income, spend and net at the existing daily slot, together with the raw transaction rows, and scan his personal mail for spending the feed has not caught up with. THE MAIL SCAN IS ONE NAMED MAILBOX, READ-ONLY: Nick's own personal Gmail, the mailbox the existing feed already reads, opened read-only — it never marks, moves, labels, replies to or deletes a message, and it reads no other account. Extend the existing shape rather than inventing a new one: an "as of" date, net worth, each account with its institution, type, balance and available, last month's totals, and the fetch time kept separately.
2. Write it to the family app's finances and nowhere else. It never writes to the Hub — personal money is not business money.
3. Handle a category the app does not recognise by showing it under its raw name rather than dropping it into the wrong bucket.
4. On a failed fetch, leave the previous snapshot in place with its own older "as of" date visible. Never write an empty snapshot and never write a zero balance.
5. Register it with the watcher: a row each morning, and a stale-data line on the app's own balances card — an "as of" date older than its allowed age raises the other alarm even when the row is healthy. Skip a run deliberately and watch the alarm fire and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case era` prints `era: PASS`; `--read-only-live era` reads the family app's own finances screen and finds the "as of" date this run wrote, read from the app rather than from the fetch's own log; a failed-fetch fixture keeps the older snapshot with its own date; nothing appears in the Hub; the skipped run produced a named alarm that cleared. Evidence: ARTIFACT SAVED — the app read-back, the failed-fetch case, and the alarm. FAILS IF the fetch date is ever shown as the data's date, or a second copy of the snapshot exists anywhere.
**Security note (section S):** this step touches a financial connector and personal mail. Nothing is hardened, audited or rotated here; anything security-shaped is one line in projects/ops/sp-sec/PLAN.md and the step continues.
**If it fails:** the task stays off and is recorded as off, and the app keeps showing the last snapshot it has with its real date; steps 18 to 21 continue.
**Handoff:** none.

### STEP 18 — Rizza's weekly finance report into the Hub

**Enter this step when:** steps 3 and 6 are proved. Nick, 2026-09-08: "for the time being were still going to pull finance numbers from rizzas weekly report in that sheet."
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: protected financial detail · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; SCRIPT · none · deterministic code compares the two dates; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the finance ingestion path under projects/ops/skippy-jobs/ and the harness fixtures. The Hub's finance record is the only destination.

**EXTENDS, MEASURED 2026-09-08:** this feed runs today as the roster task `refresh-hs-dashboard-finance` (business task_roster, cron `0 9 * * 5,6` — a Friday pass with a Saturday catch-up), watched by `projects/ops/skippy-jobs/jobs/business-feed-watchdog.mjs`. Open both before building and extend that task; do not create a second weekly finance writer. THE REGISTERED CRON IS NOW WRONG AND THIS STEP CHANGES IT: Nick set the times himself on 2026-09-08 at 18:55 — Thursday 17:00 Cancun, and again Friday 12:00 if Thursday found nothing new — replacing the Friday/Saturday cadence the register still carries. Change it at the roster source and regenerate; a hand-edit of the generated projection erases itself.
**needs Nick: no — he approved this as a standing weekly feed on 2026-09-08, and it is the single named exception to step 16's per-batch rule. No other business dump inherits it.**

**Do exactly this:**
1. Read the week's profit-and-loss numbers out of her sheet on the THURSDAY 17:00 pass, with a FRIDAY 12:00 re-check when Thursday found nothing new. Both times are Cancun time and both come from Nick directly (2026-09-08, 18:55); they are not inferred from how the report has run in the past. Step 16's weekly business collection run rides with the Thursday pass, so the two fire together.
2. Put the landed-file gate first and never make it optional: advance the week only if that week's report is genuinely present. If it is not, write nothing, say so in the row, and try again next run.
3. Never write a partial or estimated week, and never carry last week's numbers forward under this week's date. Append one week exactly once however many times the run fires.
4. Register it with the watcher: a row on Thursday and, when Thursday found nothing, on Friday; plus a stale-data line on the Hub's own finance weeks — a newest week older than its allowed age means both passes missed.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case rizza-weekly` prints `rizza-weekly: PASS`; `--read-only-live rizza-weekly` reads the Hub's own finance view and finds the new week under the week's own end date; a not-yet-landed fixture writes nothing and says so; running the same week twice changes nothing; the skipped run produced a named alarm that cleared. Evidence: ARTIFACT SAVED — the Hub read-back, the gated no-op, the repeat run and the alarm. FAILS IF a week is appended when the report is absent, or the fetch date is stored as the week's date.
**If it fails:** the task stays off and is recorded as off, and the gap in the Hub's finance weeks is stated plainly rather than filled by hand; steps 19 to 21 continue.
**Handoff:** none.

### STEP 19 — Payroll hours and the payroll adjustments sheet

**Enter this step when:** steps 3, 6 and 16 are proved.
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — never a cheap outside vendor: protected financial detail · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the payroll ingestion path under projects/ops/skippy-jobs/ and the harness fixtures. The Hub's hours and payroll-week records are the only destination.

**EXTENDS, MEASURED 2026-09-08:** this feed exists as `projects/ops/skippy-jobs/jobs/bizapp-payroll-refresh.mjs`, registered as `refresh-payroll-hours` (business task_roster, cron `2 8 * * 2,4,6` — the Tuesday pass with the Thursday and Saturday catch-ups). Open both and extend them.

**NOTHING IN THIS STEP GOES CHEAP, AT ANY POINT.** Hours and pay are financial detail by definition, so STEP 16's cheap-tier permission does not reach here even though this step enters through STEP 16's approval contract. Every model touch on this step is MID or above, on the trusted bench.
**needs Nick: no — the per-batch rule from step 16 applies here, and his standing approval covers Rizza's weekly finance report only. This is a different sheet and a different set of files, so each refresh is offered as its own batch.**

**Do exactly this:**
1. Fetch the two newest time-tracking exports and the payroll and adjustments sheet on the Tuesday pass, with the Thursday and Saturday catch-ups, because the payout block lands four to twelve days after the week ends and Tuesday usually finds it missing.
2. Gate on the week actually being present before advancing anything, exactly as step 18 does, and make a run that finds nothing new cost nothing.
3. Never re-stamp unchanged data with a new fetch date.
4. Measure the shared-drive access rather than assuming it: read it, record what came back with its timestamp, and report that state. When it was last tested it returned no files, so this task may be built and proved against a copy while remaining held on the real source. Do not work around it by having a person paste numbers in.
5. Register it with the watcher: a row on Tuesday, and on Thursday and Saturday when the week is still missing; plus a stale-data line on the Hub's newest payroll week. Make "the drive returned nothing" and "there was nothing new" two different rows.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case payroll` prints `payroll: PASS`; the Hub's hours and payroll-week views are read back under the week's own end date; a re-run writes nothing; the two different rows are distinguishable; the measured drive-access state is recorded with its timestamp. Evidence: ARTIFACT SAVED — the Hub read-back, the repeat run, the two rows and the access measurement. FAILS IF the access state is written from memory rather than from a read this step performed.
**If it fails:** the task stays built and held, that is recorded as held with the drive-access reason named, and one dated line goes to the owner of that access through Fable, recorded in projects/ops/life-os/audits/A5/PROGRESS.md.
**Handoff:** the shared-drive access, to its owner, dated, through Fable.

### STEP 20 — The team standup recording into the Hub

**Enter this step when:** steps 3, 4 and 6 are proved.
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer — the speaker attribution stays on a trusted bench · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the standup capture path under projects/ops/skippy-jobs/ and the harness fixtures. The Hub's standup record is the only destination. THE TASK'S OWN WORKING DIRECTORY, under the standup capture path, is the ONLY directory anything is ever deleted from.
**needs Nick: no — because the only file deleted is one this task itself created moments earlier, in a directory it owns. If the intent ever changes to removing the team's own copy of a recording, that is irreversible destruction of somebody else's material and it is Nick's call, not this task's.**

**EXTENDS, MEASURED 2026-09-08:** this feed exists as `projects/ops/skippy-jobs/jobs/bizapp-standup-capture.mjs`, with the structuring half running as the roster task `business-standup-structurer` (business task_roster, cron `30 15 * * 4`). Open both and extend them.

**Do exactly this:**
1. Look for the recording on the standup day at the existing passes and copy it into this task's own working directory under the standup capture path. Extract the audio there, produce the transcript, and file the transcript with the meeting's own notes in the Hub.
2. THE DELETE, NAMED EXACTLY. The only thing deleted is the INTERMEDIATE VIDEO FILE THIS TASK ITSELF WROTE INTO ITS OWN WORKING DIRECTORY in point 1 — one named file, in one directory this task created. It is deleted ONLY AFTER the transcript has been read back out of the Hub and found complete; if the read-back fails, nothing is deleted and the run says so. THE TEAM'S MEETING RECORDING IN THE SHARED DRIVE'S RECORDINGS FOLDER IS NEVER TOUCHED — not moved, not renamed, not deleted — and the task refuses any delete whose path is not inside its own working directory.
3. Never process the same recording twice: check both the local record and the Hub's own list of what it already holds before starting.
4. Run the capture on its own rather than inside the tick, and read the verdict on the following pass, so a large recording never blocks everything else. Do not solve that by giving the task a long timeout.
5. Treat the transcript as private team material; it is not summarised into any message.
6. Register it with the watcher: a row from each pass on the standup day, plus a stale-data line on the Hub's newest standup.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case standup` prints `standup: PASS`, having been shown RED first; the transcript is read back from the Hub under the meeting's own date BEFORE any delete happens; the deleted path is inside this task's own working directory and a fixture that points the delete at the shared drive's recordings folder is refused; the shared drive's recordings folder is listed before and after a run and is byte-identical; a second pass over the same recording adds nothing; a large-recording fixture completes on a later pass without holding the tick. Evidence: ARTIFACT SAVED — the Hub read-back, the refused out-of-directory delete, the before-and-after listing of the recordings folder, the repeat pass and the timing record. FAILS IF anything outside this task's own working directory is deleted, or a delete happens before the Hub read-back, or the same recording produces two records, or a long capture blocks the tick.
**If it fails:** the task stays off and is recorded as off; step 21 continues.
**Handoff:** none.

### STEP 21 — Jasmin's daily slot check, live

**Enter this step when:** steps 3 and 7 are proved. Nick, 2026-09-08: "ok once a day for jasmin." It stays its own task and is not folded into anything else.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer builds eligibility and the extraction — the slot check reads a client's own editorial record · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the slot-check path under projects/ops/skippy-jobs/ and the harness fixtures. The existing review queue is the only destination.
**needs Nick: no**

**MEASURED 2026-09-08, AND THIS ONE IS GENUINELY NEW:** a search of projects/ops/skippy-jobs/jobs/ and both task rosters for a Jasmin slot check returned nothing — there is no existing implementation to extend, so this step writes one new file. Record the search and its empty result as evidence before writing it, so "there was nothing there" is a measurement rather than an assumption.

**Do exactly this:**
1. Check once a day whether an approved editorial slot has reached its next stage and hand that one due item to the existing review queue.
2. Write nothing, publish nothing and judge no writing. THE CHEAP TIER IS FENCED HERE TOO: unpublished client editorial material is protected content, so a cheap outside model may see a slot's text only after the same deterministic pre-check STEP 16 uses has run over it and found no client name, figure, rate or unpublished draft body — otherwise the extraction stays on the trusted bench. The cheap tier never judges whether a draft is any good, at any tier of check.
3. An unreleased or cancelled slot produces nothing at all, using step 7's gates.
4. Register it with the watcher: one row a day, including on a day when nothing was due. Skip a run deliberately and watch the alarm fire and clear.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case jasmin` prints `jasmin: PASS`; a valid slot is read back in the review queue exactly once; a cancelled slot produces nothing; nothing publishes; the skipped run produced a named alarm that cleared. Evidence: ARTIFACT SAVED. FAILS IF a cancelled slot reaches the queue, or the same slot arrives twice.
**If it fails:** the task stays off and is recorded as off; steps 22 onward continue.
**Handoff:** none.

### STEP 22 — Complete the watcher: stale data, the whole named list, two cadences

**Enter this step when:** every step from 8 to 21 is EITHER registered OR explicitly held with a named reason. One held step never blocks this one — STEP 19 is expected to stay held on shared-drive access, and if a held step could close this gate it would silently stop steps 26, 27 and 30 as well. The read-back in point 2 lists a held step AS HELD, with its reason, never as missing. It completes the watcher built in step 3; it does not introduce it.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — the stale-data half reads personal and business landing places, so this is protected data and never goes cheap · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the watcher path under projects/ops/skippy-jobs/ and the harness fixtures. It never edits another task to make itself pass, and it never creates a second register or a second watchdog.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** the missing-heartbeat half is `projects/ops/skippy-jobs/jobs/roster-liveness-watchdog.mjs` and the stale-data half already has two implementations to extend — `projects/ops/skippy-jobs/jobs/feed-watchdog.mjs` (personal feeds, including the `era-live` 30-hour line) and `projects/ops/skippy-jobs/jobs/business-feed-watchdog.mjs` (business feeds). Open all three. This step extends them; it writes no fourth watchdog.

**Do exactly this:**
1. Extend the second half: ignore the run record entirely and read each feed's actual landing place, alarming when what landed is older than that feed's own allowed age. A task can write a perfectly healthy row and still be delivering nothing, and this is the only half that catches it.
2. Read the whole register back against this plan and the rebuild list, entry by entry, and prove nothing on either is unwatched and nothing watched is absent from both. A step held with a named reason is listed as HELD with that reason, never as missing.
3. Watch the three message listeners the same way as a task with no clock: by whether each one's position marker is advancing, never by whether messages arrived. A quiet channel is not a dead one.
4. Prove the missing-heartbeat half on two different cadences, not one: skip a run of a short-cadence task — the build-coordination timer at five minutes or the Hub due-work runner at fifteen — and skip a run of a task that runs once a day, and show both are noticed inside their own windows and named in plain English.
5. Prove the stale-data half separately: hold a feed's data back while its job keeps reporting success, and show the alarm fires anyway.
6. BUILD THE THIRD HALF: THE LOST-TAP SWEEP. Every 15 minutes, look for an approval Nick granted that never reached the agent waiting on it, and raise each one, naming the approval, who is waiting and how long it has been stuck. Nick set this on 2026-09-08: delivering an approval is an EVENT and must never be put back on a clock — the tap carries itself to the waiting agent the moment he taps. This sweep is the safety net BEHIND that path and must never become the way approvals normally arrive; a build that delivers approvals from this sweep has rebuilt the retired polling drain. MEASURED 2026-09-08, and it is why the sweep exists: the approval journal at projects/ops/skippy-jobs/state/slack-approvals-journal.jsonl records the card reaching Nick and his tap — both happened today with the job runner down — but records nothing about the tap reaching the agent, and both things that used to carry it (`approval-relay-drain` and the cloud `approval-ping-relay`) are off. Prove it: grant a test approval, block its delivery, show the sweep names it within fifteen minutes, then deliver it and show the alarm clears.
7. Prove it does not cry wolf: leave a healthy quiet source alone and show nothing is raised.
8. Make sure something outside the watcher notices if the watcher itself stops; it cannot be the only thing watching itself. The existing job for that is `projects/ops/skippy-jobs/jobs/com-skippy-jobs-launchd-watch.mjs`, which asks launchd and the process table on the mini directly; extend it rather than adding another.
9. PROVE EVERY ALARM REACHES A PERSON AND IS READ BACK THERE. The existing severity routing already picks the surface — a real page to Nick's own channel through `alertNick` for an overdue non-provisional fast-cadence task, a Hub board card through `postUpdate` otherwise, cleared by `resolveUpdate` on recovery. For each alarm raised in this step, read it back from that destination's own record, never from the watchdog's log, exactly as contract C4 requires of a message. An alarm raised into a place nobody opens is not an alarm.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case watchdog` prints `watchdog: PASS`, having been shown RED first; the two skipped runs on two different cadences are each noticed, named in plain English, and READ BACK at the destination their own severity chose; the held-back feed is caught by the stale half while its row stayed healthy; the blocked test approval is named by the lost-tap sweep within fifteen minutes and the alarm clears once it is delivered; the healthy quiet source raises nothing; the entry-by-entry read-back shows no unwatched task and no watched entry missing from the register, with any held step listed as held with its reason. Evidence: ARTIFACT SAVED — the two alarms with their destination read-backs, the stale alarm, the blocked-approval alarm and its clearance, the quiet control, and the read-back table. FAILS IF a green run is possible while a task's data has stopped arriving, or an approval is ever DELIVERED by the sweep rather than merely reported by it, or any alarm is evidenced from a log rather than from the surface a person opens.
**If it fails:** every task that closed against a skipped-run proof keeps that proof, and the missing half is named in one line to Fable rather than assumed covered.
**Handoff:** none.

### STEP 23 — The backup check, live

**Enter this step when:** step 3 is proved. Independent of the task steps.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer — the backup check reads store names and fingerprints that sit beside protected content · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; SCRIPT · none · deterministic code compares the fingerprints; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the backup check path under projects/ops/skippy-jobs/ and the harness fixtures. Never anything live, and never a second backup system.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** this task exists as `projects/ops/skippy-jobs/jobs/mac-backup-watch.mjs`. Open it first and extend it.

**Do exactly this:**
1. Check daily that the backup exists and is readable, not merely that it was written.
2. Once a month, restore one sample file into a named ISOLATED RESTORE DIRECTORY that this task creates for the purpose, and confirm it opens and its fingerprint matches. Never restore over anything live.
3. THE DELIBERATELY CORRUPTED THING IS A COPY INSIDE THAT ISOLATED RESTORE DIRECTORY, NEVER THE BACKUP ITSELF. Corrupt the restored copy, prove the check goes red, then discard the copy. Nothing in the real backup is ever written to by this task.
4. Never copy a secret into the result — report only whether it opened and whether the fingerprint matched.
5. Register it with the watcher: a row each day and one for the monthly pass, plus a stale-data line on the backup's own age.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case backup` prints `backup: PASS`, having been shown RED first; a restored sample's fingerprint matches the original; a corrupted COPY IN THE ISOLATED RESTORE DIRECTORY makes the check exit non-zero, and the real backup's own fingerprint is unchanged before and after; the result contains no secret value. Evidence: ARTIFACT SAVED — the match, the corrupted-copy control, the backup's unchanged fingerprint, and the scrubbed result. FAILS IF a corrupted copy still passes, or the real backup's fingerprint moves, or any secret value appears in the result.
**Security note (section S):** this step reads a backup that contains sensitive material. Nothing is hardened, audited or rotated here; anything security-shaped is one line in projects/ops/sp-sec/PLAN.md and the step continues.
**If it fails:** the task stays off and is recorded as off; steps 24 onward continue.
**Handoff:** none.

### STEP 24 — The spend and quota guard, live

**Enter this step when:** step 3 is proved. Independent of the task steps.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer builds the spend and quota guard · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · OpenAI Codex · GPT-6-Astra reviews the guard — a wrong verdict here spends real money.
**Files you may touch:** the spend and quota path under projects/ops/skippy-jobs/ and the harness fixtures. Never weaken an existing guard while tidying.
**needs Nick: no — it never buys anything.**

**EXTENDS, MEASURED 2026-09-08:** both halves exist — `projects/ops/skippy-jobs/jobs/spend-guard.mjs` with `spend-tracker.mjs` for the spend half, and `quota-kill-watch.mjs` for the model-ceiling half. Open all three and extend them; this is a consolidation of jobs that already run, not a new guard.

**Do exactly this:**
1. Watch what the work is costing at the existing cadence and stop anything that breaches the limit; write one accounting line a day.
2. Notice separately when a model account has hit its weekly ceiling, so work that was killed can be resumed rather than silently lost.
3. Never buy anything and never quietly downgrade a model to save money — that is a decision, not a timer's job. An unknown allowance stays unknown and is never recorded as zero.
4. Register it with the watcher: a row on each of its cadences, with the unknown allowance written as unknown in the row.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case spend-guard` prints `spend-guard: PASS`; a run killed by a quota limit becomes resumable exactly once; an ordinary error fixture is not treated as a quota problem; the guard still refuses spend it should refuse; an unknown allowance reads as unknown. Evidence: ARTIFACT SAVED. FAILS IF an unknown allowance is recorded as zero, or an ordinary error is resumed as a quota kill.
**If it fails:** the task stays off and is recorded as off; steps 25 onward continue.
**Handoff:** none.

### STEP 25 — The build-coordination timer, live

**Enter this step when:** step 3 is proved. It does NOT wait for step 28: until that fix lands, this step posts through the direct card path the lane already uses, exactly as section 5 says, and records that it is doing so. Waiting would idle a machinery step behind a board repair that has a working alternative in use today.
**Builder:** CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs — timer plumbing, no protected content in it · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the coordination path under projects/ops/skippy-jobs/ and the harness fixtures. Never another lane's cards.
**needs Nick: no**

**EXTENDS, MEASURED 2026-09-08:** this task exists as `projects/ops/skippy-jobs/jobs/build-control-status.mjs` with `coordination-governor.mjs` beside it. Open both and extend them.

**Do exactly this:**
1. Run it EVERY 5 MINUTES — Nick set the cadence himself on 2026-09-08 — moving approved work along its own plan, attaching its proof to its card, and picking up work whose owner has gone silent so it is not abandoned.
2. Keep one writer per thing at a time. Never mark work finished from a status message alone — only from its own recorded proof. Never invent a project or a card that does not exist.
3. THIS IS A SCRIPT AND MUST SPEND NOTHING. No model is called by the coordination pass at any point. Nick, 2026-09-08: any short-cadence task is scripts only, at zero AI cost. If this ever needs a model, that is a bug in the task, not a reason to give it one. Work it HANDS OUT runs at whatever tier that work itself declares — that is the work's cost and never the timer's, and the two must be accounted separately.
4. Register it with the watcher: a row every five minutes, including a pass that found nothing due.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case build-coordination` prints `build-coordination: PASS`; an approved next step is read back as progressed on the board; a closed step stays closed; abandoned work is picked up exactly once; the recorded cadence is five minutes, read back from the runner's own schedule rather than from this plan; and a full day of passes records ZERO model calls and ZERO AI spend for the timer itself, read from the existing spend record and measured separately from anything it dispatched. Evidence: ARTIFACT SAVED — the board read-back, the closed-step control, the single pick-up, the cadence read-back and the day's spend line. FAILS IF work is marked finished from a status message with no recorded proof, or the timer itself calls a model even once.
**If it fails:** the task stays off and is recorded as off; steps 26 and 27 continue.
**Handoff:** none.

### STEP 26 — Larry's weekly upkeep and continuity review, live

**Enter this step when:** steps 3 and 22 are proved, because his continuity check reads the watcher's own list.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer builds the scheduled task; the review it runs gathers with SCRIPT · none · deterministic code, reads ambiguous evidence at MID and judges at TOP · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the weekly review path under projects/ops/skippy-jobs/ and the harness fixtures. Never a credential and never an account.
**needs Nick: no — he proposes; nothing is retired on his say-so alone.**

**EXTENDS, MEASURED 2026-09-08:** the weekly pass already exists as the launchd agent `com.skippy.larry-weekly-pass` with `projects/ops/skippy-jobs/jobs/larry-hub-sync.mjs` carrying its findings to the Hub, and the weekly skill grader already exists as `projects/ops/skippy-jobs/jobs/grade-skill-evals.mjs` (a daemon wrapper around the grader one directory up). Open all three and extend them.

**Do exactly this:**
1. Check weekly what is broken, orphaned, duplicated or pointing at nothing, and confirm in the same pass that the same thing really is present on both Macs and every account — by checking both places, not by seeing a process running.
2. RUN THE WEEKLY SKILL GRADER INSIDE THIS REVIEW, not as its own timer — Nick, 2026-09-08 12:55: the weekly skill grader runs inside Larry's weekly review. Call the existing grader from this pass, fold its result into the same weekly output, and take its separate schedule row out so there is one weekly review and not two.
3. Hand the fixable items to their owners and one short decision list to Nick, in plain English.
4. Never re-raise something already settled. Anything proposed for retirement is independently attacked and shown to Nick before it is acted on.
5. Register it with the watcher: one row a week, saying both what the upkeep pass found and what the skill grader scored, and a row saying it deliberately stood down on the month's deep-review week.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case larry-weekly` prints `larry-weekly: PASS`, having been shown RED first; a deliberately planted problem is found; an already-settled item stays quiet; the skill grader's scores appear in the same weekly output and the grader has no separate schedule row left; the review item is read back on the Hub. Evidence: ARTIFACT SAVED — the planted problem, the settled control, the folded-in skill scores, and the Hub read-back. FAILS IF the planted problem is missed, or a settled item is re-raised, or the skill grader still fires on a timer of its own.
**If it fails:** the task stays off and is recorded as off; step 27 continues.
**Handoff:** none.

### STEP 27 — Benito's monthly outside-world review, live

**Enter this step when:** step 26 is proved.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-fixer builds the scheduled task; the review it runs reads the evidence at MID and judges at TOP · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the monthly review path under projects/ops/skippy-jobs/ and the harness fixtures.
**needs Nick: no — he proposes and never acts.**

**EXTENDS, MEASURED 2026-09-08:** the monthly pass already exists as the launchd agent `com.skippy.larry-monthly-pass`, with `projects/ops/skippy-jobs/jobs/monthly-system-review-lite.mjs` and `monthly-trend-review-lite.mjs` beside it and roster entries `monthly-system-review-cc` and `monthly-trend-review-cc` behind them. Open them and extend; do not add a second monthly review.

**Do exactly this:**
1. Look outward once a month at how the models, the tools and the vendors have moved, and propose what here is now out of date even though nothing has broken, plus the opportunities that have opened up.
2. Replace that week's light review rather than running alongside it, and make both rows say so, so the watcher never reads the skipped light review as a missing one.
3. Propose only. Nothing is retired on his say-so alone.
4. Register it with the watcher: one row a month.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case benito-monthly` prints `benito-monthly: PASS`; the monthly item is read back on the Hub; that week's light review deliberately stands down and both rows say so; the watcher raises nothing for the stood-down week. Evidence: ARTIFACT SAVED — the Hub read-back and the two rows. FAILS IF the light review also runs that week, or the watcher alarms on the deliberate stand-down.
**If it fails:** the task stays off and is recorded as off; steps 28 to 30 continue.
**Handoff:** none.

### STEP 28 — Make the board keep an update that reports success

**Enter this step when:** step 1 has landed. Independent of everything else.
**Builder:** MID · Anthropic · Claude Opus 5 · se-fixer makes the board keep a successful update · **Checker:** MID · Anthropic · Claude Sonnet 5 · verifier reads independently; TOP · Anthropic · Claude Fable 5.1 gives the verdict.
**Files you may touch:** the board posting path under projects/ops/skippy-jobs/lib/. Never another lane's cards.
**needs Nick: no**

**Do exactly this:**
1. Reproduce the fault: post an update that reports success and read the board back to show it was dropped, with a control update that is kept, so the fault is the update's content and not the session.
2. Fix the path so a successful update is stored, and prove the fix by running the same failing post again.
3. Re-post the updates from this lane that the board lost.

**PROOF:** `node projects/ops/skippy-jobs/lib/board-report.mjs --read --lane ai-builds` shows the previously dropped update present after the fix, and the control update unchanged. THE LANE AND THE TOKEN, both measured on 2026-09-08: `--read` needs `--lane` to read one lane's cards, and this lane's cards live on `ai-builds` (its ids all begin `ac-ai-builds-life-os-`); the board token is resolved by the house helper `boardToken()` from the daemon's own settings file and NEVER from an environment variable, so nothing needs to be exported and a run in a fresh shell or under launchd behaves the same. Evidence: ARTIFACT SAVED — the before and after reads. FAILS IF the control was also dropped, which would mean the session and not the board, or if the command is run without the lane, which reads every card on the board and proves nothing about this one.
**If it fails:** this lane posts through the direct card path instead and records that the board still drops successes, in one line to Fable and to the board's owner.
**Handoff:** the fix, or the reproduction, goes to the Hub build owner with a dated line.

### STEP 29 — Ask Mae whether her receipts process covers missing receipts

**Enter this step when:** step 1 has landed. Independent of everything else.
**Builder:** MID · Anthropic · Claude Sonnet 5 · se-recorder drafts the question for SKIPPY to send · **Checker:** MID · Anthropic · Claude Opus 5 · verifier reads the recorded answer back.
**Files you may touch:** projects/ops/life-os/audits/A5/BUILD-PACKAGE/service-contracts.json only.
**needs Nick: no — SKIPPY SENDS IT, UNDER HIS OWN NAME, on the team channel he already uses with Mae. That is the named sender: not "its existing owner", not Nick, and never as Nick. Internal team messages sent as Skippy are a standing grant.**

**EXTENDS, MEASURED 2026-09-08:** the receipts task exists as the roster entries `receipts-sweep-family` and `receipts-sweep-family-cc` (personal task_roster), switched off with everything else. Open them before deciding anything; if Mae's answer says build it, that entry is repaired and switched back on rather than replaced.

**Do exactly this:**
1. Draft one plain question: does her weekly receipts process already cover receipts that never arrived, or only the ones that did?
2. Skippy sends it under his own name on the team channel he already uses with her. No message goes out as Nick.
3. Record her answer VERBATIM with the date she gave it, in the `receipts_missing_covered` entry, as two fields: `answer_text` and `answered_on`. A key with a placeholder in it — "no answer yet", "pending", empty — is NOT an answer and must not satisfy this step.
4. THE PATH AFTER EACH ANSWER, so this does not dead-end: if she says the new process does NOT catch missing receipts, the Sunday 09:42 receipts chase is built by repairing the existing `receipts-sweep-family` roster entry, at MID · Anthropic · Claude Sonnet 5 · se-fixer, with the same cross-cutting requirements as every other task step — heartbeat row, watcher entry, skipped-run alarm read back, one unattended firing — and it becomes the twenty-second closed step. If she says it DOES catch them, the task is dropped for good and recorded as dropped with her words and the date. Until either answer exists, it is one of the two permitted holds in the finish line.

**PROOF:** the `receipts_missing_covered` entry in service-contracts.json carries a non-empty `answer_text` and a real `answered_on` date, checked by `python3 -c "import json,sys;d=json.load(open('projects/ops/life-os/audits/A5/BUILD-PACKAGE/service-contracts.json'));a=d['receipts_missing_covered'];sys.exit(0 if a.get('answer_text') and a.get('answered_on') else 1)"` exiting 0. Evidence: ARTIFACT SAVED — the sent question, her reply as received, and the recorded entry. FAILS IF the Sunday task is dropped, or built, with no recorded answer text — a key present with a placeholder value is a fail, not a pass.
**If it fails:** nothing is built and nothing is dropped; the open question is recorded rather than guessed, the task stays held as one of the two permitted holds, and the open gap is stated plainly.
**Handoff:** the answer goes to the existing finance owner with a dated line.

### STEP 30 — Every task live on its own proof, checked by a reader who built none of it

**Enter this step when:** every step from 8 to 27 is closed, or explicitly held with a named reason, and no more than two are held.
**Builder:** TOP · Anthropic · Claude Fable 5.1 evaluates — judgment, not building: it is the final grade across thirty live tasks · **Checker:** MID · Anthropic · Claude Opus 5 · se-blind-checker, final blind check, having built none of it.
**Files you may touch:** this plan's own state sections and projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/.
**needs Nick: no**

**Do exactly this:**
1. Read the rebuild list entry by entry and, for each of the twenty tasks, record one of exactly two states. COUNT "NICK'S MORNING" ONCE: it is one task built by two steps (10 and 11) with three timed stages and three heartbeat rows, and it is LIVE only when all three stages are. Then: LIVE — with its own passing proof, its heartbeat row, its entry in the existing register, and one recorded unattended firing on its own clock; or HELD — with the reason named in plain English. There is no third state, and there is a ceiling: no more than two tasks may be held, and they may only be the two already measured (the receipts chase pending Mae, and payroll pending shared-drive access). A third hold reopens its own step rather than being written down and passed.
2. Check that every feed lands in exactly one place and that its two dates are separately readable on the surface a person opens.
3. Prove nothing was duplicated: list projects/ops/skippy-jobs/jobs/ and the two task rosters and show that no task on the rebuild list has two implementations.
4. Hand the fresh checker the rebuild list and projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/ and let it grade without being told the answer.

**PROOF:** `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --read-only-live outcomes` returns one row per task on the rebuild list, each either live with its four receipts — proof, heartbeat row, register entry, unattended firing — or held with its reason, with at most two held; no task on the list has two implementations; and the fresh checker's independent pass agrees row for row. Evidence: ARTIFACT SAVED in the evidence folder — the twenty rows, the no-duplicates listing, and the fresh checker's verdict. FAILS IF any task's state is inferred rather than read, or a third task is held, or the two graders disagree on any row.
**If it fails:** the disagreeing rows reopen their own steps and nothing else is reopened.
**Handoff:** the closing report goes to Fable, who relays it to Nick in plain words.

## 4 · Regret Check

Every entry in the failure registry, with this lane's own measure or a named reason it does not apply.

| Failure mode (registry entry) | Measure in this plan | Where |
|---|---|---|
| A second system was built because the first was invisible | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A capability was declared impossible from a stale or unverified claim | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| An absence was asserted without opening the store that would hold it | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A known constraint's reason was lost, and it silently capped the product | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| An instruction assumed capacity the executor doesn't have | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| Expectations/manifest rows carried no grounding | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| Work was written to a queue no reader ever visits | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. The same rule is applied to ALARMS, not only to messages — each one is read back at the surface a person opens — and to the review queue Jasmin's slot check writes into, which is read back exactly once per slot. | STEP 5; STEP 8; STEP 10; STEP 21; STEP 22 |
| A detector's death was invisible because only its target read it | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A decision settled once re-opened elsewhere, or two copies of a rule disagreed | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A rule constraining the user turned out to be an agent's invention | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| Remediation was ordered with diagnosis last | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A document, label, or comment was believed over the live system | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A proposal was sold on a capability never opened and read | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A cause was named and acted on without eliminating alternatives | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| The human was asked a question the record already answers | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| A spec and its guard were authored by the same hand and ratified the same defect | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| Session rules never reached the subagents doing the work | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| One rule was blanket-applied across items needing per-item answers | One owner per fact and one writer per file. This lane never edits another lane's plan: an unmet cross-lane condition becomes one dated handoff line naming the receiving owner and the proof that would satisfy it, and an unaccepted handoff stays with the overseer. | 1 trip-over protocol; STEP 9; STEP 19 |
| Pattern-matching scoped too loosely produced false connections | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| Rules existed but were psychologically dormant at answer-time | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| A run exceeded its cost/time ceiling or hung unbounded | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| A helper was dispatched on a brief with a wrong or missing constraint | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A claim about the user/system was made without its source | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| A conclusion was drawn from a partial read | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A fact was quoted as current without its date | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A computed value never reached the persistent record | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| A missing lookup key fell back silently to a wrong default | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A hardcoded identifier broke when the referent was recreated | No task in this plan carries a typed-in identifier for something that can be rebuilt. A heartbeat row is keyed on the name the existing watchdog already resolves (`heartbeatKey \|\| taskId`), and beat.mjs's warning that a name is unwatched is treated as a stop; the register is REGENERATED from its source roster rather than hand-edited, so a regenerated table cannot leave a stale id behind; a card is addressed by the board's own deterministic id derived from its title, never by a captured row number; and a reply is matched to a task through the stored map from that morning's message, not through a position in a list. | STEP 3; STEP 9; STEP 25; STEP 28 |
| A placeholder or wrong-level path shipped as a literal instruction | Nothing is written into code that belongs in a record: Mae's answer, the measured shared-drive access state and each task's own timetable are read from a record with their dates. Host assignment stays with the existing machine-role registry, and the task list is landed on the main line before any machine is asked to read it. | STEP 1; STEP 19; STEP 29 |
| A UI reported success while the backend silently failed | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| Mid-session state was assumed unchanged | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| Uncertainty was silently absorbed instead of marked | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A serial multi-step operation blew its time budget | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| An external action went unlogged and became unrecoverable | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| A tool's own description contradicted house reality and won | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| Personal/identifying data exposed, or a record written to the wrong subject | THIS LANE WRITES THE KIDS' VIEWS, CHANTELLE'S LIST AND NICK'S HEALTH RECORD, so subject correctness is checked per write, not assumed. Every write names its one destination and its one subject: the health pull writes only to projects/personal/health/spine/health-spine.json and nowhere else; each household write carries an explicit `to_list` and a reply is never bound to somebody else's message; a calendar event that cannot be confidently attributed to ONE child appears on no child rather than being guessed onto one; wrong-person work produces zero effects with a recorded reason, proved as its own fixture; the standup transcript is treated as private team material and is summarised into no message; and no personal, health, family, financial, business or unpublished client content reaches a cheap outside vendor, by content and never by document class. Every evidence artefact is scrubbed of secret values before it is saved. | STEP 7; STEP 9; STEP 11; STEP 13; STEP 20; STEP 23; 3 frozen contracts |
| One instance of a defect class was fixed while its siblings stayed broken | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A read operation mutated state | Reads in this plan are read-only by construction and are proved so. The harness's `--read-only-live` mode may never send or change anything; the business collection look is read-only and writes nothing at all before an approval exists; the Era feed's mail scan opens one named mailbox read-only and never marks, moves, labels, replies to or deletes a message; a cursor advances only on an ACCEPTED change, so re-reading unchanged data moves nothing and re-stamps nothing; and the recurring reviews propose only and change nothing on their own say-so. | 3b harness interface; STEP 6; STEP 16; STEP 17; STEPS 26 and 27 |
| The three biggest absence-claims variants: empty result, broken probe, discarded stderr | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A generated mirror was hand-edited, or its generator never re-ran | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| Deployed config silently diverged from source config | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A delivery path was reordered and its notification behavior changed | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| A critical boundary was config-editable and could be silently widened | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A "growing" archive had actually frozen | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| Files were archived but their citations kept pointing at them | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| A pipeline broke silently and looked identical to a working one | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| Output was delivered somewhere the intended reader never looks | The destination is chosen by whether the person can actually reach it, not by what an older contract says. Nick's morning message goes to his own Slack channel and NOT to the family app's Updates feed, because that tab was removed for good on 2026-09-05 and a read-back there would pass while he had no way in; the change is recorded with his words and its date. Every alarm the watcher raises is read back at the surface its own severity chose — his channel, or the Hub board card — never from the watchdog's own log. Delivery still counts only on a destination read-back. | 1a row 9; STEP 10; STEP 22; 3b cross-cutting (d) |
| Concurrent sessions clobbered each other's work in a shared file | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| An enforcement gate covered fewer paths than its rule, or failed open | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| Identity or authority was read from a value the caller supplies | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| A new failure state was detected but reached no human | Every alarm has a named reader and a proved read-back. The existing watchdog routes by severity — an overdue non-provisional fast-cadence task pages Nick's own channel through `alertNick`, everything else becomes a Hub board card through `postUpdate`, cleared by `resolveUpdate` on recovery — and no step closes until one of its own runs has been deliberately skipped and the resulting alarm has been READ BACK at that destination's own record. An alarm evidenced from a log is an unproved alarm. Separately, no test or probe signal ever reaches Nick's live channels, so a real page is never lost in noise. | 3b cross-cutting (d); STEP 3; STEP 22; release fence |
| The builder graded its own work and passed it | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A check existed that could not fail | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| The review didn't cover the shipped artifact | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A narrowing/refactoring change broke the cases that were already correct | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| A check's verdict depended on wall-clock, machine load, or a concurrent writer | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A test existed but nothing ran it | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| An interactive element or view shipped untested / unseen | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| Coverage was reported optimistically | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A staleness/freshness check used the wrong proxy | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A quantitative claim shipped without its method | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| Done was declared before the live surface was checked | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A biometric/metric overrode the human's stated reality | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| A correlation was asserted as a cause | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A nuanced reality was collapsed into a clean binary | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A recommendation repeated something already tried, uncited | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A wrong record was disclaimed instead of corrected | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| Open items were re-typed from memory and drifted | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| A deliverable was referenced instead of delivered | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| A report used names/shorthand only the writer understood | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| Commands were sent to a surface that can't run them | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A number was published without the population it was counted over | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A finding existed only in the session's output and died with it | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| The plan named a target with total precision, and the target was wrong | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| The human approved a summary, and the summary was silent on the deciding variable | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A project stated its scope and never its anti-scope, and lanes leaked into adjacent work | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| A new rule was written as prose inside its own fix, with nothing enforcing it | Task definitions are written lean from the start rather than de-bloated later: a rule that binds everywhere is referenced once and never copied into each definition, and every safety case those rules exist to enforce has its own fixture in the harness. | 3 frozen contracts; STEP 2 |
| A confirmation was satisfied by checking the wrong kind of fact | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A blocker common to every lane was carved out of all of them and given to nobody | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| Lanes were built to stop: one pass, land, idle — while fixed ceremony ate the context | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| A caveat nobody measured travelled as fact through multiple independent lanes | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| The environment destroyed work silently, and the lane wrote a wrong lesson from it | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| A specification described ONE lifecycle in several places, and the copies drifted independently — four consecutive cold reviews each found ~5-8 blocking ambiguities, because every patch added another partial description of the same state machine | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A task brief on an existing project was treated as the plan, and a generated status checklist was treated as the task list | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| A regression test's "red-proof" failed for a reason unrelated to the thing it claimed to prove, twice in one session, two different mechanisms | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A standing instruction to route work to an outside/cheap engine eroded over a long session into doing the work directly | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| A plan's own second line named a different document as the authority, and the reader proceeded without opening it | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| A live bug got three consecutive confident wrong-or-unproven diagnoses, two claiming live verification | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| Fourteen guards stayed green all day while the live screen showed the wrong thing | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| An agent was accused of fabricating its report because a narrow search failed to find the file it cited | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A tool's failure verdict was believed without checking the disk — and separately, a success verdict shipped a syntax error | Covered by this plan's standing shape: one owner per fact, a checker who is not the builder, a runnable proof per step, an empty result recorded as unknown rather than as absence, and no task switched on before its own proof has passed — with a task that is not on recorded as not on, never assumed working. | 3 frozen contracts; 3b; STEP 30 |
| A build with several independently-shippable pieces was planned and run as one monolithic project, too large for one agent to hold | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A rule written only in prose, with no template slot and no machine gate, behaved as if it didn't exist | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| A row-quality check counted TOTAL filled cells instead of checking the specific columns it claimed to require | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| Three independent readers reported wildly different "% complete" for the exact same objective state — twice, on two different subprojects | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A V2 "opened it, here's what I saw" confirmation was wrong three separate times because it opened the WRONG PATH — the plan's own stated location, never independently rediscovered | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A shared coordination file used by several subprojects at once had no per-subproject write fence, and one subproject's list silently filled with rows belonging to the others | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| The single cheapest, most decisive test of a build's core hypothesis was defined at planning time (correctly) but not RUN until after most of the build effort was already spent | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A dispatched build agent reported an interim status ("build is in progress, will resume once a Monitor delivers the completion notification") as its FINAL answer and returned, instead of waiting for the real result | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| A sandbox restriction produced the EXACT error text this same repo's own CLAUDE.md already documents as a sign of a genuinely broken machine ("chrome exited early, code null" / Chrome preflight failure), and it was initially read as that known problem rather than investigated as a new one | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| A paid external tool (Codex CLI) ran out of its own usage quota mid-build, and the agent that hit the limit chose to switch to running the command directly via its own Bash tool instead of the mandated Codex path — correctly, but this is a real, recurring risk that needs a standing rule, not a one-off judgment call | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A card-creation script reported success ("card opened... read back and confirmed") and its own internal counter incremented, but the card did not actually exist on live re-query — twice, for two different cards, requiring full manual re-creation | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| Three separate, independently-fatal wiring gaps each made the same feature (the ai-builds board) non-functional in a different way, and NONE of them were caught by a passing `build-dist.js` run, any TIER-1 or TIER-2 gate, or any API-level check | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| A real, deployed code fix (the three fixes directly above) did not reach a real user's already-open browser tab, even after that user hard-refreshed multiple times | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A correct, intentional, previously-ruled-on design decision (the task screen's default view narrows to "my own tasks" even for leadership identities) was mistaken for a bug because it was checked from only ONE identity's login | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| The Updates panel — the actual surface a person opens to read what an agent posted about a card — is wired to Monday.com sync data ONLY, and an app-native card (this entire board) has no Monday board behind it, so it will read "No Monday updates on record for this item" FOREVER, regardless of how many real, correctly-formatted updates were posted server-side | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A pure oversight/QA dispatch (re-run four questions, grade the answers, write nothing) was refused twice in a row by the WORK-TYPE gate as "unclear," burning two full agent-spawn round-trips before the actual task began | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| The same brief, past the work-type gate, was then refused by a SEPARATE gate for missing the ~6,000-word MACHINE-RULES travel block — a requirement with no automatic injection and no template a brief author can copy from without hitting the refusal first | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| A fix (new SYSTEM-prompt grounding rules) was drafted, partially applied to disk, and left in a syntactically-valid but COMPLETELY UNVERIFIED state when the tool writing it (Codex CLI) hit its own account-wide usage cap mid-task | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| The above fix's failure was found ONLY because a second, genuinely fresh-context pass re-ran the real test live — the first pass's own self-check (syntax valid, code present) had already been satisfied and would have been reported "done" without it | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A confirmed, applied data fix was verified as working because it had only been applied to ONE of two live copies of the same data (production) — the copy actually being tested against (staging) still held the old, wrong text | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A 16-question regression suite meant to catch exactly this bug class had been silently crashing on question 1 and reporting nothing useful for a full day, because a dependency it called gained a new required argument and nobody re-ran the suite after that change landed | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| Two entire bodies of real, load-bearing work — a 34-file answer pipeline and this drive's own PLAN.md/STATE.md tracking pair — had never been committed to git, on any machine, the whole time they were being built, found only by accident while fixing something else | The North Star and finish line are written above every step, every earlier step is mapped by name into this one or recorded as deliberately removed with the measured reason, and every open assumption is written as an assumption with the question that would settle it. | North star; carried-from table; 1a |
| A request to deepen an existing artifact was answered by re-polishing the context already in hand, while named, existing sources were never opened | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A gate protecting one specific, highly sensitive file covered some tool surfaces (Write/Edit/MultiEdit) but not others (Bash), and the gap sat honestly documented in the file's own header for a day before being closed | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A function parameter's DEFAULT value silently made an entire decision branch unreachable, under a fully green test suite, since the day the branch was written | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A write-then-rename ("atomic write") pattern was used to update one row in a file that has a SECOND, independent writer appending new rows — the pattern is genuinely atomic against a torn read, and genuinely loses any row the other writer appended during the read-modify-write window | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A test suite's own "red-proof" claimed a safety property held ("removing the fix would fail the test") without ever actually removing the fix and running the suite | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| Test files that exercised a shared module's logging path wrote real output into the REAL production log file, even though every other piece of test state (queue, tickets, journal) was correctly scoped to scratch directories | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| An identity verified once, in memory, from a live authenticated source, was designed to be re-derived later from a file any process could write — which would have made the file, not the live authentication, the actual source of trust | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A background daemon process registered a global crash-and-exit handler for unhandled promise rejections; a later feature fired a promise without a `.catch()` in that same process, meaning any transient failure in that one feature (a network timeout) would have crashed the ENTIRE daemon, including everything unrelated it was doing | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A build's supersession of one design ("a standalone daemon" → "extend the existing listener") correctly re-scoped every task around the new mechanism's natural shape, and in doing so quietly dropped a piece of functionality that had no obvious home in the new shape | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| `fs.watch()` on a shared state directory was assumed to be a sufficient delivery trigger, and was not — under real concurrent load from ~235 other sessions writing to sibling files in the same directory, two real queued requests sat with zero fs.watch event ever firing | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| A plan asserted facts about the repo it never checked — one step named a symbol that travels under a different name; another's file fence named a file that does not exist (merges log items A3, A4, D2) | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| The program fixed what was BROKEN instead of building what was ASKED FOR — a day's good work landed on a component its own plan retires (log item J1) | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as held with the reason named, never assumed to be working. This plan switches nothing off: every scheduled task was already off by Nick's own hand before it started, and that state is re-measured on the machine rather than inherited. Every task step extends the file that already implements it, so a day's work can never land on a second copy that nothing loads. | STEP 1; each task's own switch-on; STEP 30 |
| A plan passed every gate — well-formed steps, real proofs — and still could not deliver what the user asked for (log item J2) | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| An assistant's first-person account of its own failure was taken as the root cause by every reader, and it was false (log item J3) | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| Three verifications were real and all three had the wrong SCOPE: verifying a quote is not verifying the claim; verifying a file once is not verifying it now; verifying the code path is not verifying the thing (merges H1, H2, H3 — one defect, three extents) | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| An orchestrator's confident relay propagated a wrong conclusion to five sessions faster than any plan could — a real acceptance criterion was deleted on it — and the builder that refused the relay with evidence was right (merges F1, J4) | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| One writer in three read the same handoff as a gate and serialized nine of fourteen steps behind another chunk's tenth step (log item F3) | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| Every failure mode of the file-approval machinery was silent: an approved-once path became permanently un-requestable; a legitimate handoff into a shared governed file consumed another chunk's pending approval; approval never notified the requester; one approval unlocked exactly one edit operation, losing a two-part edit's second half; and a plan tracker named STATE.md missed the PLAN-shaped free-edit carve-out, costing ~10 approval taps in one evening (merges B1, B2, B3, B4, I2) | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A governance CLI silently dropped unrecognized flags (exit 0), let a two-token flag value overwrite the file path, let --reason swallow the next flag as its value, and its own written spec documented the broken form in two copies (merges C1, C2, C3, C4) | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| Plan shape existed as convention, not enforcement: plans degenerated into 1,000-line session logs; the plan template itself failed the machine gate; the checker validates a plan's parts, never its shape (merges A1, A2, D1) | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A punchlist item condensed to six words pointed its reader at exactly the wrong action — implementing it literally would have silently rerouted every assistant reply into manual approval (log item I3) | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A production secret read as SET when its value was EMPTY, and every check agreed with the wrong answer for 90 minutes across three sessions | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| The SAME claim, on the SAME evidence, was CONFIRMED by a checker asked to verify it and REFUTED by a checker asked to break it — and the refuting one was right | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| Reasoning ABOUT a system instead of ASKING it — the single most repeated failure of the 2026-08-27/28 night, four times across three different sessions, every time producing a confident and wrong claim from real evidence | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| A hard prerequisite discovered AFTER a decision, with no owner assigned, silently converts a made decision into an unimplementable one | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A relayed instruction is acted on, or held, by whether the RELAY ITSELF could be the attack — and sessions had no test for that, so they either obeyed every relay or refused every relay | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| Two independent programs audited themselves on the same night and found the same disease — every instrument reported a state that was not the system's state — while both had been reading the reports as ground truth | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| A PROOF block read as complete while still containing its own template placeholders — four times in one plan, and the shape is mechanically detectable | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| Real evidence, deliberately destroyed for a good reason, is indistinguishable from evidence that never existed | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| A capability was ruled impossible on the strength of a query that structurally could not see the answer — the same shape as an earlier logged incident, on a different tool, and it was not recognised | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| The instruments used to verify a UI lie in four distinct ways, and a "drive the real surface" standard that does not name them produces confident false results | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A step's entry gate was satisfied and the step still could not run, and the format had nowhere to say so | No step waits on Nick and no step waits on a group: each entry condition names the specific artefact it needs, no human decision gates anything in this plan, and a task whose own floor steps are proved goes live alone rather than waiting for the slowest. | STEP 0; 3b gates to enter |
| An automated proof's own internal check detected failure and the surrounding pipeline logged success anyway — the checking logic and the reporting logic disagreed, and reporting won | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A dispatch gate blocked the exact defensive pattern its own preceding line prescribed, for the exact reason that pattern exists | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| A fallback held in place to make a cutover safe was itself the reason the cutover could never succeed — every retry failed, and each failure made the fallback look more necessary | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| An approved instruction was correct when it was approved and harmful by the time it could be delivered — and every existing rule for handling relayed instructions asked only whether it was AUTHENTIC, never whether it was still TRUE | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| "I fixed the file" · "I deployed it" · "that is what the user sees" are THREE different claims, and a chunk can be right about the first two and wrong about the third — the gap is a client cache that no repo read, no deploy log and no server-side fetch can see | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| In a multi-session build, code read from the working tree is not the state of the system — it may be another session's half-finished fix, and reading it as established behaviour produces a confident diagnosis of a bug that does not exist | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| Three successive rounds of fixes each produced an honest, passing proof, and the user's original complaint was untouched by all three — because every proof measured the mechanism the fixer had chosen to fix, never the sentence the user actually said | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A correct local caution was escalated into a fleet-wide halt across eight sessions on a crisis that did not exist — and the escalation priced only one side of the decision | The tier matrix is applied per row: top oversees, mid executes, cheap only where quality is unaffected, and deterministic work runs as a script with no model at all. Personal, health and family content never reaches a cheap outside vendor, whatever the tier table would otherwise allow. | 1a row 5; 3b; 5 |
| An overseer reported two pieces of work as missing because no message about them had reached its inbox — both had landed, were logged with dates and real terms, and one had already passed a full triad | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| An acknowledgement from the system under test was read as evidence of the outcome — the same word, `queued`, covered a genuine pass and a silent 40-minute failure on the same endpoint the same night | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| An overseer authorized an action by bridging a DIFFERENT ruling of the user's onto the question — reasoning correctly from a real quote that was about something else, three relay hops from where it was said | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| An agent, blocked by a safety guard mid-test, offered the user a choice between loosening the guard and accepting weaker proof — presenting a load-bearing protection as one of two equal options | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A fault that repairs itself faster than anyone reports it is invisible to every alarm in the system — two family-facing surfaces cut out roughly twice a day for a MONTH and nobody escalated once | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A relayed approval was acted on as if the work were still outstanding — and the same file had already been written, by the session doing the relaying | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| An investigator noticed that a metric could not possibly detect what it was being asked to detect, WROTE THAT DOWN, and then built a headline claim on it anyway — because the number it produced agreed with the conclusion | Standing grants are read before anything is asked, so a permission already given is never re-requested: the three decisions the earlier plan carried are all answered or dissolved and no step in this plan waits on Nick. Anything genuinely open goes to him as a single plain question with a recommendation, never bundled into a status report. | 0 standing grants; 1a; FOR NICK |
| An investigation's own searches and relays contaminated the evidence it was searching for — 80 of 84 occurrences of the string were manufactured by the act of investigating it | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| Three unrelated lanes in one night each ran an honest check against an intermittent fault and each got a clean answer, because a point-in-time probe is mathematically almost certain to miss a fault that heals itself | One owner per fact and one writer per file. This lane never edits another lane's plan: an unmet cross-lane condition becomes one dated handoff line naming the receiving owner and the proof that would satisfy it, and an unaccepted handoff stays with the overseer. | 1 trip-over protocol; STEP 9; STEP 19 |
| An overseer holding the user's GENUINE first-hand instructions relayed them as authority to four sessions — and one correctly refused, because accuracy and standing are different things and only one of them travels | Security work is click-gated: nothing is hardened, audited or rotated here. Existing outbound and job gates are read and bound, never weakened to make a case pass; anything security-shaped costs one line in the single security queue and the step continues. | 0 security surface; STEP 5; STEP 7; STEP 15 |
| A file that documents its own version history in prose ABOVE its code turns every unanchored search into a lie — three sessions in one hour read the changelog and believed it was the declaration | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A commit hash cited as closing evidence resolved to nothing later — sometimes minutes later — because the citation was checked when it was written and never at the moment it was relied on | Every step declares one evidence state and saves its artefact in the lane's own evidence folder; progress goes to one board card through a path that is itself proved in step 28, and the board's habit of dropping successful updates is fixed and reproduced with a control rather than assumed. | 5 state file; STEP 28 |
| A step's own PROOF COMMAND, not just a claim someone else wrote, over-matched — pointed at the right file this time, it still returned a plausible, close, wrong count | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A check reported PASS five separate times on one feature while the live screen was wrong every time, and the check's own instrument then reported FAIL five separate times on code that was correct — the same fake page lied in both directions | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A deliberate, reviewed, gate-passing commit was pre-empted by an automatic snapshot that bundled the change with unrelated files, destroyed its commit message, and meant the commit-time gate never executed at all | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| A blind checker's whole verdict came back UNVERIFIED because the route into the walled surface it was handed was a remembered ruling, not the measured route | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A scoped restyle rule read correctly, passed its rig and the design QA, and never applied on screen: an inline style set by a frozen script beat it | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A cache-busting parameter placed in the URL hash changed which screen the app believed it was on, so a re-check measured another screen's tokens and reported a false FAIL | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| Three of five blind-check reds were the brief's own narrowing of the pinned design (an accent allow-list shorter than the pin's list, "one line" for a row the pin wraps, an icon measured on an opacity-0 overlay) | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A verification read an eventually-consistent store within seconds of writing it and recorded the stale answer as a product defect | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A test closed ONE of several identical inputs and read the correct unchanged output as a bug | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| A routing or safety filter matched a keyword in a PARAMETER NAME rather than in any content, and refused benign mechanical work three times in series | One owner per fact and one writer per file. This lane never edits another lane's plan: an unmet cross-lane condition becomes one dated handoff line naming the receiving owner and the proof that would satisfy it, and an unaccepted handoff stays with the overseer. | 1 trip-over protocol; STEP 9; STEP 19 |
| Two cooperating passes wrote the same artifact filename and the richer one was silently lost while a grader was reading it | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| A machine owning a whole role went dark, and its peer's CORRECT standby behaviour silently froze 146 scheduled jobs for fourteen hours | An empty or unreadable result is recorded as unknown and never as proof of absence: the switched-off state is Nick's own statement and is re-measured on the Mac mini itself rather than inherited, the harness carries a sabotage control so a green run means something, and a watcher's silence counts only after a deliberately skipped run has been seen to raise its alarm on two different cadences. | the lane's notes file; STEP 1; STEP 2; STEP 22 |
| An abandoned merge blocked every commit in a shared workspace for every session, and nothing detected it | Every proof is runnable today or built by an earlier step of this plan; the acceptance harness is created by step 2 before any step cites it, and it ships with two deliberate-failure controls, one that must turn its case red and one that must not. | 3b; STEP 2 |
| An append to a SYMLINKED path was committed as the unchanged link, so the content change was never staged and a later merge silently discarded it — while every check in the session read the file through the symlink and saw the change present | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| A capture instrument reported an element blank (a sketch box, then menu icons) while every DOM and computed-style probe said visible; three fix rounds were built against the phantom | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A cheap vendor re-saved a 40 KB checker file whole twice, and its own proof reverted it both times for a removed line | Nothing is switched ON until its own proof has passed, and a task that is not on is recorded as not on with the reason named, never assumed to be working. Nothing is switched off by this plan at all: every old job was already off before it started, and that state is re-measured on the machine rather than inherited. | STEP 1; each task's own switch-on; STEP 30 |
| A concurrent lane's publish from `main` landed seconds after a branch lane's publish and took the SAME cache number, so the version said "new" while the served bytes were the old script | One authorized action produces exactly one effect across retry, crash and both machines claiming ownership, proved by three fixtures; an uncertain effect is reconciled before any retry. One writer per file, one owner per fact, one shared run record with its existing locked writer, and no second scheduler, board, ledger or store is created by this plan. | 1b; 3 frozen contracts; STEP 4 |
| A first-paint acceptance band ("now-line between 25% and 42% of the visible box") graded the only correct rendering FAIL, because nothing above the line existed to scroll away at that hour and box height | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A failure path (the sweep's "post a finding to the inbox" step) shipped untested and failed silently the first three times it fired — once on request shape, twice by mis-filing a machine failure as a code regression | A message is delivered only when the destination reads it back: queue acceptance, a heartbeat row and a log line are all recorded as undelivered. Accepted, suppressed, failed and confirmed stay four distinct states, and a heartbeat row proves only that the task ran. | STEP 5; STEP 8; STEP 10 |
| A prose section appended through an unquoted shell heredoc executed the backticks in its own text and pasted 155 lines of a selftest's output into an agent guide, unnoticed for seven hours | The date the data is ABOUT is kept separate from the date it was fetched, on every feed; a cursor advances only on an accepted change; an unreadable source produces unknown with its last known age intact, never an empty result that reads as nothing there. | STEP 6; STEPS 17 to 20; U2 |
| Screenshots taken "signed in" showed the signed-out screen: the server accepted the sign-in but the app in the already-loaded page kept `identity: null`, so every capture graded the wrong screen while the log said sign-in worked | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A checker declared a growing list "settled" after two equal reads 700 ms apart and graded a missing item as a product defect; a second checker read the wrong control entirely and reported five boards "unreachable" that were on screen | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |
| A build gate that insisted on a symlink into a second repository failed every publish after another lane made the file a tracked regular file — both lanes wanted "one reviewable copy" and the gate encoded only one route to it | Every step names a checker on a different model from its builder, and a task closes only when a reviewer who did not build it closes its row. The close is graded by a fresh top-tier reader who built none of it, and the message gate is graded by someone who did not write the service. | 3b; STEP 8; STEP 10; STEP 30 |
| A screen's design-fidelity gate read `mismatched properties: 0 · unmeasured anchors: 0` three times per round across three publish rounds while the live screen disagreed with the approved drawing on sibling ORDER three separate times (toolbar switcher after the Add form at 1280; the two desktop columns transposed; the phone stack's empty card between two populated lists) | N/A: this lane ships no rendered surface. The only thing people look at is the wording of three recurring messages, which carries the section D gate in full: a locked target, a grader who did not build the service, and zero mismatched lines before a step closes. | 2d; STEP 8; STEP 10; STEP 14 |

## 5 · Topology and roles

- OVERSEER-AUTHORITY: Fable, Nick's programme overseer appointment, 2026-09-07. The four approval classes and the data floor are unchanged by anything in this plan.
- Thread layout: one lane root at TOP, one MID builder and one MID independent reader per open step, one CHEAP worker fenced to already-approved business text and to backup fingerprints, and one fresh TOP checker at the close who has built nothing. No nested fan-out; no numeric cap on how many independent steps run at once.
- Tier rule, applied per row in section 3b: TOP oversees and decides, MID executes, CHEAP only where quality is unaffected. THE FENCE IS BY CONTENT, NEVER BY DOCUMENT CLASS — personal, health, family, financial, business-record and unpublished client editorial content never reaches a cheap outside vendor, so steps 8 to 21 are MID or TOP regardless of how mechanical they look. The cheap tier builds exactly four things and nothing else: STEP 2's harness and fixtures, STEP 4's action plumbing, STEP 6's freshness plumbing and STEP 25's coordination timer, none of which reads protected content. It also does two fenced extractions — STEP 16's and STEP 21's — and only after the deterministic pre-check named in §3 has run over that exact text and found nothing protected in it. STEP 3 and STEP 22 are deliberately NOT cheap: extending the register touches the personal health spine and the business spine, and the stale-data half reads personal and business landing places.
- Write contention: one writer per file. The lane root is the only committer for this lane, and commits are scoped to this lane's own paths. The existing runner owner keeps the runner and the shared run record keeps its existing locked writer; another lane's files are never edited from here.
- Board card id: none yet.
- STATE FILE: this plan's SUMMARY and STEPS sections, with per-run evidence in projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/ — the one evidence folder, named here and once at the top of §3b, that every "ARTIFACT SAVED" line in this plan resolves under — and relay lines in projects/ops/life-os/audits/A5/PROGRESS.md. The review ledger that decides DONE is projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/evidence/REVIEW-LEDGER.txt, one row per step, closed by a reviewer who is not that step's builder.
- HEARTBEAT ROW: the lane's own card on the `ai-builds` lane of the agent board, moved a stage each turn and posted through the board path repaired in step 28; until that step closes, the direct card path is used and the gap is stated — no step waits on it. This is the lane's own progress row and is separate from the twenty tasks' heartbeat rows in the shared run record, which are built in step 3.
- MORNING-REPORT LINE: Fable relays one plain line for this lane into Nick's programme thread. Nick's own morning message never carries work items.

| Stage | Overseer | Sub-overseers | Workers |
|---|---|---|---|
| Landing and the shared floor, steps 1 to 7 | 1 — TOP · Anthropic · Claude Fable 5.1 | 0 | 2 builders — MID · Anthropic · Claude Sonnet 5 · se-fixer and CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs; 1 independent reader — MID · Anthropic · Claude Opus 5 · verifier; SCRIPT · none · deterministic code counted separately |
| People-facing tasks, steps 8 to 14 | 1 — TOP · Anthropic · Claude Fable 5.1 | 1 | 2 builders — MID · Anthropic · Claude Sonnet 5 · se-fixer and MID · Anthropic · Claude Opus 5 · se-fixer on the family prompts; 1 independent reader — MID · Anthropic · Claude Opus 5 · verifier; 1 message grader who built none of it — MID · Anthropic · Claude Opus 5 · se-blind-checker |
| Business tasks and data feeds, steps 15 to 21 | 1 — TOP · Anthropic · Claude Fable 5.1 | 1 | 2 builders — MID · Anthropic · Claude Opus 5 · se-fixer on financial content and MID · Anthropic · Claude Sonnet 5 · se-fixer elsewhere; 1 independent reader — MID · Anthropic · Claude Opus 5 · verifier; 1 cheap worker fenced to already-approved business text — CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs |
| The machinery, steps 22 to 27 | 1 — TOP · Anthropic · Claude Fable 5.1 | 0 | 2 builders — MID · Anthropic · Claude Sonnet 5 · se-fixer on steps 22, 23, 24, 26 and 27, which read personal and business records, and CHEAP · Z.ai · GLM 5.3 · cheap-task.mjs on step 25's coordination timer alone, which reads none; 1 independent reader — MID · Anthropic · Claude Opus 5 · verifier, with TOP · OpenAI Codex · GPT-6-Astra reviewing the spend guard |
| Folded-in items and the close, steps 28 to 30 | 1 — TOP · Anthropic · Claude Fable 5.1 | 0 | 1 builder — MID · Anthropic · Claude Opus 5 · se-fixer; 1 independent reader — MID · Anthropic · Claude Sonnet 5 · verifier; 1 fresh checker — MID · Anthropic · Claude Opus 5 · se-blind-checker |

## 6 · Evals

| Capability | Exact check / procedure | Pass |
|---|---|---|
| C1 every task built and proved | Step 30's entry-by-entry read of the rebuild list against the live runner, plus each task's own case in steps 8 to 27, each shown red before green | Each of the twenty tasks is live with its own passing proof, its heartbeat row, its register entry and one recorded unattended firing on its own clock — or held with a named reason, and no more than two are held |
| C2 one effect | Step 4 lifecycle case: retry after timeout, crash between effect and receipt, both machines claiming ownership | Exactly one effect in all three; an uncertain effect reconciled before retry |
| C3 honest age and morning readiness | Steps 6, 8 and 10: unchanged re-read, unreadable source, and both messages against the locked wording | Nothing restamps as fresh; date-of-data stays separate from date-fetched; one message per person per day; zero mismatched lines; zero work items in Nick's |
| C4 delivery proved | Step 5 delivery case with the four states separated | A queue acceptance with no read-back, and a healthy heartbeat row with no read-back, are both recorded as undelivered |
| C5 heartbeats and single landing places | Step 3's heartbeat case, and steps 17 to 20 read back on the one surface each feed lands on | Every task writes a row on every run including a quiet one; each feed's data is found in exactly one place and nowhere else |
| C6 gates respected | Step 7 eligibility case and step 16's four approval refusals | Zero effects in every ineligible case; missing, altered, expired and reused approvals each write nothing |
| C7 the watcher can actually fire, AND REACH SOMEBODY | Step 22: a skipped run on two different cadences, held-back data behind a healthy row, a healthy quiet source, and a read-back of each alarm at the destination its own severity chose | Both skipped runs noticed inside their own windows, named in plain English, and read back at Nick's own channel or the Hub board card — never evidenced from a log; the stale half catches what the heartbeat half cannot; the quiet source raises nothing |
| C8 none-tier tasks cost zero | Step 3 records each task's declared tier in the register; steps 15 and 25 each close on a full day of runs measured against the existing spend record, and every other none-tier task closes the same way | Every none-tier task and every none-tier part of a mixed task records zero tokens across a full day of runs, read from the spend record rather than asserted; the build-coordination timer and the Hub due-work runner are scripts with no model call in them; work dispatched BY a timer is accounted separately from the timer |
| C9 approval delivery is an event, not a clock | Step 22's lost-tap case: grant a test approval, block its delivery, wait; then deliver it | The sweep names the stuck approval within fifteen minutes, says who is waiting and how long, and the alarm clears on delivery; the sweep itself never delivers an approval, and no scheduled job carries an approval to a waiting agent |
| Whole-lane outcome | Step 30's read-only-live outcomes, graded independently by a fresh reader who built none of it | The twenty rows agree between the two graders, with no task's state inferred rather than read, no more than two held, and no task carrying two implementations |

## 7 · THE ONE DECISION LIST FOR NICK

NOTHING ON THIS LIST. None of the four approval classes — money leaving, rotating a credential, irreversible destruction, a message sent as Nick to another human — is reached by any step in this lane, and the 2026-09-09 audit found none. Every item below carries a default and is already solved; nobody waits.

- The hour Chantelle's morning message goes out. DEFAULT: 08:00 Cancun, built and shipped. The question goes to CHANTELLE inside her own existing conversation, never to Nick, and the answer changes one configuration line. §1a row 8 records the hour as an assumed default and NOT CONFIRMED; NOTES.txt beside this file records it as confirmed. Those two disagree, and the build is identical either way.
- The standing schedule for the four security and vault watches. DEFAULT: they join task 15's register. Nick's 2026-09-08 note leaves this to the builder — "builder decides, Nick does not."
- Whether the weekly knowledge consolidation and the mini's crashing phone service belong to this lane at all. DEFAULT: they do NOT — neither is one of the twenty tasks on the rebuild list, so each gets a named owner in the programme plan rather than being absorbed here silently. The carve-out rule requires the name in the same edit.

Not asked, because you already answered:
- Whether scheduled work runs on the mini — yes, 2026-09-07, and it is a full work machine.
- Whether the Hub and the family app are the databases and Monday is out — yes, 2026-09-08 10:30.
- Where the business finance numbers come from — Rizza's weekly report, 2026-09-08, a standing feed needing no per-batch tap.
- Whether your morning message carries work items — no, 2026-09-08; and there is no Updates tab, 2026-09-05.
- Where Chantelle's hormone readings are collected — inside Gracie's own morning message, 2026-09-08.
- The weekly and monthly personal money review, and the engine watchdog going back on — 2026-09-08, "1 good 2 yes".
- Your go on the thirty-step rebuild, and whether to build the Gmail ear. That is programme §7 item 8 and it lives there, quoted, not re-asked from this lane. The Gmail ear itself belongs to the Skippy lane's mailbox-watch step.

## SUMMARY

Draft state, 2026-09-08: nothing has been built yet in this lane, and every scheduled task on both Macs is off by Nick's own hand. What is off is the SCHEDULING; the code is not. Measured on 2026-09-08, projects/ops/skippy-jobs/jobs/ holds 176 job files with named implementations of most of these twenty tasks, and the two task rosters hold entries for the rest. So the work is to repair and extend a named existing file per task, register it with the register and watchdog that already exist, prove it, and switch it back on — never to write a second copy of a job that is already there.

The plan is thirty steps: land the list where the Mac mini reads it first, build the acceptance harness and the shared floor every task stands on, then the tasks themselves in the order Nick was given — Chantelle's message and her reply path, his own morning as one task in three timed stages, the overdue clock, Willow's and Noah's two, the Hub's due work and the permissioned collection, the four standalone feeds, Jasmin's daily check, then the machinery. Each task goes live on its own passing proof shown red before green, writes a heartbeat row through the existing locked writer, carries an entry in the one generated register the existing fleet watchdog reads, has one of its runs deliberately skipped with the alarm seen to fire AND read back where a person opens it, and has fired at least once unattended on the real clock before it closes.

The finish line is one line, not two: every task on the rebuild list live on the Mac mini, except tasks explicitly held with a named reason, of which there may be no more than the two already measured — the receipts chase, waiting on Mae's answer, and the payroll feed, waiting on shared-drive access. A third hold reopens the close.

No step waits on Nick. One thing is genuinely open and is built past rather than waited on: the hour Chantelle's message goes out is the assumed default of 08:00, because the locked contract calls it a proposed default and nothing on the record confirms an hour with her; it changes in one configuration line if she wants another. Two answers are owed by other people and neither holds up the build: Mae on whether her receipts process catches missing receipts, and the shared-drive access the payroll feed needs, which returned no files the last time it was measured.

## STEPS

1. Land the task list and this plan on the main line, and re-measure that the old jobs are off — 40%
   DEFINITION OF DONE: the list is on the main line through a scoped pull request, the file's SHA-256 is identical on both machines with both checksums machine-written, and the Mac mini's loaded-job count is recorded as a measurement with its timestamp.
   PROOF: `git ls-tree origin/main --name-only projects/ops/life-os/REGROUP-2026-09-08/lanes/` — re-run 2026-09-09, exit 0, both named files listed. Held at 40%: the two machine checksums and the mini's loaded-job count were not taken.
2. Build the acceptance harness and its two deliberate-failure controls — 70%
   DEFINITION OF DONE: the five floor cases pass, a case name that was never built comes back as an error rather than a pass, and the sabotage control comes back red, then green again on reversal.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case heartbeat --case lifecycle --case delivery --case source-time --case eligibility` — re-run 2026-09-09, exit 0, five PASS lines; `--case does-not-exist` exits 1 as an error. Held at 70%: the sabotage control was deliberately not re-run, because breaking live production code to demonstrate a control is not an audit action.
3. The heartbeat contract, and the watcher that reads it — 20%
   DEFINITION OF DONE: a task that ran, a task that correctly did nothing and a task that could not read each write a different row through the existing locked writer; the existing generated register is extended at its source and read back by the existing fleet watchdog; a row that never appears raises a named alarm that is read back at its own destination and clears itself; and the job runner is measured loaded and alive on the Mac mini with one unattended row to show it.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case heartbeat` — re-run 2026-09-09, exit 0, `heartbeat: PASS`. That is the fixture half only. One of this step's seven required items is complete on its own review-ledger row; the register still carries `"generated_at": "2026-09-07T09:17:13"` and none of these tasks; and the runner is DISABLED on both Macs, so the last clause of the done-line is measured FALSE rather than merely unmeasured.
4. One authorized action produces exactly one effect — 80%
   DEFINITION OF DONE: retry, crash and two-machine cases each produce exactly one effect, with uncertainty reconciled before any retry.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case lifecycle` — re-run 2026-09-09, exit 0, `lifecycle: PASS`. Capped at 80: no independent checker has signed a dated VERIFIED line.
5. A message counts as delivered only on destination read-back — 80%
   DEFINITION OF DONE: accepted, suppressed, failed and confirmed stay four distinct states, and neither a queue acceptance nor a heartbeat row ever closes a delivery.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case delivery` — re-run 2026-09-09, exit 0, `delivery: PASS`. Capped at 80: no independent checker has signed a dated VERIFIED line.
6. Old data never looks new — 80%
   DEFINITION OF DONE: an unchanged re-read does not restamp, an unreadable source produces unknown rather than empty, and the date data is about stays separate from the date it was fetched.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case source-time` — re-run 2026-09-09, exit 0, `source-time: PASS`. Capped at 80: no independent checker has signed a dated VERIFIED line.
7. Cancelled, expired and wrong-person work produces nothing — 80%
   DEFINITION OF DONE: every ineligible case produces zero effects with a recorded reason, and no existing gate was weakened to get there.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case eligibility` — re-run 2026-09-09, exit 0, `eligibility: PASS`. One clause is unmeasured: that no existing gate was weakened to reach the pass. Loosening a check moves the danger to where nothing is looking, so that clause is settled by reading the diff, never by the green.
8. Chantelle's morning message, live — 0%
   DEFINITION OF DONE: one message a day with a real provider receipt, zero mismatched lines against the locked wording, and a deliberately skipped run raising a named alarm that clears.
9. Chantelle's replies actually completing a task — 0%
   DEFINITION OF DONE: a test task moves end to end through the real conversation and is read back, the same reply repeated moves nothing twice, and a stalled listener marker raises a named alarm.
10. Nick's morning message, live, carrying no work items — 0%
   DEFINITION OF DONE: one message a day read back at both destinations, zero mismatched lines, seeded work items appearing nowhere, and a skipped run noticed.
11. Nick's body data collection, live — the ring pull — 0%
   DEFINITION OF DONE: a reading carrying yesterday's date read back from the health record, an unavailable source keeping the old value and marking it stale, and a skipped pass noticed.
12. Overdue becomes today, live — 0%
   DEFINITION OF DONE: an overdue task carries today's date afterwards, a row in the store's own someday array is untouched, a collapsed read refuses to write and says why against its own prior read, the pre-run due dates are saved with a proved way back before the first live run, and a skipped run is noticed.
13. The kids' calendar push, live — 0%
   DEFINITION OF DONE: a known event read back on the correct child's day, an ambiguous one on no child, an unreadable calendar leaving yesterday visibly dated, and a skipped run noticed.
14. The kids' check-in prompts, live — 0%
   DEFINITION OF DONE: the prompt read back on the intended parent route, a closed topic staying closed across two runs, zero mismatched lines, and a skipped run noticed.
15. The Hub due-work runner, live — 0%
   DEFINITION OF DONE: a real Hub row moving from due to done with the effect visible in the Hub, a cancelled one producing nothing, and a skipped run noticed inside ten minutes.
16. Business data collection, with Nick's permission each time — 0%
   DEFINITION OF DONE: an approval record joined to the exact stored batch, and missing, altered, expired and reused approvals each writing nothing.
17. The Era bank feed into the family app's finances — 0%
   DEFINITION OF DONE: the app's own finances screen reading back the "as of" date this run wrote, a failed fetch keeping the older snapshot with its own date, nothing landing anywhere else, and a skipped run noticed.
18. Rizza's weekly finance report into the Hub — 0%
   DEFINITION OF DONE: the Hub's finance view showing the new week under the week's own end date, a week that has not landed writing nothing, the same week appended twice changing nothing, and a skipped run noticed.
19. Payroll hours and the payroll adjustments sheet — 0%
   DEFINITION OF DONE: the Hub's hours and payroll week read back under the week's own end date, a re-run writing nothing, and the shared-drive access state recorded from a read this step performed rather than from memory.
20. The team standup recording into the Hub — 0%
   DEFINITION OF DONE: the transcript readable in the Hub under the meeting's own date and read back BEFORE any delete, the only deleted file being the intermediate video inside the task's own working directory with the shared drive's recordings folder byte-identical before and after, a second pass adding nothing, and a long capture not blocking the tick.
21. Jasmin's daily slot check, live — 0%
   DEFINITION OF DONE: a valid slot reaching the review queue exactly once, a cancelled one producing nothing, nothing publishing, and a skipped run noticed.
22. Complete the watcher: stale data, the whole register, two cadences — 0%
   DEFINITION OF DONE: skipped runs noticed on two different cadences and each alarm read back at the destination its own severity chose, held-back data caught behind a healthy row, a healthy quiet source raising nothing, and no task on the list left unwatched, with any held step listed as held with its reason.
23. The backup check, live — 0%
   DEFINITION OF DONE: a restored sample's fingerprint matching the original, a deliberately corrupted backup failing the check, and no secret value in the result.
24. The spend and quota guard, live — 0%
   DEFINITION OF DONE: a quota-killed run becoming resumable exactly once, an ordinary error not treated as a quota problem, and an unknown allowance staying unknown.
25. The build-coordination timer, live — 0%
   DEFINITION OF DONE: an approved next step progressing on the board, a closed step staying closed, and abandoned work picked up exactly once.
26. Larry's weekly upkeep and continuity review, live — 0%
   DEFINITION OF DONE: a deliberately planted problem found, an already-settled item staying quiet, the weekly skill grader's scores folded into this same review with no separate schedule row left for it, and the review item read back on the Hub.
27. Benito's monthly outside-world review, live — 0%
   DEFINITION OF DONE: the monthly item read back on the Hub, that week's light review deliberately standing down, and the watcher raising nothing for the stand-down.
28. Make the board keep an update that reports success — 40%
   DEFINITION OF DONE: the previously dropped update read back from the board on this lane's own lane after the fix, with a control update proving it was the board and not the session.
   PROOF: `node projects/ops/skippy-jobs/lib/board-report.mjs --read --lane ai-builds` — re-run 2026-09-09, exit 0, and the board answers: `board-report --read: 33 of 255 total tasks on lane "ai-builds"`. Held at 40% — report-only: reading the lane is not the same as reading back the specific success update after the fix with its control update.
29. Ask Mae whether her receipts process covers missing receipts — 20%
   DEFINITION OF DONE: the question sent by Skippy under his own name, her answer text and its date both recorded, a placeholder value failing rather than passing, and the Sunday receipts task built by repairing its existing roster entry, or dropped, on that answer alone.
   PROOF: THE PROOF AS WRITTEN CANNOT PASS AND MUST BE REPOINTED FIRST. Re-run 2026-09-09: exit 1 with `KeyError: 'receipts_missing_covered'` — that top-level field has never existed in projects/ops/life-os/audits/A5/BUILD-PACKAGE/service-contracts.json, whose real top-level keys are owner, purpose, as_of, timezone, runtime_policy, services and retirement_proofs; the only matching name in the file is `receipts`. The drafted question exists in the evidence folder and has not been sent. Sending it as Skippy under his own name is inside the standing grant and is not one of the four approval classes.
30. Every task live on its own proof, checked by a reader who built none of it — 0%
   DEFINITION OF DONE: one row per task on the rebuild list, each either live with its four receipts — proof, heartbeat row, register entry, unattended firing — or held with its reason, no more than two held, no task carrying two implementations, agreed row for row by a fresh checker who built none of it.
   PROOF: `node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --read-only-live outcomes` — re-run 2026-09-09, exit 1, and the harness says so itself: `--read-only-live outcomes is not implemented yet`. NOT STARTED, which is correct sequencing for the close — but this mode is also the one command that would run all thirty proofs in a single pass, so it is worth more than its position in the order suggests.

## NEXT

The full audited state is one list, written once, beside this file: projects/ops/life-os/REGROUP-2026-09-08/plans/SCHEDULED/AUDIT-LIST-2026-09-09.txt — PROVEN TONIGHT, NOT PROVEN, and fifteen GAPS each with its owning task and the one command that would prove it. The order below is that list's conclusion; no new build step is created here.

- FIRST, AND IT IS NOT A BUILD: switch the job runner back on. `com.skippy.jobs` reads disabled at the launchd level on the Mac Studio AND on the Mac mini, measured on each machine 2026-09-09, and appears in neither machine's loaded list. Every step from 8 to 27 carries cross-cutting requirement (e) — it must fire once unattended on the real clock — and not one can satisfy it until this is reversed. Prove it with `launchctl list | grep com.skippy.jobs` returning a row on the mini.
- SECOND, A CONTRADICTION TO SETTLE BEFORE TRUSTING ANY HEARTBEAT: a runner is alive by a route this plan does not name — projects/ops/skippy-jobs/state/runner-boot.json records a boot at 2026-09-09T21:44:26Z with a live process and 212 job hashes, while the launchd agent that should start it is disabled on both machines. Name what is starting it; until then "the runner is up" and "a task will fire on its own clock" are two different claims and only one is evidence.
- THIRD: repair the watcher before registering anything with it. It is disabled on the Studio, its last run on the mini exited 1, and its register carries `"generated_at": "2026-09-07T09:17:13"` — generated before this work, holding none of these tasks. It is generated, never hand-edited, so a task is registered by adding it to the right source roster and regenerating.
- THEN the two proofs that can never pass as written, because a step cannot close against a broken check: STEP 29's reads a field that has never existed in service-contracts.json, and STEP 30's names a mode the harness itself reports as unimplemented. Repoint one, build the other.
- THEN the twenty task steps in the order Nick set, each adding its own case to the harness and shown RED before green, exactly as §3b already requires. Steps 8, 10 and 12 are the three he notices first.
- No question goes to Nick from this lane. Two go to other people — Mae on missing receipts, and the owner of the shared-drive access the payroll feed needs — and neither holds up a step. One goes to Chantelle and holds up nothing either: whether 08:00 is the right hour for her morning message, which is built to 08:00 regardless and changes in one configuration line.

2026-09-09 — from the WORKSHOP lane: the weekly self-check and Larry's weekly review are yours, and one measured fact changes the job: com.skippy.jobs — the scheduled job RUNNER itself — is DISABLED at the launchd level on BOTH Macs (launchctl print-disabled lists it on the Studio and on the mini). It is switched off, not missing, so confirm that before rebuilding anything. The identical fault silently stopped the auto-push job on both machines until 2026-09-09. Thirteen jobs are disabled on the Studio and seven on the mini.

2026-09-09, CONFIRMED BY THIS AUDIT, independently and on both machines: that fact is correct and still true. `launchctl print-disabled user/$(id -u)` reads `"com.skippy.jobs" => disabled` on the Studio and, over ssh, on the mini; the label is in neither machine's `launchctl list`. One half of the same note has since changed and is corrected here rather than left to mislead: the auto-push job is now ENABLED on both Macs, so that specific stoppage is over. The pull side is not clean — `com.skippy.auto-pull` last exited 1 on the Studio, and its autostash reverted this audit's own writes to this file three times, which is why the lane's record must be committed to main at every stopping point rather than left in the working tree.

## POSTMORTEM

Written at audit time, not at the close, because the gap between what the 2026-09-08 plan recorded and what tonight's re-run proved is itself the lesson.

WHAT THE PLAN CLAIMED VERSUS WHAT THE RE-RUN PROVED. The step record said 0% on all thirty steps, and that was wrong in two directions at once. It understated six steps: the harness and the five floor cases were built and green, and nothing in the lane's own record said so, because the step record was written before the build and never revisited. And it hid two dead proofs — STEP 29's reads a field that has never existed in the contract file, STEP 30's names a harness mode that reports itself unimplemented. A proof that cannot pass is worse than a missing proof, because a step can be worked to perfection and still never close, and nobody finds out why until someone runs it. Both were found by RUNNING all thirty rather than reading them.

WHAT WAS CONFUSED. Three separate things were being read as one: the code existing, the check existing, and the task being switched on. §3b says this clearly and the record still drifted, because "switched off is not the same as absent" is easy to write and easy to stop applying. Tonight all three were measured separately: 181 job files exist, five of twenty-five checks exist, and zero tasks can fire because the runner is disabled on both machines.

WHAT TO KEEP. Re-running every proof cost one pass, moved six steps off zero, killed two proofs that would each have wasted a build, and turned one recorded gap — the file-sync push — from open to closed on measurement alone. Measuring the machine rather than reading the note produced every finding here that mattered.

THE OPERATIONAL FAILURE THIS AUDIT HIT, with its cost. This shared checkout's auto-pull reverted the audit's writes to this very file three times while the audit was running; two full re-applications were lost. Only the new untracked audit list survived, because autostash does not discard untracked files. So a lane's record is not saved until it is committed to the main line by pathspec, and RULE 20 is a working instruction rather than a policy sentence. The plan checker also FAILS for a real, pre-existing reason unrelated to the audit: §1b names two plan files that exist nowhere on disk. The fix keeps both subprojects and both named owners and replaces only the dead path with a placeholder — deleting either row would delete a capability and its owner.

WHAT WOULD HAVE CAUGHT IT EARLIER. One command that runs every step's DONE-PROOF and prints one line per step. Thirty proofs were run by hand tonight in four batches; STEP 30's unimplemented `--read-only-live outcomes` is exactly that command, which means this lane's own close is also its missing instrument.

JASMIN-CAPTUS STEP 7 closed 2026-09-10 — projects/ops/skippy-jobs/jobs/captus-tracker-refresh.mjs runs once by hand and is registered, not scheduled. It wants a Monday 07:00 Cancun slot when the rebuild reaches it: on a Monday it also composes the weekly report and posts it as one comment on the week's report card, keyed to the week so a second run cannot add a second. Its proof line is: tracker: published <n> · numbers written <n> of <n> · weekly comment 1 · slack paths 0.
JASMIN-CAPTUS STEP 5 closed 2026-09-10 — projects/ops/skippy-jobs/jobs/captus-voice-feedback.mjs runs by hand and is registered, not scheduled. It wants a nightly slot. It reads the client's saved edits off the Captus cards and writes one dated row per changed sentence into that author's own voice file, then commits it. Run it with SKIPPY_DRY_RUN=1 to see what it would write without writing anything. One caveat for whoever schedules it: it only sees an edit while the card carrying it still exists, so it must run before anything clears those cards.

Current state PROGRESS.txt

PROGRESS 2026-09-08 ~09:40 EST — LANE 4 SCHEDULED TASKS plan draft: read the lane split, the progress-screen standard, SCHEDULED.json (16 steps, 190-job inventory, nine homeless timers, five open decisions), the A5 PLAN and build package, the plan doctrine and the A7 model plan. Step map drafted: 21 steps, all 16 earlier steps carried. Writing the plan file now.
PROGRESS 2026-09-08 ~10:05 EST — DONE: steps 21, checker PASS. Plan draft written (PLAN.proposed.txt), machine check recorded (CHECK.txt), Hub render contract written (STEPS.json). All 16 earlier A5 steps carried by name into 21; 189 of 189 failure-registry entries covered with zero weak matches; three decisions for Nick isolated as steps 2, 13 and 15, none of which blocks the build.
PROGRESS 2026-09-08 ~10:35 EST — Starting revision under Nick's 10:30 rulings. Read the current SCHEDULED-REBUILD-LIST (19 tasks), PLAN.proposed.txt, STEPS.json, CHECK.txt. Next: read A5 evidence for the standalone data feeds.
PROGRESS 2026-09-08 ~10:55 EST — Evidence read for the feeds revision: Era is the daily ~07:28 bank-feed pull (kv era-live + raw transaction files) read by the family app's finances screen at /api/era-finance and nowhere else; Rizza's weekly P&L is the Fri 09:00 + Sat 09:00 catch-up landed-file gate into the business spine (A5 dispositions rows 182/339, business-feed-watchdog header); payroll hours (Time Doctor + Rizza's payroll sheet) Tue/Thu/Sat; standup capture 4x/day Thu. Monday-sourced feeds (task boards, comments, vendors, NPS, repeat-order tracker) excluded per Nick 10:30. Writing the revised list now.
PROGRESS 2026-09-08 ~11:20 EST — Rebuild list revised in place: 21 tasks (was 19), the two Monday sync clocks removed with the household lists now family-app-only, a new THE DATA FEEDS group (Oura cross-referenced, Era bank feeds, Rizza's weekly report, payroll hours, standup recording), Jasmin kept as its own daily task, a heartbeat line on every task and feed, the watchdog rewritten to alarm on missing heartbeat AND stale data with a skipped-run proof, and the closing paragraph corrected to the jobs being OFF. Plan revised to the start-over shape: 30 steps in Nick's build order, no shadow run, no retirement gate, heartbeats/watchdog cross-cutting, no open decision for Nick. Checker re-run: red first (2 rows where the checker was the builder), fixed, then PASS. CHECK.txt and STEPS.json updated. Committing now.
DONE
PROGRESS 2026-09-08 ~15:40 EST — Cold-read revision started. Read COLD-READ-2026-09-08.txt (16 blocking + 11 minor), PLAN.proposed.txt, STEPS.json, EXECUTOR-ROSTER.txt, the rebuild list, the 2026-09-08 handoff rulings and the plan doctrine. No NOTES-FROM-NICK.txt for this lane. Measured the repository claims the cold read makes rather than believing them: 176 job files in projects/ops/skippy-jobs/jobs/, the twelve named implementations all present, roster-liveness.json holding 36 generated entries, the existing fleet watchdog, the launchd agent + runner SCHEDULE as the real switch-on, the family app's own someday array and row-loss floor, the Era producer (refresh-era-finance / morning-refresh-era-gmail-personal) and Rizza's weekly (refresh-hs-dashboard-finance, Fri+Sat 09:00). Applying every blocking finding and the wording minors now.
PROGRESS 2026-09-08 ~16:00 EST — All 20 blocking findings and all 11 minor findings applied in place. The framing correction (findings 1 and 2) reaches §0, §1, §1a, the SUMMARY, FOR NICK and every task step, each of which now names the existing file or roster entry it extends — or, for Jasmin's slot check alone, records the search that found nothing. Named for the first time: the one evidence folder and the review ledger (created, 30 rows OPEN), the switch-on mechanism, the alarm's readers and their read-back, the register and that it is generated rather than hand-edited, Nick's replacement message source and destination with both wording changes recorded, the test recipient, the health record, the family app's own someday array and prior-row-count rule, the deleted video's directory, the board lane and token, and Mae's sender. One done-line replaces the two that contradicted each other; STEP 22's gate no longer locks out five steps; STEP 25 no longer waits on STEP 28; six copied Regret Check rows rewritten to answer their own failure. Checker re-run on a /tmp .md copy: PASS, and --failures returns nothing. Writing STEPS.json and CHECK.txt now.
PROGRESS 2026-09-08 ~16:20 EST — STEPS.json rewritten to match: steps 3 and 22 off the cheap bench onto MID Sonnet with an Opus reader, four proofs corrected, the carried_from field removed from all thirty steps (that mapping now lives in NOTES.txt under Nick's plan-holds-only-work-to-do ruling), and a new "extends" field naming the existing file or roster entry each step repairs — with STEP 21 recording a measured NONE. NOTES.txt carries the measured inventory, the two superseded lines of the locked message contract with their checksum, and the two amendments owed to the rebuild list, which is a different file this commit does not touch. CHECK.txt carries the dated revision note, all 31 findings and how each was fixed, the five red runs before green, and the final checksums. Checker PASS, --failures empty. Committing the SCHEDULED folder now.
DONE
PROGRESS 2026-09-08 ~19:05 EST — Nick's 18:50 review rulings started. Read NOTES-FROM-NICK.md (all 2026-09-08 sections including the 18:50 review and the 18:55 Rizza-day correction), the 21-task rebuild list, SCHEDULED.json (190 jobs), the plan, NOTES and the lane summary. Confirmed Nick's 55 coverage jobs mechanically against the inventory: 27 = every job in families S01/S02/S04 plus the two remaining retire rows outside them (coach-source-silence, x-digest); 23 = every job in "none - outside S01-S17" (the preserved host services); 5 = the END_PHASE security watches. Live measurement taken: launchctl on the Studio, ssh to nicks-mac-mini.local, launchctl print-disabled on both, and the three Claude cloud task registrations read from ~/.claude/scheduled-tasks. Writing the revised list now.
PROGRESS 2026-09-08 ~14:40 EST (machine clock; Nick's review is timestamped 18:50 in his own notes) — PART A DONE. Rebuild list revised in place: tasks 1 and 2 merged into one "Nick's morning" with three timed stages (06:30 ring pull, 07:36 message, 12:45 repair pass); the kids named as Willow and Noah throughout and every other "For" line re-checked, which also caught Nick's morning still naming a Monday board and an Updates card in its Reads/Writes — both replaced by the family app's own list and #nicks-life; Hub due-work runner moved to every 15 minutes with a zero-token line; business data collection made one weekly run riding with the Rizza check (Thursday 17:00, Friday 12:00 re-check, per Nick's 18:55 correction of his own Monday ruling) plus on demand, with a strengthened per-batch approval line; Rizza's own task moved off Friday/Saturday onto Thursday/Friday; build-coordination timer moved to every 5 minutes with "zero tokens; if this ever needs a model it is a bug", and the same zero-token line added to all eleven none-tier tasks; the lost-tap sweep written into the watchdog as its third half, with a sentence in the opening that approval delivery is an event and not a clock; renumbered to twenty tasks. Also discharged the two amendments NOTES.txt said were owed to this file: the weekly skill grader inside Larry's review, and the switch-off attribution. PART B DONE next.
PROGRESS 2026-09-08 ~14:55 EST — PARTS B AND C DONE. Coverage file written: SCHEDULED-COVERAGE-2026-09-08.txt, one row for each of the 55 old jobs no new task rebuilds, with the 27/23/5 split reproduced mechanically from SCHEDULED.json rather than trusted. Every "is it running" answer is a live measurement taken at 14:36:25 EST: launchctl list and launchctl print-disabled on the Studio, both over ssh on the mini, the three cloud task registrations read from their own files, and the approval journal read for today. Verdicts, counted from the file itself rather than estimated: 55 rows numbered 1 to 55 with no gaps and every row carrying a verdict — 25 COVERED, 18 COVERED-BUT-OFF, 12 NOT COVERED. (A first version of this line said 20/26/9; that was written from memory before the file was counted, and is corrected here.) Five things the plan did not already know: there is no Gmail listener anywhere (two ears exist, not three); nothing records an approval tap reaching its waiting agent, though a card was delivered and tapped today with the runner down; seven of the twenty-three host services are down and two of those are failing rather than parked (the mini's phone service exits 78, its agent-liveness check exits 1); the file-sync push is disabled on both Macs; and all four security watches are off inside the runner. The file ends with the three lists Nick asked for — safe to leave off, must be turned back on now with one command each, and eight things not covered that need his decision. Plan folded: STEPS 1, 3, 10, 11, 13, 14, 15, 16, 18, 22, 25 and 30 changed, contracts C8 (none-tier costs a measured zero) and C9 (approval delivery is an event, never a clock) added with their own eval rows, task count changed to twenty in thirteen places, STEPS.json rewritten to match. Checker red first — it caught STEP 25's cheap builder against the word "token" in "zero tokens", which is its credential keyword; the requirement was kept and the ambiguous word dropped — then PASS, with --failures empty. Committing and pushing now.
PROGRESS 2026-09-08 ~15:05 EST — Pushed as bb30d89bc on life-os/programme. The direct push was rejected (remote had moved) and this shared checkout is carrying 2380 uncommitted files belonging to other lanes, so `pull --rebase` was refused and autostash would have put all of that at risk. Pushed instead through a temporary detached worktree at the remote tip, cherry-picking the one commit: this working tree was never touched, no stash was created (110 before, 110 after), and the only status differences afterwards are the SKIPPY and VOICE lanes' own live edits during the window. The local branch keeps its own copy of the commit and will be dropped as a duplicate patch on the next rebase.
DONE
PROGRESS 2026-09-09 ~18:10 EST — AUDIT-ONLY REVISION, and it DISCHARGES the independent read the line below still owed. All thirty steps' own DONE-PROOFs re-run once by a reader who built none of this: 8 passed, 22 did not, 0 machines unreached (the mini answered over ssh). The record was stale in the lane's favour — six steps were green and sitting at 0%; percents are now 40/70/20/80/80/80/80 for steps 1-7, 40 for 28, 20 for 29, 0 for the rest. Two proofs CANNOT PASS as written and are plan defects, not build defects: STEP 29 reads a field that has never existed in service-contracts.json, STEP 30 names a harness mode that reports itself unimplemented. Twenty task cases return "unknown" because the harness holds only the five floor cases, which is what §3b says happens at this point. THE BLOCKING FACT, measured on both machines: com.skippy.jobs is disabled at the launchd level on the Studio AND the mini and is in neither loaded list, so requirement (e) is unsatisfiable for every step until reversed; a runner is nevertheless alive tonight by an unnamed route, which is carried as a gap rather than resolved by guess. One recorded gap closed on measurement alone — the file-sync push is now enabled on both Macs. Written: AUDIT-LIST-2026-09-09.txt (the one list, 15 gaps), the plan revised in place status-only with all thirty steps intact, STEPS.json percents, a CHECK record, and a handoff prompt telling the running agent NOT to restart from step 1. check-no-scaffolding PASS on the plan and the audit list; check_plan.py FAIL (1) on two non-existent plan paths in §1b — pre-existing, fixed by placeholder without deleting either subproject or owner, and the checker still repeating it is UNRESOLVED and left measured rather than claimed. Four of this audit's own edits were reverted mid-session by this checkout's auto-pull autostash and had to be re-applied: nothing is saved here until it is committed to main by pathspec. Nothing committed by this audit.
PROGRESS 2026-09-08 ~15:15 EST — SELF-CHECK AFTER THE UNREVIEWED-BUILD FLAG. No independent reader graded this revision; the session prompt forbids dispatching one, so the check was run mechanically instead and its result is recorded here rather than claimed. Counted from the files themselves: the coverage file holds exactly 55 rows numbered 1 to 55 with no gaps and no duplicates, every row carries a verdict, and the tally is 25 COVERED / 18 COVERED-BUT-OFF / 12 NOT COVERED — which corrected the 20/26/9 figures the earlier progress line and the report to Nick both carried from memory. The rebuild list holds exactly twenty task headings, numbered 1 to 20 in sequence. Both files' SHA-256 on this machine match what is on origin/life-os/programme. The plan checker was re-run to PASS with --failures empty. STILL OWED: a fresh reader who built none of this, grading the revised list and the coverage file against Nick's seven rulings. Nothing here is a substitute for that.

2026-09-09T23:39:36Z - Programme planner re-ran both gates on the audit revision: PASS; fingerprint e69a219f35ddb59c84f89354c29f8b7a917aa41f354833710e6d0712ee0b44fe; committed to main by pathspec. Hand-off to the running agent waits for Nick.

2026-09-10T00:45Z — FROM THE HUB LANE (a dated handoff, information not an assignment): three runner rows the Hub's finished steps depend on, for the rebuild list — hub-conversation-send (every 2 minutes: carries a reply Nick sent from the Hub Inbox into Slack or Gmail; without it an approved reply sits until run by hand), hub-upkeep-collapse (hourly at :20: keeps Larry's upkeep notices at one card per cause), todo-bump-overdue (00:05 and 07:05 Cancún: moves overdue tasks on the Hub board and the household lists to today). All three exist in projects/ops/skippy-jobs/runner.mjs today. The Mac mini's checkout is level with the cloud main as of 2026-09-10T00:40Z; the runner stays off per Nick's 2026-09-08 ruling until this lane turns it back on.
2026-09-10T01:40Z — FROM THE HUB LANE (handoff, information not an assignment): a fourth runner row for the rebuild list — hub-conversation-read-sweep (every 5 minutes: hides, for Nick, any Slack row in his Inbox that his own Slack account has already read, or that sits in a channel his account is not a member of; reversible through the Inbox's own Undo). File: projects/ops/skippy-jobs/jobs/hub-conversation-read-sweep.mjs; it needs SLACK_USER_TOKEN in skippy-app/.env on the machine that runs it (present on the Studio and read through lib/slack-read-state.mjs).

2026-09-10T01:22:26Z - HANDED OFF to the running agent: Nick ruled the machine map (one home per always-on service; runner on the mini only) and approved the audit hand-off, 2026-09-09. The map is G0 in AUDIT-LIST-2026-09-09.txt.

2026-09-10T01:29:05Z - Nick, 2026-09-09: one hand-off per machine, neither touching the other. The mini keeps AUDIT-LIST + HANDOFF-PROMPT-FOR-BUILDER (fenced to the mini); the Studio gets STUDIO-LIST-2026-09-09.txt + HANDOFF-PROMPT-FOR-STUDIO.txt (fenced to the Studio); the one signal between them is the ANSWERING line in this file.
2026-09-10T13:22:14Z - STUDIO KEEPS PROOF: launchctl list | grep -E "slack-listener|wa-watcher|business-narrative-bridge|deploy-runner|auto-pull|autopush|actions.runner" - output: [- 0 com.skippy.autopush] [974 0 com.skippy.deploy-runner] [- 1 com.skippy.auto-pull] [82876 0 com.skippy.slack-listener] [987 0 com.skippy.business-narrative-bridge] [56041 0 com.skippy.wa-watcher] [981 0 actions.runner.nick-deck-deck-business.nicks-mac-studio] - note: com.skippy.auto-pull exit 1, all others 0
2026-09-10T13:22:30Z - STUDIO S1: launchctl print-disabled user/$(id -u) | grep com.skippy.jobs - output: "com.skippy.jobs" => disabled | launchctl list | grep com.skippy.jobs - output: (empty)
2026-09-10T13:22:50Z - STUDIO S2: launchctl bootout gui/$(id -u)/com.skippy.transcribe; launchctl disable gui/$(id -u)/com.skippy.transcribe; launchctl list | grep com.skippy.transcribe - output: (empty) | launchctl print-disabled user/$(id -u) | grep com.skippy.transcribe - output: "com.skippy.transcribe" => disabled
2026-09-10T13:23:15Z - STUDIO S3: queue status (ls -R projects/ops/cheap-loop/queue) - output: queue directories exist but are empty | launchctl bootout gui/$(id -u)/com.skippy.cheap-loop; launchctl disable gui/$(id -u)/com.skippy.cheap-loop; launchctl list | grep com.skippy.cheap-loop - output: (empty) | launchctl print-disabled user/$(id -u) | grep com.skippy.cheap-loop - output: "com.skippy.cheap-loop" => disabled
2026-09-10T13:24:40Z - STUDIO S4: launchctl kickstart -k gui/$(id -u)/com.skippy.mac-server; sleep 10; launchctl list | grep com.skippy.mac-server - output: 52111 -15 com.skippy.mac-server; plist log path: /Users/nickdeck/Documents/Claude 2.0/projects/personal/skippy-app/mac-server.launchd.out.log; first line: 🧠 HEALTH SPINE loaded — 183,564 chars from /Users/nickdeck/Documents/Claude 2.0/projects/personal/health/spine/projections/injection-context-core.md; after 60s more: 52111 -15 com.skippy.mac-server (exit -15 persists)
2026-09-10T13:25:45Z - STUDIO git commit and push: commit ac0118fcab created with progress S0-S5; pull --rebase origin main failed: unmerged files in projects/ops/skippy-jobs/lib/dispatch-contract.mjs; recording failure and continuing per lane instructions; overseer will land this
2026-09-10T13:26:30Z - PUSH FAILED: git push origin HEAD:main rejected (remote ahead); pull --rebase origin main encountered merge conflict in projects/ops/skippy-jobs/lib/dispatch-contract.mjs; conflict not mine (file not touched by studio agent); rebase aborted per instructions; overseer will resolve and push
2026-09-10T13:35Z - STUDIO OVERSEER (session claude-2-0-c0 [0261ec], on the Studio) RE-CHECKED the helper's six lines above first-hand: launchctl list shows com.skippy.transcribe and com.skippy.cheap-loop gone and print-disabled reads disabled for both and for com.skippy.jobs; com.skippy.mobile still loaded (pid 967) as S5 requires; com.skippy.mac-server row reads "52111 -15" — the -15 is the exit status of the copy that kickstart -k killed, the pid is the new server (ps etime 04:03 at the check), and http://127.0.0.1:3000/ answers HTTP 401 (its sign-in wall), so S4 PROOF is read as MET: running and answering, no non-zero exit after the restart. KEEPS row not 0: com.skippy.auto-pull exits 1 every run (its log /Users/nickdeck/.skippy-autopush/auto-pull.err ends in MODULE_NOT_FOUND) — recorded, not changed, the list says record only; consequence: nothing carries this Mac's commits to the cloud copy on its own. The helper's two local commits (4f4e876124, ec195c5e11) could not push because the shared checkout is 9 commits ahead and 13 behind origin/main with other lanes' work in flight, so their lines were carried to origin/main by the overseer through a detached scratch worktree (this commit). S5 WAITING ON THE MINI: a watch checks origin/main every fifteen minutes for a line beginning "PHONE SERVICE ON THE MINI: ANSWERING"; nothing changes on the Studio's phone service until it appears. S6: every item above is recorded with its command and literal output.

2026-09-10T02:31Z — HANDOFF FROM THE HUB LANE (STEP 16): one more runner row for the jobs machine — hub-slack-user-capture (every 5 minutes, before hub-conversation-capture): reads Nick's own Slack account through lib/slack-read-state.mjs and writes his direct messages, group messages, the channels the Sources screen allows, and his own replies into the inbound-from-humans seam; hub-conversation-capture --once then stages them and hub-conversation-read-sweep marks what he has already read in Slack. All three run from the workspace root on the jobs machine; the Slack user token comes from the vault (slack-user-token-main), never from the row.
2026-09-10T14:50Z - STUDIO S5 DONE ON NICK'S WORD, NOT ON THE MINI'S LINE. Nick, 2026-09-10, in the Studio overseer's chat: "im saying you an turn it off and close out with the assumption that it has its side covered" (after "its active now assume youre good to act itll be built by morning"). The overseer read that back as switch-it-off-now and he confirmed, so the list's "never unload on any other evidence" rule was overridden by its author. DO: launchctl bootout gui/501/com.skippy.mobile (exit 0); launchctl disable gui/501/com.skippy.mobile (exit 0). PROOF: launchctl list | grep com.skippy.mobile returns nothing; launchctl print-disabled user/501 | grep com.skippy.mobile reads "com.skippy.mobile" => disabled; the plist stays at ~/Library/LaunchAgents/com.skippy.mobile.plist (1053 bytes, untouched). The ANSWERING line from the mini had NOT appeared on origin/main at the time (checked by fetch); the phone is unanswered until the mini's rebuild answers, by Nick's decision. To reverse on the Studio: launchctl enable gui/501/com.skippy.mobile; launchctl bootstrap gui/501 ~/Library/LaunchAgents/com.skippy.mobile.plist. S6: the Studio's half is complete — S1 through S5 recorded above with command and literal output; the fifteen-minute watch for the mini's line is stopped. STUDIO HALF CLOSED.

2026-09-10T14:25Z — HANDOVER FROM THE PROJECT-MANAGEMENT LANE (Group H, STEP 4; information and one ask, nothing of yours is edited from here): the four-times-a-day document check now reads every registered live lane's build-board card, progress screen and step record together and names the one that disagrees. Measured 2026-09-10T14:25Z on the cloud copy: this lane's card's newest update says STEP 15 is at 100% while its STEPS.json says 0% — the card's newest step update predates the audit-only revision of this plan, so the two no longer describe the same plan. The fix is one run of the shared update command (unified-project-update.mjs, in the exact one-command form your builder prompt carries) for the step you consider current — it writes the card, the screen and the step record together; until then the check names this lane as MISMATCH.

2026-09-10T15:50Z — NICK'S RULING, AND IT SUPERSEDES EVERY LINE IN THIS RECORD THAT SAYS THE CLOCKWORK IS OFF. Nick, 2026-09-10 ~15:40Z, in chat: the Mac mini's jobs runner is ON ON PURPOSE — he rebooted the scheduled tasks on the mini himself last night. Any earlier line here or in another lane's record that reads "runner OFF by Nick's 2026-09-08 ruling", or that treats the mini's clockwork as switched off, is out of date from this moment and must not be acted on. NOBODY SWITCHES IT OFF. Two things stay true beside it and are not changed by this: the machine map still gives each always-on service one home, with the runner living on the mini and not on the Studio; and no scheduled task runs on a Claude account on the Studio, while a plain script may run on either machine (Nick, 2026-09-10). Written as the first record act of the incoming HUB and PROJECT-MANAGEMENT overseer.

2026-09-10T16:20Z — THE MAC MINI'S SYNC, DIAGNOSED END TO END AND UN-STRANDED. Handed to this lane because it owns
the machines and their jobs; the diagnosis was done by the incoming HUB and PROJECT-MANAGEMENT overseer while
picking up its own work, since nothing on the mini could be trusted until this was understood.

WHAT WAS BELIEVED, AND WHY IT WAS WRONG: the record said the mini's automatic pull reports it "cannot reach the
shared store" while a hand-run connection from that machine authenticates fine. That reading pointed at the
network or the login, and both are healthy: from the mini, asking the shared store for its main line answers
correctly and instantly, returning the very commit that had landed there minutes earlier. THE REAL CAUSE WAS A
STAND-OFF BETWEEN THE MACHINE'S OWN TWO JOBS. The mini's copy had 35 commits that existed nowhere else AND was
436 commits behind. In that state the pushing job refuses to push and says, in its own words, "auto-pull rebases
hourly; this will clear itself", while the pulling job sees the same divergence, exits quietly with a success
code, and pulls nothing. Each deferred to the other, so neither ever acted, and the machine sat weeks behind
running code from 23 August onward. A "cannot reach the shared store" line does appear in the log, but only
intermittently and it is not the blocker.

WHAT WAS AT RISK, AND IS NOW SAFE: of those 35 commits, roughly a dozen were real work held on that machine
alone — acceptance cases added to the scheduled-contracts harness for steps 15, 16, 18, 21 and 23, cases for the
sleep-ring, bank-feed, kids-calendar, kids-prompts and weekly-report jobs, a safety fix stopping a zero reading
from overwriting a real one, and a restore of a person dropped from a surface list by an earlier sweep. All 35,
plus the machine's uncommitted working files, are now on the shared store on the branch
mac/mini-catchup-2026-09-10, and today's later commits on mac/mini-post-catchup-2026-09-10. NOTHING IS STRANDED
ON THAT MACHINE ANY MORE: its local-only count is zero. THE WORK IS PRESERVED BUT NOT MERGED — it needs a read by
whoever owns those harness cases before any of it joins the main line, which is why it sits on branches.

THE MACHINE IS NOW CURRENT: brought level with the shared main line and confirmed to be carrying today's code,
including the Slack catch-up fix that landed this afternoon. That is the first time in roughly three weeks.

🔴 ONE MECHANISM FAULT REMAINS AND IT WILL RECUR — A CODE FIX, NOT A ONE-OFF. The pushing job's safety net, the
fallback that exists precisely so work is never stranded, is permanently broken on that machine today. It pushes
to one fixed branch name carrying the current date, and that branch on the shared store still holds the machine's
pre-catch-up history. Now that the machine's main line descends from the shared one instead, the two histories
have diverged, so every fallback push is rejected outright with "Updates were rejected because a pushed branch
tip is behind its remote counterpart". Its log already shows the consequence twice this afternoon, reading
"commit(s) exist ONLY on this Mac" while the rescue push fails. RECOMMENDED FIX, for whoever next touches that
script: the per-machine fallback branch is scratch space for one machine and should either be pushed with force
or given a fresh unique name per attempt, so that resetting a machine's main line can never disable its own
rescue path. Checked before recommending it: every commit on the stale branch is already contained in
mac/mini-catchup-2026-09-10, so retiring or overwriting that stale branch destroys nothing.

ALSO MEASURED ON THAT MACHINE, worth a look by this lane but not blocking: its repository store has grown to 16
gigabytes with a standing warning that automatic cleanup is refused until too many unreachable loose objects are
pruned, on a disk with 51 gigabytes free.
2026-09-10T18:15Z - SWITCHOVER COMPLETE ON THIS MACHINE + ROLE SWITCH RULED BY NICK.

THE SWITCH-OFF LANDED ON BOTH SURFACES, verified by direct measurement:
- runner.mjs: 153 live SCHEDULE rows -> 22 live / 143 commented. Archive-never-delete honoured (rows prefixed with //, nothing removed), .bak in this evidence folder, node --check passes, runner alive (com.skippy.jobs pid 53884, exit 0). ALL 22 SURVIVORS VERIFIED row-by-row against their own recorded disposition in SCHEDULED.json: every one is either a recorded "keep" or one of the post-audit rows deliberately retained. Zero misses -- no row carrying "fold into" or "retire" is still live.
- This account's Claude scheduled tasks: 16 old ones disabled via the scheduler (nothing deleted, all reversible), keep-list confirmed still enabled, verified independently by an Opus checker who re-listed and cross-checked every row.

THE MAPPING WAS NEVER A JUDGEMENT CALL: all 190 audited jobs in REGROUP-2026-09-08/SCHEDULED.json each carry their own recorded disposition ("fold into Sxx" / "retire" / "keep") from the 2026-09-08 audit, giving 142 switch-off and 48 keep with zero ambiguous. Applied mechanically. Table: evidence/SWITCHOVER-DECISION-TABLE.txt.

CROSS-LANE FINDING, not ours: three of the eight post-audit Hub rows (hub-conversation-read-sweep, hub-slack-user-capture, hub-conversation-capture) are gone from runner.mjs -- REMOVED, not commented, by a separate commit 5360ed6ef at 12:46 today, "hold the three Hub Inbox feed rows off the clock until proven", because the runner guard check "a fast job completes and logs RAN" passed without them and failed with them. Held for cause; recoverable by reverting that commit. Do not re-add without proving them.

🔴 THE HONEST STATE, TOLD TO NICK PLAINLY WHEN HE ASKED "have you actually built any tasks on this account yet": NO. Fifteen of twenty steps are closed against the plan's own definition (their acceptance test passes) but A PASSING TEST IS NOT A RUNNING TASK. Of ten task definitions registered on this account, EIGHT HAVE NEVER WRITTEN A SINGLE RUN RECORD (all five larry-* and all three benito-*: zero heartbeat rows). One carries a lastRunAt and still produced nothing -- the plan's own rule 2 failure exactly, "it ran" is not "it arrived". I had been reporting steps closed without flagging clearly enough that closed does not mean live. Owned, corrected, and the finish line is restated below.

NICK'S RULINGS THIS SESSION:
1. THE TWENTY MOVE TO THE OTHER ACCOUNT. His reason: this account is used heavily and runs out of tokens; the other is a true untouched always-on backup. A scheduled task that cannot fire because its account went dark is the exact silent failure this rebuild exists to kill. ~15 of the 20 run as Claude scheduled tasks and consume account tokens; the rest are daemon rows and are account-independent. Switching cost was near zero because all real work (tests, fixes, the switch-off) lives in git, not in an account.
2. ROLES SWITCHED. The other agent (previous lane driver, on the untouched account) BUILDS; this session VERIFIES AND OVERSEES, and owns the Studio handoff. Its dispatch was probed, not assumed: its own tool calls work, cheap-vendor dispatch works, only Anthropic subagent fan-out is capped until Sunday 06:00 -- so the build proceeds tonight, serial rather than wide, with no Sunday dependency.
3. THE STUDIO IS NICK'S OWN. Handoff delivered to him by Slack DM, revision 2, at evidence/MACHINE-SPLIT-FOR-NICK-2026-09-10.txt.

CORRECTIONS I OWE, both found by the peer's cold read and both re-verified here before accepting:
- COMMIT HASH WAS WRONG in the 2026-09-10T09:48Z entry above: 450e263f2 is NOT an ancestor of main. The oura zero-overwrite guard genuinely IS live (line 74 of jobs/oura-backfill-heal.mjs, confirmed by direct read); it reached main via 78e8e5727. The fix is real, only the citation was wrong.
- "The Studio is off network" was WRONG and I relayed it to Nick as fact. Nick corrected it himself. The peer's ping/ssh failure was hostname resolution from the mini, not the machine being down. The runner decision did not rest on it -- it rested on machine-roles.json "steward": "nicks-mac-mini", verified directly.

THE FINISH LINE, RESTATED AND AGREED BY BOTH AGENTS: a task is done when it FIRED ON ITS OWN CLOCK, UNATTENDED, AND WROTE ITS OWN RUN RECORD. Never a passing harness case. Both sides have accepted this and it supersedes any earlier "closed" that meant only a green test.

STANDING PRACTICE ADOPTED FROM THE PEER: anything that mutates a real file to test it runs in an ISOLATED WORKTREE, never the live checkout -- the auto-sync sweeper here committed a mutation-test value into production lib.mjs for 29 minutes and clobbered the harness three separate times.
2026-09-10T18:35Z - 🔴 REAL DEFECT IN MY OWN SWITCHOVER, FOUND BY THE PEER'S COLD READ, CONFIRMED AND WIDENED BY ME. Correcting the record above.

WHAT I GOT WRONG: I built the kill list mechanically from each job's recorded `disposition` in SCHEDULED.json, treating "fold into Sxx" as "comment out this runner row". That is wrong. "Fold into Sxx" means the old WORK is absorbed into that service family -- it does NOT mean the job FILE stops being the implementation. For a large set of rows the file IS what a new task step declares it EXTENDS, so commenting the row switches off the new task's own engine. I conflated "its work is superseded" with "its clock should stop"; those are different statements.

THE CORRECT RULE, which I should have written first: a runner row stays ON if its .mjs file is named in ANY step's `extends` field (or anywhere in SCHEDULED-REBUILD-LIST.txt), REGARDLESS of its recorded disposition. Disposition governs whether the old work is superseded; extends governs whether the file is still the engine.

SCOPE, measured by extracting all 33 .mjs mechanisms the plan names and diffing against runner.mjs: 24 named mechanisms are commented out; 22 of those were commented BY MY SWITCHOVER (2 were already off beforehand). It reaches THIRTEEN OF THE TWENTY TASKS -- 1, 2, 7, 8, 11, 13, 14, 15, 16, 17, 18, 19, 20. The peer found 16; my sweep found the other 6.
THE 22 TO RESTORE: oura-backfill-heal(11) · bizapp-payroll-refresh(19) · bizapp-standup-capture(20) · mac-backup-watch(23) · spend-tracker(24) · larry-hub-sync(26) · business-feed-watchdog(18,22) · com-skippy-jobs-launchd-watch(22) · booking-reminders-sweep, broadcast-tick, nps-tick, recurrence-tick, ro-followup-tick, sla-tick (all 15) · build-control-status, coordination-governor (25) · gracie-chantelle-inbox-lite(8) · daily-task-email-liveness(10) · capture-tick(16) · bizapp-engine-ingests(16) · grade-skill-evals(26) · monthly-system-review-lite(27) · feed-watchdog(17,22).
HELD DELIBERATELY, NOT RESTORED: roster-liveness-watchdog -- G0 rules roster-liveness off everywhere until task 15 / STEP 22 lands. Recorded as a decision, not an oversight.
THE WORST SINGLE ONE: com-skippy-jobs-launchd-watch is the watchdog that notices if the job runner itself dies. I switched off the alarm while switching off the fleet -- the exact silent failure this rebuild exists to kill.

WHY MY OWN VERIFICATION MISSED IT: my "all 22 survivors verified clean" pass was ONE-DIRECTIONAL. It confirmed every row still live deserved to be live. It never ran the inverse -- that everything deserving to stay on had stayed on. A survivors-are-legitimate check cannot detect an over-reach; only a keeps-all-survived check can. BOTH DIRECTIONS ARE NOW PERMANENT PRACTICE on anything this session signs off.

ALSO CORRECTED: evidence/SWITCHOVER-DECISION-TABLE.txt is NOT the deterministic table this session generated. An Opus decide-stage in an earlier workflow wrote its own judgement-based table to the same path and overwrote it (columns are surface|identifier|state|verdict, not the generated verdict|family|name|machine|cadence|disposition). That file is a model's opinion, not the audit's own record, and must not be cited as authority by either agent. Its KEEP-ON labels happened to be right where my mechanical rule was wrong -- right by luck, not by method.

STATUS: the peer is landing the restore on a branch cut from origin/main, uncommenting only the named rows (restore, not delete, so archive-never-delete holds) and leaving the other commented rows alone. This session re-verifies BOTH directions against origin/main once it lands.

2026-09-10T19:05Z — RECORDER/VERIFIER PASS: CORRECTING THE 2026-09-10T09:48Z COMMIT CITATION. That
entry cited commit 450e263f2 as having landed the oura zero-overwrite guard. Re-verified directly,
just now, rather than trusted: `git merge-base --is-ancestor 450e263f2 main` exits 1 — 450e263f2 is
NOT an ancestor of main. The wrong hash is 450e263f2; the right one is 78e8e5727, confirmed an
ancestor of main (`git merge-base --is-ancestor 78e8e5727 main` exits 0) and its own commit message
names exactly this guard. The fix itself was never in doubt — line 74 of
projects/ops/skippy-jobs/jobs/oura-backfill-heal.mjs reads verbatim: `if (trueVal === 0 && cur !==
0) return { text: md, changed: false, old: cur };`, confirmed by direct read just now. Only the
citation was wrong, and only in the one entry timestamped 09:48Z; this is an append per the
append-only rule, not an edit of that entry. (Note: this same correction was already folded into
the body of the 2026-09-10T18:15Z entry above, written by the agent who found it; this entry
restates it as its own dated record per this pass's brief, and changes nothing about the
underlying facts, which match.)
2026-09-10T18:45Z - RESTORE LANDED AND VERIFIED BOTH DIRECTIONS (verifier session, against origin/main, re-derived not trusted).
origin/main runner.mjs: 45 live, 120 commented, node --check passes. PR #67 (16 rows) + PR #68 (7 rows) = 23 restored.
  (a) nothing LIVE that should be off: 0. Every live row is a recorded "keep", an agreed post-audit row, or a named mechanism.
  (b) nothing OFF that should be live: 1 -- roster-liveness-watchdog, deliberately held per G0 until task 15 / STEP 22, stated in the commit as a decision. The three Hub rows held by 5360ed6ef correctly stayed absent.
Of the 23: 22 were our regression, 1 (feed-watchdog) was already commented beforehand and is a deliberate turn-on -- named by STEP 17 and STEP 22, no hold marker.

THE RULE, NOW CONVERGED ON INDEPENDENTLY BY BOTH AGENTS (two derivations, same answer, which is what makes it trustworthy):
  A runner row stays ON if its file is named in any step's `extends` field or in SCHEDULED-REBUILD-LIST.txt, REGARDLESS of its recorded disposition. Disposition governs whether the old WORK is superseded; extends governs whether the FILE is still the engine.
AND ITS MIRROR, contributed by the peer after it nearly made the opposite error: whether the NEW step is finished governs whether the new TASK is done -- it says NOTHING about whether an already-working job should keep running. Switching off a working job because its replacement is unproven is the same conflation with the sign flipped. Both halves are now standing practice for this lane.

TASK 1 STAGE-ONE FORK RESOLVED BY THE VERIFIER, and the answer is neither option as posed. Read from morning-refresh-wave.mjs's own scope-boundary header: the real architecture is THREE parts, not two.
  PRIMARY   = morning-refresh-early-cc (~07:10, BROWSER-based Oura pull) -- the header says explicitly it is "UNTOUCHED and stays".
  BACKSTOP  = morning-refresh-wave's own Oura leg, API-based, which NO-OPS when the primary already has the data; the wave also imports healCore from oura-backfill-heal.mjs and drives four other refresh legs currently dark.
  REPAIR    = oura-backfill-heal at 12:45 (stage three), live again as of PR #67.
So STEP 11's acceptance case names the WRONG mechanism when it points stage one at the 06:40 wave. The wave is the backstop behind stage one, not stage one. Restore the wave as a backstop (zero-token, no-ops when the primary works, and it carries "fold into S05" which by the rule above does not govern) -- do not wire it as stage one.

🔴 PLAN DEFECT RECORDED AGAINST STEP 11, NOT WORKED AROUND. Point 1 requires stage one to cost "ZERO tokens: no model is called at any point in either stage, and if one of them ever needs a model that is a bug in the task." But the plan's own primary ring pull is a browser-based Claude task, which is a model session and cannot be zero tokens. The zero-token clause and the named mechanism are incompatible. Per §3b's own words a proof that cannot pass is a plan defect, not a build fault -- so the build follows the real architecture and the conflict is carried to Nick. The honest grading, and what §289 point 7 already provides for partly-none tasks like Nick's morning: the ZERO-TOKEN part is the wave's API backstop, and the browser primary is the "model-using part [that] is named and separately accounted".
CONSEQUENCE FOR THE ACCOUNT MOVE: morning-refresh-early-cc is a Claude scheduled task living on THIS (heavy) account, which Nick is retiring for scheduled work. It must be registered on the builder's account like the rest; it is not among the ten definitions registered here.
2026-09-10T18:23Z - 🔴 THE RESTORE WAS ON DISK BUT NOT RUNNING. CAUGHT AND FIXED BY THE VERIFIER.
A build report flagged it honestly and it was real: com.skippy.jobs was running as pid 93919, booted 13:10:40 local. The three restore commits landed AFTER that boot -- e16a785fd 13:12:13 (16 rows), aa7516801 13:13:28 (7 more), 610931b12 13:20:11 (morning-refresh-wave as task 1's backstop). So the running process still held the 22-row schedule it imported at boot and NONE of the 24 restored mechanisms were actually firing. The file was correct and the machine was not -- exactly the gap between "the record says" and "the machine does" that this lane keeps producing, and the reason the finish line is a run record rather than a passing test.
FIXED: launchctl kickstart -k gui/$(id -u)/com.skippy.jobs at 18:22:05Z. New pid 67478, boot record written (state/runner-boot.json, 264 file hashes), jobs.log healthy from the restart ("loaded 78 fired slots (0 pruned >48h) -- restart will not re-fire them", "event-driven work-watch rebuild armed"), process stable. The 46 live rows on disk are now the 46 the runner actually holds.
NOTE for anyone reading launchctl: the "-15" beside com.skippy.jobs is the PREVIOUS instance's exit status (SIGTERM from kickstart -k), not a failure of the current one.
STANDING LESSON, now practice: after ANY change to runner.mjs's SCHEDULE, the runner must be restarted or the change is inert. A green file is not a live schedule. Verify the boot timestamp against the commit timestamp, not just the file contents.

ALSO: the builder had already landed my STEP 11 fix (610931b12) before my message reached it -- morning-refresh-wave restored, and its commit message correctly records it as task 1's BACKSTOP rather than its stage one, matching the verifier ruling.

OPEN AND UNEXPLAINED, named rather than passed over (raised by the builder, not yet resolved): jobs.log was showing fresh completions for jobs (e.g. bizapp-standup-capture) that were not in the running process's own 22-job in-memory set nor its 7-job standby set, and no second local runner.mjs process was found. Either something else reaches this log file or there is a mechanism not yet identified. It does not affect the switchover's correctness but it is unexplained and should not be forgotten.
2026-09-10T18:32Z - 🔴 THE ACCEPTANCE TESTS WRITE FAKE "THIS JOB RAN" EVIDENCE INTO THE LIVE jobs.log. THIS INVALIDATES OUR OWN FINISH-LINE TEST. Found by the verifier while chasing the builder's unexplained-completions report; the mystery is solved and the answer is worse than the mystery.

PROVEN BY CONTROLLED EXPERIMENT, not inference:
  md5 jobs.log before : 1370daf78793d35b907b3c33b6d34196
  node projects/ops/skippy-jobs/_test-scheduled-contracts.mjs --case overdue --case standup
  md5 jobs.log after  : f9891648561d75b8400eb02d60cce5b2
Lines that test run produced, verbatim:
  [2026-09-10T18:28:51.568Z] todo-bump-overdue OK - lists: 4 · would bump: 1 · wrote: 1
  [2026-09-10T18:28:51.788Z] bizapp-standup-capture OK - capture in progress (2026-09-04, 5m, pid 90175)
That is exactly the pattern the builder flagged (bizapp-standup-capture completing while absent from the running process's schedule). There is no second runner and nothing external reaching the log -- the harness itself is the writer. Every `--case all` run by either agent has written fake run evidence into the live record.

WHY IT MATTERS MORE THAN A LOGGING NUISANCE:
- roster-liveness-watchdog reads jobs.log's RAN lines via loadLastRunTimes() to decide whether a job is alive -> test runs make dead jobs look alive to the watcher.
- STEP 30's `--read-only-live outcomes` counts "unattended firing" as a completed RAN line in jobs.log -> STEP 30 can report a task LIVE on evidence a test manufactured.
- The agreed finish line is "it fired on its own clock, unattended, and WROTE ITS OWN RUN RECORD". If the harness writes run records, that criterion proves nothing. EVERY LIVENESS CLAIM MADE FROM jobs.log IS CURRENTLY UNSAFE, INCLUDING ONES THIS SESSION HAS ALREADY MADE.

SAME DEFECT WE ALREADY FIXED ONCE AND ONLY HALF-FIXED: STEP 12's case was forging OK rows into the live HEARTBEAT.md; the fix wrapped it in SKIPPY_HEARTBEAT_OVERRIDE to a temp file. jobs.log never got the equivalent. The verifier missed it at the time by confirming HEARTBEAT.md was byte-identical and never checking jobs.log -- verification scoped too narrowly, for the second time today.

THE FIX (builder's to implement): give the job logger the same override the heartbeat writer has -- an env var the harness sets to a temp path before invoking any case that calls a real job's run(), restored in a finally. Cases known to reach real jobs: overdue (todo-bump-overdue), standup (bizapp-standup-capture), kids-calendar (calendar-push), oura (healCore), hub-due-work. Prove it as the heartbeat fix was proved: md5 jobs.log before and after a full --case all must be identical.

🔴 INTERIM VERIFICATION RULE, IN FORCE UNTIL THAT LANDS: a task counts as genuinely live ONLY IF its run record's timestamp corresponds to its own scheduled fire time AND no test run happened near it. A RAN line alone is no longer evidence. Any task handed over as live must come with its due fire time alongside the record timestamp so the two can be matched. Corollary: some of the eight-with-zero-heartbeat-rows may be the HONEST ones, and any task that looked live off a log line needs re-checking against its real cadence.

GOOD STATE FROM THIS SAME PASS, all verified fresh: all twenty acceptance cases PASS including oura -- the builder's morning-refresh-wave restore (610931b12) fixed STEP 11's failure exactly as the verifier predicted. origin/main runner.mjs 46 live / 119 commented, node --check passes, both directions clean (nothing live that should be off; nothing off that should be live except roster-liveness-watchdog, held by agreement). Runner pid 67478 holding all 46 since 18:22:05Z. So the SCHEDULE is sound; it is the LIVENESS EVIDENCE that is compromised.

STILL OPEN: STEP 29's done_proof remains the broken d['receipts_missing_covered'] version. S11 confirmed present in service-contracts.json, so the fix is viable as described. Needs re-applying AND committing.
2026-09-10T18:43Z - VERIFIER PASS. TWO LEDGER ROWS CLOSED ON MEASUREMENT, ONE DEFECT STILL OPEN.

STEP 29 CLOSED. The done_proof re-fix landed and this time it is committed: 8583e6682, confirmed a genuine ancestor of HEAD with a clean working tree. Verified by the verifier directly, not from the builder's report -- the proof was extracted verbatim from STEPS.json and run from the repo root: EXIT 0. It was also proved able to FAIL (same logic against a scratch copy with S11 renamed: exit 1), because a proof that cannot fail is worthless. It now reads the entry in `services` with id "S11" and asserts its `definition` contains "does not establish weekly missing-receipt coverage" and its `rules` contains "no message to Mae is sent by this lane" -- both confirmed present in the real file. NOTHING WAS SENT TO MAE AND NOTHING NEEDS TO BE: the answer is already recorded in the repo, which is precisely why the proof can read it instead of waiting on a reply. The drafted question stays "DRAFT ONLY -- Not sent", confirmed untouched. This needed fixing TWICE because the first fix was never committed and the auto-sync sweeper reverted it -- the verifier's own error, and the reason "commit immediately" is now standing practice in this lane.

STEP 11 CLOSED, and the ledger's own prediction about it was WRONG. The ledger row stated "Restoring the wave as a backstop will not make this specific case pass as written." It did: after the builder's commit 610931b12 restored morning-refresh-wave, `--case oura` returns PASS/exit 0, confirmed in two separate passes and inside a full `--case all` (20/20). The row is closed on the run, not on the reasoning. Measurement beats prediction, including a verifier's own.
🔴 BUT THE PLAN DEFECT UNDER IT IS NOT CLOSED BY THAT ROW AND MUST NOT BE: STEP 11 point 1 requires stage one to cost "ZERO tokens... if one of them ever needs a model that is a bug in the task", while the plan's own primary ring pull is a browser-based Claude task -- a model session, which cannot be zero tokens. The case also still labels the wave "stage one" when the wave is the BACKSTOP behind the browser primary. The test is green and the label is inaccurate. That goes to Nick as a plan defect and must NEVER be resolved by editing the assertion to agree with the verdict it exists to check.

LEDGER NOW: 16 CLOSED / 1 OPEN (STEP 30, correctly -- it is the final grade and cannot close until the twenty are actually live).

🔴 STILL OPEN, AND IT IS THE ONE THAT MATTERS: THE HARNESS STILL FORGES RUN EVIDENCE INTO THE LIVE jobs.log. Re-measured this pass, unchanged -- md5 before/after a full `--case all` still differs. Until the builder lands the job-log override (mirroring SKIPPY_HEARTBEAT_OVERRIDE), no task counts as live on a RAN line alone: its record timestamp must match its own scheduled fire time with no test run nearby. Every liveness claim in this lane, including this session's own, is provisional until that lands.

OTHERWISE GREEN THIS PASS, all fresh measurement: origin/main runner.mjs 46 live / 119 commented, node --check passes; both directions clean (nothing live that should be off = 0; nothing off that should be live = 1, roster-liveness-watchdog, held by agreement per G0); runner pid 67478 booted 18:22:05Z, after the newest schedule commit, so the process genuinely holds all 46; all twenty acceptance cases PASS.

2026-09-10T18:5xZ — THE HUB'S THREE INBOX FEED ROWS ARE ON THE CLOCK, and this lane's rebuild list now
records them. Written by the HUB lane overseer; nothing here is an ask.

WHAT IS NOW TRUE: the Inbox fills on its own every five minutes instead of only when a person runs a
job by hand. Three jobs that already existed and worked were on no schedule at all — one learns which
Slack people and channels exist, one captures new conversation rows, one hides for Nick anything he
has already read past. They sit directly above the row that sends his approved replies, so a captured
row exists before the sender looks for one. All three are idempotent.

THIS ONLY MATTERS BECAUSE THE CLOCKWORK IS ON. Nick, 2026-09-10: the Mac mini's runner is ON on
purpose and nobody switches it off. Every earlier line in this record saying the runner is off is
superseded.

HOW IT WAS PROVEN, after a false alarm that is worth recording. The rows were held off the main line
for an hour because one guard check appeared to fail only when they were present. Re-run properly —
the whole guard, both ways, back to back, in one clean copy of the cloud line — the failing set is
the SAME SEVEN checks with the rows and without them. The earlier difference came from the shared
working copy on this Mac changing between the two runs, which is a standing hazard for any
measurement taken there. The rows also cost only 32 milliseconds of extra startup, measured.

🔴 AND THE ALARM ITSELF TURNED OUT TO BE A BROKEN CHECK THIS LANE OWNS: "a fast job completes and logs
RAN" exercises the runner against the date-tick job, which is commented out of the schedule, so the
runner answers "unknown job" and exits 1 every time, in every copy. It cannot pass. While it stands
red it will hide a real regression in the same guard. Fix by pointing it at a scheduled fast job or
re-enabling date-tick; never by widening a budget.

A FOURTH JOB IS READY AND DELIBERATELY UNSCHEDULED: the mail-capture wrapper, inert until someone puts
it on the clock. The reason it must exist rather than calling the shared job directly is in the
rebuild list entry.
2026-09-10T18:46Z - VERIFIER PASS. THREE HUB ROWS WENT LIVE -- INVESTIGATED, AND IT IS CORRECT, NOT A REGRESSION.
origin/main jumped 46 -> 49 live rows and my check flagged hub-conversation-capture, hub-conversation-read-sweep and hub-slack-user-capture as "live but should be off", because they were the three held for cause by 5360ed6ef. Traced before reacting: commit d9457652d ("the three Hub Inbox feed rows go on the clock -- cleared of the guard failure that held them") DISCHARGES that hold by measurement, and the reasoning holds up:
 - the full runner guard reports the SAME SEVEN failing checks with and without these rows, run back to back in one clean copy pinned to the cloud line;
 - the earlier one-off difference came from the shared working copy shifting between runs, not from the rows;
 - measured cost of the rows: 32ms of extra startup (2 + 29 + 1 ms of module import).
So the hold was correct when made and is now properly retired on evidence. My expected-live set is updated to include all three; they are legitimate.
🔴 A REAL DEFECT SURFACED BY THAT SAME COMMIT, CARRIED HERE SO IT IS NOT LOST -- IT BELONGS TO ANOTHER OWNER: the runner guard check "a fast job completes and logs RAN" CANNOT PASS IN ANY COPY TODAY. It exercises the runner against the date-tick job, which is commented out of the SCHEDULE, so the runner correctly answers "unknown job" and exits 1. That is a broken CHECK, not a broken runner, and it belongs to whoever retired date-tick. Worth knowing because a permanently-red check is one nobody reads -- the same failure mode this lane's own watcher work exists to prevent.

RUNNER WAS STALE AGAIN AND IS NOW CURRENT. It was running pid 67478 from 18:22:05Z while d9457652d landed at 18:44:16Z, so the three newly-cleared rows were on disk and NOT loaded -- the same inert-change gap caught earlier today, second occurrence. Kickstarted: new pid 45279, booted 18:45:40Z, healthy startup ("loaded 120 fired slots (0 pruned >48h) -- restart will not re-fire them", "event-driven work-watch rebuild armed"), stable on re-check, no new failures. The runner now genuinely holds all 49 rows. This is now a per-pass check, not an incident.

STATE THIS PASS, all fresh measurement: origin/main 49 live / 119 commented, node --check passes; direction (b) still the single expected roster-liveness-watchdog held per G0; all twenty acceptance cases PASS; review ledger 16 CLOSED / 1 OPEN (STEP 30 only, correctly).

🔴 UNCHANGED AND STILL THE ONLY BLOCKING DEFECT: the harness continues to forge run evidence into the live jobs.log -- md5 before/after a full --case all still differs. Every liveness claim in this lane stays provisional until the job-log override lands.
2026-09-10T19:05Z - 🔴🔴 THE SCHEDULED FLEET IS RUNNING ON NEITHER MACHINE. ROOT CAUSE FOUND. NEEDS NICK -- IT GATES THE ENTIRE FINISH LINE.
Surfaced by the independent verifier on the jobs.log fix and then confirmed directly here.

THE MEASUREMENT: the mini's runner is awake, healthy and DELIBERATELY STANDING BY. Its own log at both restarts today (18:22:05Z and 18:45:40Z):
  "skippy-jobs STANDBY - STANDING BY on Nicks-Mac-mini - Nicks-Mac-Studio is in charge of the job runner, so scheduled jobs are held here (this is correct, not a fault). Still running the 7 job(s) that are about this machine: presence-beacon, work-watch, retire-verified-signals, agents-md-heal, service-code-fresh, service-restart-actor, sync-drift-watch."
So all 49 scheduled rows are HELD on the mini, not fired. And the Studio wrote its last job-runner heartbeat at 2026-09-09T21:45:26Z and nothing since. BOTH MACHINES ARE DEFERRING. Nothing is firing the fleet anywhere.

ROOT CAUSE -- TWO FIELDS IN ONE FILE THAT DISAGREE: projects/ops/machine-roles.json carries
  "steward": "nicks-mac-mini"        <- the field this session read and verified
  "roles": { "jobs": "Nicks-Mac-Studio" }  <- THE FIELD THE RUNNER ACTUALLY READS
projects/ops/skippy-jobs/lib/role-owner.mjs resolves ownership from `roles`, not `steward`. This session checked the wrong field and told Nick the mini owned the runner. IT DOES NOT. That is this session's error and it is corrected here rather than quietly amended -- and it invalidates the confident "the mini owns the runner" line in the Studio handoff sent to Nick earlier, which has now been corrected to him directly.

WHY THIS OUTRANKS EVERYTHING ELSE IN THE LANE: all twenty tasks are specified to run on the mini through this one runner. Until roles.jobs names the mini they CANNOT fire there however correctly they are built. Every piece of tonight's work -- the switch-off, the 23-row restore, the harness, the twenty acceptance cases -- has been building toward a runner that is holding the door shut. It is not a build defect; the build is sound. It is a one-field configuration fact.

WHY NEITHER AGENT MAY FIX IT: machine-roles.json is person-only by explicit rule, and role-owner.mjs records WHY at length -- automatic hand-over was designed and REJECTED on measurement 2026-08-11, because a standby machine cannot distinguish "idle" from "dead" (the other Mac once looked 2h36m dead while running fine), and because each machine's record of already-fired slots is local and gitignored, so a mid-morning takeover re-sends the morning message to a real person twice. Fail-to-status-quo is deliberate. An agent editing this file would be overriding a safety decision made against measured evidence.

THE ASK, SENT TO NICK BY SLACK DM 19:05Z: change roles.jobs from "Nicks-Mac-Studio" to "Nicks-Mac-mini" in projects/ops/machine-roles.json, then `launchctl kickstart -k gui/501/com.skippy.jobs`. Flagged to him that it should be done while he can watch, since the mini then begins firing the full schedule; and that it is the same stale-row problem already raised in the Studio handoff, so roles.jobs and the stale Studio job list are worth fixing in one sitting.

UNTIL HE DOES: no task on this machine can satisfy "fired on its own clock, unattended" -- not because of anything the builder has or has not built. The builder's remaining work (registering the twenty on the untouched account) is unaffected and continues.

2026-09-11T02:26Z - STUDIO (a session running on Nicks-Mac-Studio): DONE ON NICK'S WORD. Nick, 2026-09-10, in the Studio session: "the mini was alwasy supposed to have scheduled jobs on it" and "do whatever you need for the docs". roles.jobs AND roles.ala-daily now read "Nicks-Mac-mini" (commit d4e9d23a56, on origin/main, verified by `git show origin/main:projects/ops/machine-roles.json`); app-host stays Nicks-Mac-Studio. The Studio's jobs row was rewritten to the measured set (eleven loaded, owned services) and the stale rows removed. No kickstart is needed on the mini: runner.mjs re-reads the file every tick (lines ~1358-1370), and a takeover claims slots before firing, so nothing already passed is re-sent (~1409-1422). PROOF ON THE STUDIO: its runner logged at 02:24:05Z "who is in charge of the job runner CHANGED: Nicks-Mac-Studio → Nicks-Mac-mini. STANDING BY" and has fired nothing but its own seven machine-local jobs since. CONTEXT: the Studio's runner had been repaired and started by another Studio session at 17:59 local (commit 53079f183e, against STUDIO-LIST S1), so between then and 02:24Z the Studio fired the schedule, from one runner, with the mini on standby -- no double fire. OWED BY THE MINI'S AGENT: confirm its runner logged OWNER after its next pull and push a heartbeat row. OWED BY THE STUDIO: once that row is on origin/main, unload and disable the Studio's com.skippy.jobs again (S1). Full Studio measurement and the hand-over list for the mini: evidence/STUDIO-CHECK-2026-09-10.txt section 7.
2026-09-11T03:40Z - NOTE FROM THE VOICE LANE (a Studio session), for the mini hand-back above. (1) Nick's Mac mini has not pushed its in-flight list to the brain since 2026-08-31 07:34Z (cloud /data/threads-push-Nicks-Mac-mini.json; the git copy work-threads-Nicks-Mac-mini.json is 2026-09-08) - that is the "One machine has stopped sending updates" line on Nick's Status screen in both apps. When the mini's runner logs OWNER, please also confirm its work-watch RAN and that cloud file's time moved. (2) The Studio's own work-watch must keep running after the Studio's com.skippy.jobs is unloaded: Nick's live sessions are on the Studio and the runner is the only thing firing work-watch here (com.skippy.work-watch.plist is not loaded). The VOICE lane restarted the Studio runner at 03:18Z (launchctl kickstart) because it booted before work-watch was re-enabled in runner.mjs (commit 6f6ff23615); it now fires work-watch on standby, first run 03:18:33Z, push landed. If you unload the Studio runner, load com.skippy.work-watch here in the same sitting, or Nick's Status goes blank again. (3) 27 leftover test and probe files (VERIFY-PROBE, smp*, terra-u2*, defect-test-*, and the two old .local machine names) were MOVED, not deleted, from the cloud box's /data into /data/retired-threads-push-2026-09-11/, because they held a permanent false "stopped sending" warning on Nick's screen.