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 — PROJECT FILES — one card, one live file, a locked archive
Owner: Nick. Purpose: plan (this lane's only record; RULE 41).
**🔴🔴 THIS IS THE ONLY PLANNING DOCUMENT FOR THIS PROJECT. Do not create a second plan, tracker, summary, or scratch state file — extend THIS file. Any status view is GENERATED from this plan; if a view disagrees with the plan, the plan wins.**
**NORTH STAR:** Nick's words, 2026-09-18 14:45Z: "the single project file is the single source of truth - we run that one file all the way through until its done - if a new file is created it archives the old one so there isnt any confusion … i want a project file active while its active and nothing else created besides the one project file unless given specific permission - then when that file is retired it goes in the archive and that archive is locked or blocked - the same way original claude folder is supposed to be hidden from use or searches". Confirmed 2026-09-18 17:20Z: "sounds good - triad your ideas and act".
**FINISH LINE:** (a) RULE 51 carries one dated 2026-09-18 addendum in MACHINE-RULES.md and CORE §5 and BUILD §5 cite RULE 51; (b) every git-tracked file that called itself retired, superseded or archived, every tracked backup copy, every extra plan and every companion file beside a closed project's plan sits under `projects/_archive/2026-09-18-<project>/` with its git history, no registry-named or card-named file moved, no gitignored side-copy moved or added, and this file records the before and after counts from the same command; (c) a Read, Grep, Glob or Bash read under `projects/_archive/` or the old workspace folder is refused with the reason, a ticket lets one through, a live file still reads, and the ignore file keeps the archive out of search; (d) a commit that adds a second plan-like file to a project folder is refused unless the registry or a ticket names it; (e) every AI Builds card shows its live file as a link, and closing the card retires the file into the archive; (f) one generated retired-projects list exists and names every retired project with its archive folder and date; (g) each of (a)–(f) has a `VERIFIED:` line from a checker that did not build it. Finish-line date: 2026-09-21.
**Owner:** Fable (this session, lane lead) · **Overseer:** ONE — Fable; never builds the mechanical steps, and builds the instruction files and the control-plane `check-*` files by the standing exception (CORE §3, check-routing-missed.mjs) — STEP 0 item 3 does not move those down · **Design authority:** none — the only rendered change is an existing Hub text row becoming a link
> **STEP 0 — ARM THE LOOP, BEFORE ANYTHING ELSE.** Set a 5-minute loop. Every time it fires, answer
> these five in order and CORRECT any failure before doing anything else:
> 1. **NORTH STAR** — is what I am doing this minute moving this plan's North Star? If not, drop it.
> 2. **FAN-OUT** — declare the whole actual roster, dispatch useful ready work, and shed your own unnecessary processes. Coordinate through peers or the launching dispatcher; no numeric cap or load-wait rule applies.
> 3. **CHEAP** — are cheap models doing the building AND the per-step checking? If anything on
> Anthropic or OpenAI is building or checking a step, move it down now (§M).
> 4. **STUCK** — for anything I have called blocked: name the input that does not exist yet, or the
> three concrete things I tried. If I cannot, it is not blocked — drive through it now.
> 5. **NEXT** — did something just finish? Then the next step whose inputs exist starts THIS minute.
> A finished step is never a place to stop, a report is never a reason to wait, and Nick being
> away or asleep is the reason to keep going, not to pause.
> Then keep building. The loop never stops until the FINISH LINE is proven.
**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.**
## Already true (facts, not story)
- The rules already say most of this and nothing enforces them at commit time or on reads: RULE 31 (birth needs approval), RULE 41 (the plan file is the only record), RULE 38 (the old setup is out), RULE 51 (one thread, one project file, one card), RULE 54 (what supersedes replaces) — evidence: `command grep -n "RULE 31\|RULE 38\|RULE 41\|RULE 51\|RULE 54" projects/ops/MACHINE-RULES.md`
- Measured twice on 2026-09-18 and the two passes disagreed (mine over the disk: 163 plan files, 23 multi-plan folders, 249 companions, 51 banners, 82 tracked retired names; the skeptic's over `git ls-files`: 18 multi-plan folders, 57 extra plans, 286 companions, 72 banners, 15 tracked retired names, 2,544 gitignored side-copies including three vault backups and two OAuth tokens) — so no number here is trusted until STEP 2's module prints it from `git ls-files`, and gitignored files are never touched — evidence: re-created by STEP 2 as `node projects/ops/skippy-jobs/lib/project-files.mjs --measure --json` CREATED BY STEP 2
- The archive holds 14,779 files (2.6 GB, 7,416 git-tracked) and every agent can read and search it; the old workspace path `~/Documents/Claude/projects/ops/skippy-jobs/state` was recreated empty at 09:38 on 2026-09-18 by a writer not yet found — evidence: `find projects/_archive -type f | wc -l`, `ls -la ~/Documents/Claude/projects/ops/skippy-jobs/`
- Hub cards already carry `project_file` (validated `projects/**/*.md`), `project_folder`, `north_star`, `finish_line`, robot-only `bind_project` and `bind_project_folder`, and the card detail shows a plain-text "Project file" row — evidence: `command grep -n "project_file" app/functions/api/tasks.js app/js/tasks.js, run inside the Hub repository`
- Two write-time gates exist and neither closes the hole: `check-plan-proliferation.mjs` watches Write only, PLAN-named files only, and exempts STATE/QUESTIONS/ASSUMPTIONS/PLAN-CHANGES/*-REPORT; `check-md-governance-gate.mjs` needs a ticket for a second `.md` in a folder but its kill switch is active until 2026-09-18 23:55Z; nothing runs at commit time, nothing hides the archive — evidence: `sed -n 1,45p projects/ops/skippy-jobs/lib/check-plan-proliferation.mjs`, `node projects/ops/skippy-jobs/lib/md-gov-kill-switch.mjs status`
- Commit-time gates live in the tracked `ZION/lib/pre-commit-parity.sh`; the per-machine pre-commit hook is rewritten each session end and sources it — evidence: `sed -n 20,30p .git/hooks/pre-commit`
- Tickets are rows in `tickets.jsonl` (repo root) with `path`, `date`, `approver`, `is_test`; filed by `request-ticket.mjs <path> --reason "<why>"`; `check-root-ticket-gate.mjs` already matches a same-day non-test row by exact path — evidence: `tail -1 tickets.jsonl`
- The project-status registry already has `retired`, `retiredBecause`, `supersededBy` fields on one row, and `projects/ops/artifacts/project-status/build.py` renders the registry — the retired list is a generated projection of those rows, never a second ledger — evidence: `command grep -c '"retired"' projects/ops/artifacts/project-status/registry.json`
- A working-documents tier exists in the business engine (the Hub repository's `engine/store/working_tier.py`, index in the gitignored `skippy.db`, retirement folder `projects/_archive/working-retired-<date>/`); its lifecycle job is not in `runner.mjs` and its folder has never existed (DATA-RULES.md RULE 8B, its own words); the Hub card's `project_file` plus the tracked registry supersede that machine-local index (RULE 54), and this plan says so rather than building beside it — evidence: `command grep -c "working-tier-lifecycle" projects/ops/skippy-jobs/runner.mjs` → 0
- Live REGROUP lanes written in the last three days (ASSISTANTS, HEALTH-ONE-DOOR, HEALTH, HUB, LANE-1-WORKSHOP, LINKEDIN-ENGINE, MEETINGS, SCHOOL, SKIPPY-NEXT, SKIPPY-TESTING, TALK-APP-LAYER, CLOUD-MOVE, JASMIN-CAPTUS, LANE-6-FAMILY-APP, RECRUIT-HEADHUNT, VOICE) keep their companion files until their owner closes the lane; SKIPPY-TESTING is untouchable while its run is live — evidence: `stat -f "%Sm %N" projects/ops/life-os/REGROUP-2026-09-08/plans/*/PROGRESS.txt`
## 0 · Gate Zero receipts (the plan may not exist without these)
- Failure Mode Registry loaded: 2026-09-18, 197 entries (`command grep -c '^| ' .claude/skills/plan/references/failure-registry.md`); the eight this build is exposed to are named in §4
- Canonical specs loaded: `projects/ops/CORE.md` §4–§5, `projects/ops/blocks/BUILD.md` §5, `projects/ops/blocks/REPO.md`, the HUB path block the Hub repository's own `CLAUDE.md` (the HUB path block) §2–§3, the Hub repository's `KANBAN-AND-AGENT-BOARDS-SPEC.md` (whose headings end at §9.18 — the HUB block's §10–§12 citations point at nothing; handed to the HUB lane in STEP 6), `projects/ops/MACHINE-RULES.md` RULE 31/38/41/51/54, `.claude/skills/plan/references/plan-template.md`
- Ownership check: `projects/ops/artifacts/project-status/registry.json` has no row for a project-files or archive-lock lane (`command grep -c "project-files\|archive-lock" projects/ops/artifacts/project-status/registry.json` → 0); the PROJECT-MANAGEMENT lane (`projects/ops/life-os/REGROUP-2026-09-08/plans/PROJECT-MANAGEMENT/PLAN.proposed.txt`) covers board naming and the shared update command, not files or the archive, and is one of the folders this lane cleans; the failure registry, the ticket ledger, the registry and the Hub's `project_file` field are extended, never copied
- Expected inputs confirmed to exist: `tickets.jsonl` (root), `projects/ops/skippy-jobs/lib/request-ticket.mjs`, `projects/ops/skippy-jobs/lib/check-root-ticket-gate.mjs`, `projects/ops/skippy-jobs/lib/check-claude2-write-gate.mjs` (exports `extractBashTargets`), `projects/ops/skippy-jobs/lib/check-plan-proliferation.mjs` (exports `planScopeOf`), `ZION/lib/pre-commit-parity.sh`, `.claude/settings.json`, `projects/ops/artifacts/project-status/registry.json`, the Hub repository's `app/functions/api/tasks.js`, `projects/ops/skippy-jobs/lib/hub-session.mjs`, the vault key `deck-business-skippy-token` (present, 2026-09-18)
- PLAN AUTHOR: Fable, session claude-2-0-6e, 2026-09-18
- COLD READER: the triad — an independent skeptic attacked the design on 2026-09-18 (findings folded into §3b and §4); a fresh spec-breaker reads this plan once before STEP 1 lands and its disputes are recorded here
- PROMPT-SPEC scan (P1–P7): P1 "plan-like file" → defined mechanically in STEP 2's shape list; P1 "old-setup path" → `~/Documents/Claude/` and any `Documents/Claude/` not followed by ` 2.0`; P3 "nothing enforces them" → re-measured, two write-time gates exist and are named above; P4 exclusions → live lanes, SKIPPY-TESTING, Hub worktree copies, cheap-task snapshots, the Hub's built `dist` folder; P5 destination → this file and the Hub card; P6 none; P7 none
## 1 · Goal and definition of done
- **What we're building, one paragraph.** One rule, enforced: a project is one Hub card naming one live file; everything else beside that file needs a ticket or does not exist; when the card closes the file is archived and the archive is locked against every agent's reads and searches. The workspace is cleaned to that rule once, with history, and the Hub shows every project's live file.
- **HOW IT'S USED:** an agent opening a project opens its card and its one file; an agent that tries to read the archive or create a second plan-like file is refused and told the ticket command; Nick opens any AI Builds card and clicks through to the live file. · HOW WE KNOW: the hook and gate refusals are reproduced by the checker; the link is clicked on the live Hub.
- **WHAT IT LOOKS LIKE:** a refusal message naming the path, the rule and the door; a "Project file" link on the card; one retired-projects list. · HOW WE KNOW: the checker pastes the refusal and screenshots the card.
- **WHERE IT LIVES:** the rule in `projects/ops/MACHINE-RULES.md` (RULE 51, 2026-09-18 addendum), the hooks in `projects/ops/skippy-jobs/lib/`, wiring in `.claude/settings.json` and each machine's `~/.claude/settings.json`, the commit checks in `ZION/lib/pre-commit-parity.sh`, the retired list in `projects/ops/artifacts/project-status/` (STEP 7), the cards on hub.heroesandsidekicks.io — **opened by Nick and every agent.** · HOW WE KNOW: each path is read back after landing.
- **WHAT IT MUST DO:** 1. refuse a Read/Grep/Glob/Bash read under `projects/_archive/` or the old workspace without a ticket; 2. let a ticketed read through; 3. never refuse a live file; 4. keep the archive out of Grep results; 5. refuse a commit adding a second plan-like file unless registered or ticketed; 6. refuse a commit whose live text points into the archive; 7. archive every retired, superseded, backup, extra-plan and closed-companion file with history; 8. show the live file link on every AI Builds card; 9. retire the file when the card closes; 10. list every retired project in one generated file. · HOW WE KNOW: §6 evals, one per capability.
- **NOT in scope:** deleting anything (archive only; deletion is one of the four acts and is never requested here); the 52 loose PLAN/HANDOFF/SPEC/AUDIT-named files at `projects/ops/` root (listed for a second pass, not moved — they include live instruction files); the Hub board layout beyond one link row (HUB lane's design redo, Nick 2026-09-12); moving any live lane's companion files while the lane is open (told to the owner instead); security and privacy work (always out; trip-over protocol below).
- **Trip-over protocol:** a lane that finds something outside the fence writes one handover line to its named owner (a security- or privacy-shaped thing: one line in `projects/ops/sp-sec/PLAN.md`), then back to building — never investigates, never fixes.
## 1a · Critical variables — the confirmation sheet is GENERATED from this table
| # | The variable, in plain words | Value chosen | Alternatives rejected | Class | HOW WE KNOW | Cost if wrong | CONFIRMED |
|---|---|---|---|---|---|---|---|
| 1 | **SURFACE — which screen this lands on, and who opens it** | The AI Builds board card detail on hub.heroesandsidekicks.io, opened by Nick; the refusal text in every agent's tool result | A new Hub screen; a Slack digest | V1 | Nick, 2026-09-18, "it should be a part of how we do PM in the hub so its clear" | A record nobody opens | Nick, 2026-09-18, "sounds good - triad your ideas and act" |
| 2 | What counts as the one live file when a folder has several | The card's `project_file`, else the registry's `planFile`, else the newest plan whose top is not retired | Always the newest; always PLAN.md | V1 | Nick, 2026-09-18, "the single project file is the single source of truth" | A live plan archived | Nick, 2026-09-18, "sounds good - triad your ideas and act" |
| 3 | Whether the archive stays in git | Yes — tracked, locked, never deleted | Untrack it; move it off the repo | V1 | Nick, 2026-09-18, "goes in the archive and that archive is locked or blocked" | History lost, or an unlockable copy | Nick, 2026-09-18, "sounds good - triad your ideas and act" |
| 4 | Whether a GitHub link to the private repository opens for Nick (gates STEP 6 only; STEPS 1–5 do not depend on it) | A GitHub link to `nick-deck/deck-brain-2`, opened once in Nick's own browser as him before the link ships | A Hub-served copy of the file | V2 | opened `.git/config`, 2026-09-18, saw: a private remote reached through a token, so a browser must be signed in; STEP 6 step 2 opens one such link in the test browser as Nick and records what it saw before building | Every card's link is a sign-in wall for the one person it is for | opened the remote, 2026-09-18, saw: private repository; the browser check is STEP 6's first act |
- V1 confirmation reads `<name>, <date>, "<their own words>"` — the date is required.
- V2 confirmation reads `opened <what>, <date>, saw: <what was actually there>`.
**Considered and ruled NOT critical:**
- `the archive folder naming` — `projects/_archive/<YYYY-MM-DD>-<project>/` is the existing convention (26 dated folders already); no second answer changes the build
- `which cheap vendor moves the files` — any of the three named executors produces the same `git mv` list; the proof is the same
## 1b · Subproject decomposition — could a piece of this ship on its own?
- **SINGLE SUBPROJECT:** the rule, the cleanup, the lock, the gate, the Hub record and the list each depend on the same plan-like definition and the same archive path; shipped apart they would disagree on what a project file is, which is the defect this lane exists to end.
**Carve-out rule:** anything left out of every subproject's scope is named with a real owner in the same edit, or it may not be left out.
## 2 · The complete UX map (this becomes the test manifest verbatim)
| Id | Screen / entry point | State (default·empty·error·loading) | Element / interaction | Expected behavior | Navigation from → to |
|---|---|---|---|---|---|
| U1 | Any agent session · Read tool | error | Read `projects/_archive/JOBS-OFF-THE-MAC-2026-08-08.md` | Refused: 🔴 message names the path, RULE 51, and the ticket command | tool call → refusal |
| U2 | Any agent session · Grep tool | default | Grep repo-wide for a word only the archive contains | Zero hits from `projects/_archive/` | tool call → result |
| U3 | Any agent session · Bash | error | `cat projects/_archive/JOBS-OFF-THE-MAC-2026-08-08.md` or `cat ~/Documents/Claude/anything` | Refused with the same message | tool call → refusal |
| U4 | Any agent session · Read tool with a ticket | default | Ticket filed and approved for the exact path, then Read | Allowed; the ticket row is the reason | tool call → content |
| U5 | Any agent session · Read tool | default | Read this plan file | Allowed, unchanged | tool call → content |
| U6 | git commit | error | Stage a second `PLAN-X.md` in a folder that already has `PLAN.md` | Refused: names the existing file, RULE 51, the ticket command | commit → refusal |
| U7 | git commit | default | Stage a `PLAN.md` in a folder with none, or one the registry names | Allowed | commit → landed |
| U8 | git commit | error | Stage a live `.md` whose text contains `projects/_archive/` | Refused, names the line | commit → refusal |
| U9 | Hub · AI Builds board · card detail | default | "Project file" row | A link that opens the live file on GitHub | card → file |
| U10 | Hub · AI Builds board · card detail | empty | Card with no `project_file` | Row reads "no project file — bind one" and the agent door refuses opening such a card | card → refusal |
| U11 | Hub · card marked Done or superseded | default | The retire job's next run | File moved to the archive, registry row `retired`, list regenerated; the card keeps its original path and the list maps it to the archive folder | card close → archive |
| U12 | The retired list (STEP 7) | default | One line per retired project | Name, date, one-clause reason, archive folder | file → archive folder (the one allowed pointer) |
DESIGN FIDELITY GATE: N/A — nothing new is rendered; one existing Hub text row becomes a link in the Hub's own style
## 3 · Lanes and frozen contracts
| Lane | Scope (in / out) | Owner | Definition of done | Builder (cheap, named) | Backup builder | Checker (different model) | Backup checker |
|---|---|---|---|---|---|---|---|
| RULE | the RULE 51 addendum, CORE §5 line, BUILD §5 line / no other rule edits, no new rule number (RULE 23) | Fable | the three files carry the rule once, cite by number | Fable (instruction files stay on Anthropic, CORE §3) | Opus | Sonnet (verifier agent) | Codex gpt-6-astra |
| CLEANUP | the moves in §3b STEP 2–3 / no live lane, no SKIPPY-TESTING, no `projects/ops` root strays | Fable | counts before and after in this file; zero live readers of any moved file | DeepSeek V4 Pro (`deepseek`) runs the move list | Qwen 3.8 (`qwen`) | Sonnet (verifier agent) | Codex gpt-6-astra |
| LOCK | the archive-lock hook, the ignore file, the live-pointer commit check, wiring / no other hook | Fable | U1–U5, U8 pass | Fable (control-plane `check-*` files are never handed to a vendor; check-routing-missed.mjs rule) | Opus | Sonnet (verifier agent) | Codex gpt-6-astra |
| BIRTH | the birth gate, wiring / no write-time gate changes | Fable | U6–U7 pass | Fable (control-plane) | Opus | Sonnet (verifier agent) | Codex gpt-6-astra |
| HUB | the retire job, the link row, the empty-row door / no board layout | Fable with the HUB lane owner | U9–U11 pass on the live Hub | GLM 5.3 (`zai`) for the job; HUB lane owner for the UI | DeepSeek V4 Pro | Sonnet (verifier agent) with a browser | se-blind-checker |
| INDEX | the retired-list generator / no hand edits | Fable | U12 passes | DeepSeek V4 Pro (`deepseek`) | Qwen 3.8 | Sonnet (verifier agent) | Codex gpt-6-astra |
**Contracts between lanes (FROZEN at plan time — change = a dated line in this file's SUMMARY):** the plan-like shape list lives once in the STEP 2 module and every lane imports it · the archive path is `projects/_archive/<YYYY-MM-DD>-<project>/` · a ticket is a `tickets.jsonl` row with `path`, `date`, `is_test:false` · the live-file order is card → registry → newest-unretired. **Buckets that share a goal message each other:** the HUB lane owner gets one dated line in `projects/ops/life-os/REGROUP-2026-09-08/plans/HUB/PLAN.proposed.txt` when STEP 6 opens and when it closes.
## 3b · Execution map — the Step map, then one STEP block per row
A task is DONE only when its review-ledger row is CLOSED by a reviewer that is not the builder.
**Step map (read this first):**
| Stage | # | Task (step name) | Needs (named artefact, or `none — start now`) | EXECUTOR (cheap model) | EXECUTOR BACKUP | CHECKER (different model) | CHECKER BACKUP | DONE-PROOF (runnable command) |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | The rule written once, this lane registered, carded and ticketed | none — start now | Fable (instruction files, CORE §3) | Opus | Sonnet | gpt-6-astra | `command grep -c "RULE 51 ↳ 2026-09-18" projects/ops/MACHINE-RULES.md && test -s projects/ops/project-files/PLAN.md` CREATED BY STEP 1 |
| 1 | 2 | The shared definition and the move list, measured; the harnesses written red | STEP 1 landed | Fable writes the module and the harnesses; DeepSeek runs `--measure` | Qwen | Sonnet | gpt-6-astra | `node projects/ops/skippy-jobs/_test-project-files.mjs` CREATED BY STEP 2 |
| 2 | 3 | The cleanup moved, with history and dated lines | STEP 2 list reviewed | DeepSeek (`deepseek`) | Qwen | Sonnet | gpt-6-astra | `node projects/ops/skippy-jobs/lib/project-files.mjs --measure --json` CREATED BY STEP 2 |
| 2 | 4 | The lock: hook, ignore file, commit check, wired, red then green | STEP 1 landed; STEP 2 harnesses | Fable (control-plane) | Opus | Sonnet | gpt-6-astra | `node projects/ops/skippy-jobs/lib/check-archive-lock.mjs --selftest && node projects/ops/skippy-jobs/_test-archive-lock-wired.mjs` CREATED BY STEP 4, the wiring test CREATED BY STEP 2 |
| 2 | 5 | The birth gate, wired, red then green | STEP 2 module and harnesses | Fable (control-plane) | Opus | Sonnet | gpt-6-astra | `node projects/ops/skippy-jobs/lib/check-project-file-birth.mjs --selftest && node projects/ops/skippy-jobs/_test-birth-gate-wired.mjs` CREATED BY STEP 5, the wiring test CREATED BY STEP 2 |
| 3 | 6 | Hub PM: the link row, the empty-row door, the retire job | STEP 2 module; HUB lane owner's dated line | GLM 5.3 (`zai`) job; HUB owner UI | DeepSeek | Sonnet with browser | se-blind-checker | `node projects/ops/skippy-jobs/jobs/project-retire.mjs --dry-run` CREATED BY STEP 6 |
| 3 | 7 | The retired index generated | STEP 6 job | DeepSeek (`deepseek`) | Qwen | Sonnet | gpt-6-astra | `node projects/ops/skippy-jobs/jobs/project-retire.mjs --index-only && test -s projects/ops/artifacts/project-status/RETIRED-PROJECTS.md` CREATED BY STEP 7 |
| 4 | 8 | Postmortem, written into this file | STEPS 1–7 closed | Fable | Opus | Sonnet | gpt-6-astra | `command grep -c "^## POSTMORTEM" projects/ops/project-files/PLAN.md` |
### STEP 1 — The rule written once, this lane registered, carded and ticketed
**FOR NICK:** the rule you stated exists in the one rulebook, and this project has its one card and its one file. · **Tier:** FRONT
**Start when:** none — start now.
**Builder:** Fable (instruction files stay on Anthropic, CORE §3) · **Builder backup:** Opus · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** `projects/ops/MACHINE-RULES.md` (one ↳ addendum under RULE 51), `projects/ops/CORE.md` §5 (one sentence citing RULE 51), `projects/ops/blocks/BUILD.md` §5 (one sentence citing RULE 51), `projects/ops/artifacts/project-status/registry.json` (one row), this file. **Never** `CLAUDE.md`, `RULEBOOK.md`, `FILE-STANDARD.md` (root-ticket gate, owner: Nick).
**Do exactly this:**
0. Create `projects/ops/project-files/` in the private worktree and write this plan there as `PLAN.md` with its `STEPS.json` beside it; from then on "this file" means that path. Write the walk-away row `lane:project-files` into `projects/personal/skippy-app/ala-state/work-threads.json` (kind `lane`, person `nick`, pointer `projects/ops/project-files/PLAN.md`).
1. Under RULE 51 in `projects/ops/MACHINE-RULES.md` add one paragraph beginning `↳ RULE 51 ↳ 2026-09-18 addendum (Nick, 2026-09-18):`, quoting his words above, stating what RULE 51 lacked: the card names the one live file (`project_file`); a sub-project is a child card with its own single file; the one mandated second file is the spec (RULE 29) and the shared update command's own `STEPS.json`; anything else beside a live file needs an approved ticket naming it; closing the card archives the file under `projects/_archive/<YYYY-MM-DD>-<project>/` with history; the archive and the old workspace are locked to every agent's tool reads and searches without a ticket, and git history is not sealed and is not pretended to be. No new rule number (RULE 23).
2. In CORE §5 and BUILD §5 add one sentence each that states the rule in one reading and cites RULE 51.
2b. File one ticket per new file this plan births (`node projects/ops/skippy-jobs/lib/request-ticket.mjs <path> --reason "project-files lane, Nick 2026-09-18: sounds good - triad your ideas and act"`): this plan and its `STEPS.json`, the STEP 2 module and three harnesses, the two STEP 4 hooks and the root ignore file, the STEP 5 gate, the STEP 6 job and its Hub lane file `LANE-PROJECT-FILE-LINK-<date>.md`, and the STEP 7 list — RULE 31 is a separate gate from the lane's approval. The documentation gate re-arms at 23:55Z on 2026-09-18: from then every new `.md` needs its ticket before it is written, so the tickets are filed here, first.
3. Add the registry row `{slug:"project-files", name:"OPS: Project files - One card, one file, locked archive", dir:"projects/ops/project-files", planFile:"PLAN.md", publicOk:true, publicOkReason:"<the real result of the registry's own grep over the final PLAN.md, written as every other row writes it: the count and what each hit is>"}`.
4. Open the card on the AI Builds board as agent `fable-project-files` with a due date of 2026-09-21, `session_id` and `session_title`, and bind `project_file` to this plan's path with the robot bearer; write the card id into §5 of this file.
5. Land from the private worktree `.claude/worktrees/project-files` and push to main.
**DEFINITION OF DONE:** the RULE 51 addendum appears once in MACHINE-RULES.md, RULE 51 is cited once each in CORE §5 and BUILD §5, the tickets are queued, and the registry row and the bound card exist.
**PROOF:** `command grep -c "RULE 51 ↳ 2026-09-18" projects/ops/MACHINE-RULES.md` → `1`; `command grep -c "RULE 51" projects/ops/CORE.md` → `2` (one pre-existing in §4, one new in §5); `command grep -c "RULE 51" projects/ops/blocks/BUILD.md` → `1`; `node -e "const r=require('./projects/ops/artifacts/project-status/registry.json'); console.log(r.filter(x=>x.slug==='project-files').length)"` → `1` · **FAILS IF:** any count differs from the number stated, or the card read back by id has no `project_file`.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 2 — The shared definition and the move list, measured; the harnesses written red
**FOR NICK:** the machine can say exactly which files are clutter and which one is live, before anything moves; and every later step already has the test that will judge it. · **Tier:** FRONT
**Start when:** STEP 1 landed on main (`git log --oneline -1 -- projects/ops/MACHINE-RULES.md` shows the addendum commit).
**Builder:** Fable writes the module (two control-plane gates import it) and the harnesses (test authoring is never cheap, MODEL-MATRIX); DeepSeek V4 Pro runs the measurement · **Builder backup:** Qwen 3.8 · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** in `projects/ops/skippy-jobs/lib/` the new module `project-files.mjs`; in `projects/ops/skippy-jobs/` the new harnesses `_test-project-files.mjs`, `_test-archive-lock-wired.mjs`, `_test-birth-gate-wired.mjs`; this file. **Never** any file under `projects/` the list names — this step only lists. Record `git rev-parse origin/main` in SUMMARY as the BEFORE sha for STEP 3's deletion proof.
**Do exactly this:**
1. Write the module exporting: `PLAN_LIKE` (the basename shapes: `PLAN*.md`, `PLAN.proposed.txt`, `PROJECT.md`, `plan.md`, `PROGRESS*.txt|md`, `HANDOFF*`, `HAND-OFF*`, `HANDBACK*`, `PLAN-CHANGES*.md`, `STATE*.md`, `STATUS*.md`, `QUESTIONS*.md`, `ASSUMPTIONS*.md`, `CHECK.txt`, `*-REPORT.md`, `POSTMORTEM*`, `WORKER-*`, `VERIFIER-*`, `AUDIT-*`, `SWEEP-BATCH-*`, `CAPABILITY-*`), `ALLOWED_BESIDE` (`SPEC*.md` — the one mandated second file, RULE 29 — and `STEPS.json`, the shared update command's own data), `RETIRED_BY_NAME` (`.bak`, `.pre-<digits>`, `-OLD`, `STALE`, `SUPERSEDED`, `RETIRED`, `ARCHIVED`, `OBSOLETE`, `.orig`), `retiredByBanner(path)` (first 8 lines carry RETIRED / SUPERSEDED / ARCHIVED / DO NOT USE as a banner; generated mirrors and correction notes excluded), `PROTECTED` (never listed, whatever its name: every path a registry row names as `planFile` or `stateFile`, every path a live Hub card names as `project_file`, every file named by `projects/ops/agents/roster.json` as generated output, and every `projects/…` path cited inside `CLAUDE.md`, `AGENTS.md`, `projects/ops/CORE.md` or any file under `projects/ops/blocks/`, resolved by grep at measure time), `liveFileOf(folder, cards, registry)` (card → registry → the plan whose newest dated line inside the text is latest; a folder the dates cannot settle goes to a HAND-REVIEW list, never to a mtime guess), `EXCLUDED` (`projects/_archive/`, the Hub repository's folder under projects/business whole — a nested repository the parent ignores, `node_modules/`, `.git/`, `**/.claude/worktrees/`, `projects/ops/.cheap-task-snapshots/`, `plans/SKIPPY-TESTING/`; the files at `projects/ops/` root itself are LISTED with `why: "second-pass-hold"` and never moved by `--apply`, every lane folder whose plan-like files have a commit within the last 3 days by `git log -1 --format=%ct -- <those files>` — never a file's mtime, which a fresh checkout resets — and every path `git check-ignore` matches — a gitignored side-copy is never moved and never added), `--measure --json` reading `git ls-files` only and printing `{folders, planFiles, multiPlanFolders, extraPlans, companions, bannerRetired, nameRetired, ignoredSideCopies, unboundPlans:[…], handReview:[…], moveList:[{from,to,why}]}`; an unretired plan with no card and no registry row is UNBOUND and is listed, never moved — STEP 6 binds or retires it through its card; `to` is `projects/_archive/<date of the run>-<project>/<basename>` where `<project>` is the folder's basename (`REGROUP-<lane>` for a REGROUP lane), and a destination that already exists gets a `.dup-<timestamp>` suffix so nothing is ever overwritten.
2. Write the three harnesses so that each FAILS today: `_test-project-files.mjs` (fixtures: a live PLAN.md is never listed; a PROGRESS.txt beside it is; a `.bak` is; a lane written today is excluded; `STEPS.json` is never listed; prints `PASS 5/5` only when all hold), `_test-archive-lock-wired.mjs` and `_test-birth-gate-wired.mjs` (the first asserts the hook is present in the tracked `.claude/settings.json` and only WARNS about the per-machine `~/.claude/settings.json`, so it fails for the code and never for the machine; the second asserts `ZION/lib/pre-commit-parity.sh` calls the gate; each fails until STEP 4 / STEP 5 wire it).
3. Run `--measure --json`, write the counts into this file's SUMMARY as the BEFORE line, and read every `moveList` row whose `why` is `extra-plan` by hand (Fable) before STEP 3 starts.
**DEFINITION OF DONE:** the module exists, `_test-project-files.mjs` passes, the two wiring harnesses exist and fail red, and the move list is written into this file's SUMMARY with the BEFORE counts.
**PROOF:** `node projects/ops/skippy-jobs/_test-project-files.mjs` → last line `PASS 5/5`; `node projects/ops/skippy-jobs/_test-archive-lock-wired.mjs; echo $?` → the literal line `RED: check-archive-lock.mjs is not wired in .claude/settings.json` and then `1` (red until STEP 4; a crash prints no such line); `node projects/ops/skippy-jobs/lib/project-files.mjs --measure --json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const j=JSON.parse(s);console.log(j.moveList.length>0&&j.moveList.every(r=>!/SKIPPY-TESTING/.test(r.from)))})"` → `true` · **FAILS IF:** any fixture fails, a wiring harness is already green, or any move-list row names SKIPPY-TESTING or a live lane.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 3 — The cleanup moved, with history and dated lines
**FOR NICK:** the clutter is out of every live folder and in the archive with its history; nothing was deleted. · **Tier:** FRONT
**Start when:** STEP 2 closed and Fable has read the extra-plan rows (a dated line in SUMMARY says so).
**Builder:** DeepSeek V4 Pro (`deepseek`) runs `node projects/ops/skippy-jobs/lib/project-files.mjs --apply` CREATED BY STEP 2 · **Builder backup:** Qwen 3.8 · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** every `from` path in the move list (git mv only), the live file in each affected folder (one appended dated line), this file. **Never** `plans/SKIPPY-TESTING/**`, any live lane's companion, anything at `projects/ops/` root.
**Do exactly this:**
1. In the private worktree, run `--apply`: for each row, `git mv <from> projects/_archive/2026-09-18-<project>/<basename>`; untracked rows are moved with `mv` then `git add`; after each folder, append to its live file one line naming the archive FOLDER, never its full path (the live-pointer check would otherwise refuse the commit): `2026-09-18 — <n> files archived (<basenames>) → archive folder 2026-09-18-<project>`; the commit message carries the full archive path (the lock allows `git commit`, `git add`, `git mv` and `git log` with an archive path; the appended line was run through `ZION/lib/check-no-scaffolding.mjs --passages` on 2026-09-18 and flags nothing).
2. Run `--measure --json` again and write the AFTER counts into SUMMARY beside the BEFORE counts.
3. Commit in batches of one project folder each, push, and send each live lane whose companions were left in place one cross-session message naming the rule and the files.
4. The gitignored side-copies (`ignoredSideCopies` in the measurement, 2,544 on 2026-09-18, vault backups among them) are never moved, never added and never deleted by this lane: deletion is one of the four acts, so one `request-act.mjs --act destruction` is filed naming the count and total size, and the list stays in the measurement output until Nick taps.
**DEFINITION OF DONE:** every move-list row is moved with history, every affected live file carries its dated line, AFTER counts are in SUMMARY, and no file was deleted.
**PROOF:** `node projects/ops/skippy-jobs/lib/project-files.mjs --measure --json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const j=JSON.parse(s);console.log(j.moveList.length)})"` → `0`; `git log --diff-filter=D --name-only <the BEFORE sha in SUMMARY>..origin/main -- projects/ | wc -l` → `0` · **FAILS IF:** the move list is not empty, or any path shows as deleted rather than renamed.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 4 — The lock: hook, ignore file, commit check, wired, red then green
**FOR NICK:** no agent can read or search the archive or the old Claude folder without a ticket, and a live file still opens. · **Tier:** FRONT
**Start when:** STEP 1 landed (the addendum exists to cite) and STEP 2's wiring harness exists.
**Builder:** Fable (control-plane `check-*` files are never handed to a vendor, check-routing-missed.mjs rule) · **Builder backup:** Opus · **Checker:** Sonnet verifier agent, which also proves RED before wiring · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** in `projects/ops/skippy-jobs/lib/` the new hooks `check-archive-lock.mjs` and `check-no-live-pointer-into-archive.mjs`; a new root `.ignore`; `.claude/settings.json` (one PreToolUse entry); `~/.claude/settings.json` on this Mac (one entry); `ZION/lib/pre-commit-parity.sh` (one call); this file. **Never** any other hook or gate.
**Do exactly this:**
1. Before wiring, the checker records RED: the Read tool on `projects/_archive/JOBS-OFF-THE-MAC-2026-08-08.md` returns content; `command grep -rl "JOBS-OFF-THE-MAC" projects/ | head -1` prints an archive path.
2. Write the lock hook with ONE resolver shared by every tool path: each candidate (`tool_input.file_path` for Read/Edit/Write/NotebookEdit, `tool_input.path` and `tool_input.pattern` for Grep/Glob, every path-shaped token of `tool_input.command` for Bash) is resolved to an absolute path (`~` and relative paths against the repo root), and is LOCKED when its segments contain `/projects/_archive/` (so worktree copies count and `projects/ops/agents/_archive/` does not) or its root is `/Users/<anyone>/Documents/Claude` exactly (never `Claude 2.0`). A locked target is refused (exit 2) unless `tickets.jsonl` holds a non-test row for the exact path or its archive folder dated within 24 hours; Bash `git mv`/`mv`/`mkdir -p`/`git add`/`git commit`/`git log` whose locked tokens are arguments, `node …/request-ticket.mjs <locked path>` (the door itself) and `ls projects/_archive` with no deeper path are allowed; the locked test is on path SEGMENTS after resolution, never `startsWith`; an unparseable payload or a command with no locked token exits 0 before any file or git read; `--selftest` runs the fixture cases, each named (archive Read refused; `cat` of an archive path refused; `/Users/nickdeck/Documents/Claude/anything` refused; the archive copy inside any worktree folder (`<any worktree>/projects/_archive/y.md`) refused; `/Users/nickdeck/Documents/Claude 2.0/projects/ops/CORE.md` allowed; `projects/ops/agents/_archive/x` allowed; a live plan allowed; a ticketed archive read allowed; `git mv` into the archive allowed; `git commit -m` naming an archive path allowed; `node …/request-ticket.mjs projects/_archive/x --reason y` allowed) and exits 1 on any wrong answer, and times a miss under 50 ms. STATED LIMIT, written into the addendum and the refusal text: git history (`git show`, `git log -p`) and a path assembled from a variable are not caught; the lock is a guard on tool reads and search, not a seal.
3. Write the root `.ignore` (ripgrep reads it; the Grep tool is ripgrep) containing `projects/_archive/`; `.vexpignore` already carries the same line for the other indexer and is left as is.
4. Write the live-pointer check as a RATCHET, the same before-versus-after shape `pre-commit-parity.sh` already uses for scaffolding: for every staged text file outside the archive, refuse (exit 1) only a line containing `projects/_archive/` that this commit ADDS (absent from `HEAD:` of the same file), unless the file is on the allowlist (this plan, the retired list, `MACHINE-RULES.md`, `CORE.md`, `BUILD.md`, `DATA-RULES.md`, the ignore files, the two hooks, their tests, `pre-commit-parity.sh`); the 406 existing references stay untouched and uncounted; add one call to `ZION/lib/pre-commit-parity.sh`.
5. Wire the hook in the tracked `.claude/settings.json` (matcher `Read|Grep|Glob|Edit|Write|MultiEdit|NotebookEdit|Bash`) — that file reaches every machine on the next pull and is the enforcement; `~/.claude/settings.json` is per machine and is NOT relied on: this Mac's copy gets the same entry by hand for sessions started outside the repo folder, other machines' copies are not touched and the harness does not read them; STEP 2's wiring harness turns green. The hunt for whatever recreated `~/Documents/Claude/` runs under a ticket for that path, filed the same day.
6. Checker records GREEN in a fresh session: U1, U3 refused with the message; U2 zero archive hits; U4 allowed after a ticket; U5 allowed.
**DEFINITION OF DONE:** the selftest and the wiring test pass, RED and GREEN are both recorded by the checker with the exact refusal text, and a live file reads.
**PROOF:** `node projects/ops/skippy-jobs/lib/check-archive-lock.mjs --selftest && node projects/ops/skippy-jobs/_test-archive-lock-wired.mjs` → last line `PASS` (hook CREATED BY STEP 4 is cited from the step map; the wiring test CREATED BY STEP 2); the checker's Grep TOOL (not `command grep`, which reads no ignore file) for the word `JOBS-OFF-THE-MAC` repo-wide → no hit under `projects/_archive/`, and for a phrase only this plan contains → this file (the ignore file hides the archive and nothing live) · **FAILS IF:** any selftest case answers wrong, the tracked settings file lacks the entry, or a live-file Read is refused.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 5 — The birth gate, wired, red then green
**FOR NICK:** a second plan file cannot be committed beside a live one unless a ticket or the registry names it. · **Tier:** FRONT
**Start when:** STEP 2's module and wiring harness exist on main.
**Builder:** Fable (control-plane) · **Builder backup:** Opus · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** in `projects/ops/skippy-jobs/lib/` the new gate `check-project-file-birth.mjs`; `check-plan-proliferation.mjs` (its header only: the `.bak` sibling advice is deleted under RULE 54 and the quartet comment now says those files are ticket-gated at commit by this gate); `ZION/lib/pre-commit-parity.sh` (one call); this file. **Never** `check-md-governance-gate.mjs`.
**Do exactly this:**
1. Checker records RED in a scratch clone: a second `PLAN-X.md` staged beside `PLAN.md` commits today, and so does one `git mv`-ed in from elsewhere.
2. Write the gate: for each staged added OR renamed-in file (`git diff --cached --name-status --diff-filter=AR`, judging the destination path of a rename) whose basename matches `PLAN_LIKE` from the STEP 2 module, and whose folder already holds another plan-like file in HEAD or the index, refuse (exit 1) unless `registry.json` names the path as `planFile` or `stateFile`, or `tickets.jsonl` holds a non-test row for the exact path dated within 7 days; `ALLOWED_BESIDE` (`SPEC*.md`, `STEPS.json`) is never gated; the message names the existing file, RULE 51 and `node projects/ops/skippy-jobs/lib/request-ticket.mjs <path> --reason "<why>"`; `--selftest` builds a temp repo and proves refused / renamed-in refused / ticketed-allowed / registry-named allowed / first-plan-allowed / SPEC-beside-plan allowed.
3. Add one call in `ZION/lib/pre-commit-parity.sh`; STEP 2's wiring harness turns green.
4. Checker records GREEN: the same scratch commit is refused with the message; a ticketed one lands.
**DEFINITION OF DONE:** selftest and wiring test pass; RED and GREEN recorded by the checker.
**PROOF:** `node projects/ops/skippy-jobs/lib/check-project-file-birth.mjs --selftest && node projects/ops/skippy-jobs/_test-birth-gate-wired.mjs` → last line `PASS` (gate CREATED BY STEP 5 is cited from the step map; the wiring test CREATED BY STEP 2) · **FAILS IF:** any case answers wrong or `pre-commit-parity.sh` lacks the call.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 6 — Hub PM: the link row, the empty-row door, the retire job
**FOR NICK:** every AI Builds card shows its one file as a link, and closing a card is what retires its file. · **Tier:** FRONT
**Start when:** STEP 2's module exists on main and the HUB lane owner has answered the dated line in their plan (or 24 hours have passed, in which case Fable makes the one-row UI change under the HUB block's own lane-file rule).
**Builder:** GLM 5.3 (`zai`) writes the retire job; the HUB lane owner (or Fable) makes the UI row and the door change · **Builder backup:** DeepSeek V4 Pro · **Checker:** Sonnet verifier agent with a browser · **Checker backup:** se-blind-checker
**Files you may touch:** in `projects/ops/skippy-jobs/jobs/` the new job `project-retire.mjs`; `projects/ops/skippy-jobs/runner.mjs` (one row); the Hub repository's `app/js/tasks.js` (the "Project file" row); the Hub repository's `app/functions/api/tasks.js` (the AI Builds create door); a `LANE-PROJECT-FILE-LINK-<date>.md` in the Hub repo naming those two files; this file. **Never** any other Hub screen; never a live client card (RULE 46).
**Do exactly this:**
1. The job's `--dry-run`: list cards on `ai-builds` that are Done or superseded and whose `project_file` still exists live; `--apply`: for each, run the STEP 3 move for that one file, set the registry row's `retired` (the date), `retiredBecause` (`card <id> closed <date>`) and `supersededBy` (when the card carries one), and regenerate the retired list (STEP 7); the card's `project_file` is NOT repointed — the Hub refuses that through `edit` (403) and `bind_project` (409), git history holds the old path, and the retired list maps old path → archive folder; register ONLY `--dry-run` in `runner.mjs` hourly beside `larry-hub-sync` (it lists what is due and writes nothing); `--apply` is run by this lane from its private worktree, never by the scheduler, and passes the run's own date. A `retire_project` robot action that repoints is proposed to the HUB lane owner in the handoff line, not built here.
2. In `app/js/tasks.js`, render the "Project file" row as a link to `https://github.com/nick-deck/deck-brain-2/blob/main/<path>` where `<path>` is the archive path from the retired list when the project's registry row is `retired`, else `project_file` (a retired card must never render a 404), and, when the field is empty, the text `no project file — bind one`. The repository is private: the link opens only for a browser signed into a GitHub account with access — confirmed with Nick once (§1a row 4), never assumed.
3. In the door, refuse an agent-session `create` on `ai-builds` without `project_file`, message naming RULE 51.
4. The link needs the registry's slug for the card's file, and the browser cannot read the registry: the Hub build copies the registry's `slug`, `dir` and `planFile` columns into a static asset in `dist/` (the HUB block's own pattern for a computed value), the card detail fetches it once and maps `project_file` to `https://hs-project-status.pages.dev/<slug>.html`; a file with no row shows the path and "register it".
5. Push to deck-business main from the Hub's real folder (that lane's rule); after the edge rolls, open one card as Nick in the test browser, click the link, screenshot. The lane file `LANE-PROJECT-FILE-LINK-20260918.md` is on the Hub repository's main (Nick, 2026-09-18: "1 yes 2 yes").
**DEFINITION OF DONE:** the link opens the live file from a card; a card without a file is refused at the door; the dry run lists the right cards.
**PROOF:** `node projects/ops/skippy-jobs/jobs/project-retire.mjs --dry-run` → exit 0 and a JSON list (job CREATED BY STEP 6 is cited from the step map); the checker's browser screenshot shows the link and the opened file · **FAILS IF:** the row is plain text on the live Hub, or an agent can open an AI Builds card with no `project_file`.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
**Handoff (if any):** the moment this step closes, post one dated line into `projects/ops/life-os/REGROUP-2026-09-08/plans/HUB/PLAN.proposed.txt`: `STEP 6 closed <date> — every AI Builds card shows its project file as a link; the door refuses a card without one; proposed for the HUB lane: a robot-only retire_project action that repoints project_file, and a fix to the HUB path block, which cites KANBAN spec §10–§12 that do not exist (the spec ends at §9.18).`
### STEP 7 — The retired index generated
**FOR NICK:** the assistants can tell you when a programme was retired and where it went, without digging up old context. · **Tier:** FRONT
**Start when:** STEP 6's job exists on main.
**Builder:** DeepSeek V4 Pro (`deepseek`) · **Builder backup:** Qwen 3.8 · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** the job's `--index-only` branch (job CREATED BY STEP 6); the generated list `RETIRED-PROJECTS.md` in `projects/ops/artifacts/project-status/`; this file. **Never** hand-edit the generated file.
**Do exactly this:**
1. `--index-only` writes the list: a generated banner, then one line per retired project from registry rows with `retired` plus every `projects/_archive/<date>-<project>` folder: `- <name> — retired <date> — <one clause> — projects/_archive/<folder>/`.
2. The archive-lock allowlist (STEP 4) already names the list as the one file that may point into the archive.
**DEFINITION OF DONE:** the file exists, is generated, and lists every retired project with its date and archive folder.
**PROOF:** `node projects/ops/skippy-jobs/jobs/project-retire.mjs --index-only && command grep -c "^- " projects/ops/artifacts/project-status/RETIRED-PROJECTS.md` → the number the generator itself prints as `distinct retired projects: <n>` (the distinct slugs in the union of registry `retired` rows and dated archive folders; a project with both is one line) (list CREATED BY STEP 7 is cited from the step map) · **FAILS IF:** the counts differ or the file lacks the generated banner.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
### STEP 8 — Postmortem, written into this file
**FOR NICK:** what failed, what confused, what to keep — in the one file, so the next lane starts smarter. · **Tier:** FRONT
**Start when:** STEPS 1–7 carry a `VERIFIED:` line.
**Builder:** Fable · **Builder backup:** Opus · **Checker:** Sonnet verifier agent · **Checker backup:** Codex gpt-6-astra
**Files you may touch:** this file (a `## POSTMORTEM` section), `.claude/skills/plan/references/failure-registry.md` (append rows for any new failure mode). **Never** any other file.
**Do exactly this:**
1. Write `## POSTMORTEM` here: what failed, what was confused, what to keep; "nothing worth extracting" is a valid answer.
2. Append each new failure mode to the failure registry in its four-column shape.
**DEFINITION OF DONE:** the section exists and every new failure mode is in the registry.
**PROOF:** `command grep -c "^## POSTMORTEM" projects/ops/project-files/PLAN.md` → `1` · **FAILS IF:** 0.
**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.
**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.
**Step-writing rules:** every step names the literal command and the literal expected output — "verify it works" is a defect · as many steps as the North Star needs, no more · red-first for any fix step · builds and per-step checks on the cheap tier by name; the overseer never builds; the plan is written and the FINISH LINE signed off on Anthropic or OpenAI.
## 4 · Regret Check (the registry failures this build is actually exposed to)
| Failure mode (registry entry) | The measure in THIS plan that prevents it | Where it lives (section / artifact / gate) |
|---|---|---|
| A second system was built because the first was invisible | Gate Zero names the registry row, the two existing gates, the Hub's `project_file` field and the ticket ledger, each extended, none copied | §0 Ownership check; §3 contracts |
| Files were archived but their citations kept pointing at them | The commit check refuses a live line pointing into the archive; each move appends the dated line to the live file | STEP 3, STEP 4 (the live-pointer check) |
| An enforcement gate covered fewer paths than its rule, or failed open | The lock matches the ACT (a read of an archive path) across Read, Grep, Glob and Bash, fails closed on a recognised target, and the birth gate runs at commit where Codex and Bash writes also pass | STEP 4, STEP 5 |
| A check existed that could not fail | Every hook carries a `--selftest` with a wrong-answer exit, and the checker records RED before wiring and GREEN after | STEP 4 step 1 and 6, STEP 5 step 1 and 4 |
| A test existed but nothing ran it | The wiring tests are added to the nightly runner beside `_test-approval-gate-is-wired.mjs` in the same landing | STEP 4, STEP 5 |
| A new rule was written as prose inside its own fix, with nothing enforcing it | the RULE 51 addendum lands in STEP 1 and its two mechanical gates land in STEPS 4–5 of the same plan; the finish line requires both | FINISH LINE (a), (c), (d) |
| An absence was asserted without opening the store that would hold it | The move list is a measured JSON from the module, reviewed by hand, and every "no live reader" claim is a `command grep` the checker re-runs | STEP 2 step 3, STEP 3 |
| A staleness/freshness check used the wrong proxy | Live-lane exclusion uses the folder's own write time plus the owner's word, never a registry flag alone; a lane's companions are left, not moved, when in doubt | §Already true, STEP 2 `EXCLUDED` |
| Novel: the lock hook slows every Bash call | The hook returns on a regex miss before any file or git read; the selftest times a miss under 50 ms | STEP 4 step 2 |
| Novel: a live lane's companion moved mid-run | Lanes written in the last 3 days and SKIPPY-TESTING are excluded by name; owners get a message, not a move | STEP 2 `EXCLUDED`, STEP 3 step 3 |
## 5 · Topology and roles
- **OVERSEER-AUTHORITY:** none named (`projects/ops/OVERSEER-AUTHORITY.md` CURRENT HOLDER: "NO SEAT IS NAMED", 2026-08-28). **The four approval classes (money leaving · credential rotation · irreversible destruction · a message sent as Nick) and the floor (logins · credentials, tokens and keys · government IDs · card, bank and routing numbers) never move on the overseer's word.**
- Thread layout: one overseer thread (this session); builders and checkers as dispatches; the HUB lane owner reached by a dated line in their plan and a cross-session message
- Overseer: Fable · Workers: DeepSeek V4 Pro (`deepseek`), Qwen 3.8 (`qwen`), GLM 5.3 (`zai`); Sonnet verifier agents check · Cap: 8 per session, ~40 machine-wide
- State files location: this file only; `STEPS.json` beside it is the shared update command's own data
- **Board card id:** `nt-20260918-175745-3217` (AI Builds board, owner `fable-project-files`, bound to this file 2026-09-18)
- **Artefact consumers:** the move list → Fable's review then STEP 3; the refusal messages → every agent's tool result; the retired list → the assistants' brain push; the dated handoff line → the HUB lane's plan (arrival proven by reading it back)
- **Write-contention (parallel lanes in a shared checkout):** this lane writes only from `.claude/worktrees/project-files`; the shared checkout is never edited; the Hub change is written in the Hub repo's own folder under its lane file
**Per-stage topology — counts DECLARED at plan time (machine-gated: a number in every row):**
| Stage | Overseer | Sub-overseers | Workers |
|---|---|---|---|
| 1 | 1 | 0 | 3 |
| 2 | 1 | 0 | 3 |
| 3 | 1 | 0 | 3 |
| 4 | 1 | 0 | 1 |
**The walk-away contract — a stranger resumes the drive from files alone:**
- **STATE FILE:** `projects/ops/project-files/PLAN.md` (this file's `## STEPS` and `## SUMMARY`)
- **HEARTBEAT ROW:** `lane:project-files` in `projects/personal/skippy-app/ala-state/work-threads.json`, written by STEP 1
- **MORNING-REPORT LINE:** the first sentence of this file's `## SUMMARY`, rewritten at every stopping point (`projects/ops/walkaway/REPORT.md` is a dated 2026-08-23 report, not a rolling one, so nothing is written there)
## 6 · Evals — what "working" means, decided now
| Capability | Check (exact command or procedure) | Pass looks like |
|---|---|---|
| 1 refuse an archive read | Read tool on `projects/_archive/JOBS-OFF-THE-MAC-2026-08-08.md` in a fresh session | refusal text names the path, RULE 51, the ticket command |
| 2 ticketed read allowed | `node projects/ops/skippy-jobs/lib/request-ticket.mjs projects/_archive/JOBS-OFF-THE-MAC-2026-08-08.md --reason "eval"`, approve, Read again | content returned |
| 3 live file never refused | Read tool on this plan file | content returned |
| 4 archive out of search | Grep tool for a word only the archive holds, repo-wide | zero hits under `projects/_archive/` |
| 5 second plan refused at commit | the birth gate's `--selftest` case 1 | `refused` |
| 6 live pointer refused at commit | stage a scratch `.md` containing `projects/_archive/x`; `git commit` | refused, line named |
| 7 cleanup with history | `git log --follow --oneline -- projects/_archive/2026-09-18-<project>/<file> | wc -l` | greater than 1 |
| 8 link on every card | browser: open an AI Builds card, click "Project file" | the file opens on GitHub |
| 9 close retires | mark a test card Done, run the retire job with `--apply` | file moved with history, registry row retired, list regenerated |
| 10 retired list | `command grep -c "^- " projects/ops/artifacts/project-status/RETIRED-PROJECTS.md` | equals the generator's own `distinct retired projects` count |
## If you get stuck (all steps)
Before writing "blocked": (1) re-read the step's START WHEN line — most "stuck" is a misread gate, (2) try a concrete workaround, (3) write one line to the overseer naming the ONE missing artefact. Then keep working every other step whose inputs exist. Never idle on a blocker; never end a turn waiting on a background result.
## Your loop
Every pass: every step whose START WHEN inputs exist and which is not yet CLOSED is running, up to the cap → each builder runs its own PROOF, hands to its checker → PASS closes it, FAIL loops it → repeat until the FINISH LINE is proven.
## SUMMARY — a few plain-English lines, read by the status generator
The rule Nick confirmed on 2026-09-18 is now written once in the rulebook as a dated addendum to RULE 51, and the two path blocks point at it. This project has its one card on the AI Builds board and this one file, and the plan was attacked by two independent readers before anything landed; every finding that would have moved or exposed a live file was folded in. Nothing has moved yet. Steps 1 to 3 are verified by checkers who did not build them. The rule is in the rulebook; the clutter is archived with history (239 files, 0 deleted); the lock, the ignore file, the pointer ratchet and the birth gate are landed and wired and await their checkers' word; the retire job's hourly dry run is registered and the retired list is generated (73 entries). The Hub's own two changes — the card row as a link to the project's status page, and a card needing its file at birth — are handed to the HUB lane with a 24-hour clock before this lane makes the link row itself.
BEFORE (2026-09-18, printed by the shared module from `git ls-files` on origin/main `a5b3d3d7b47f77dfaa5b626e43129e788c59a1d8`, the sha STEP 3's deletion proof counts from): 87 project folders hold a plan; 113 plan files; 6 folders hold more than one; 214 companion files sit beside a plan; 33 files carry a retired or superseded banner; 14 are retired by name; 108 paths are protected (registry, live cards, roster, the instruction files' own citations); 209 live Hub cards read. Move list: 247 rows — 193 companions, 29 banner-retired, 3 banner-retired plans whose registry row is flipped, 14 retired by name, 8 held at the ops root and never moved. 22 unretired plans have no card and no registry row and are listed for STEP 6, not moved; 22 retired-looking files are registry-named and stay; 22 folders were committed to in the last 3 days and are left alone. 84 gitignored side-copies (4.4 MB, vault backups among them) sit on the main checkout and are never touched by this lane.
UNBOUND PLANS (no card, no registry row — STEP 6 binds each to a card or retires it through one; none moves before that): projects/ops/agent-fleet/PLAN-cheap-model-rollout.md; projects/ops/agent-fleet/PLAN.md; projects/ops/assistants-replan/PLAN-1-SKIPPY.md; projects/ops/assistants-replan/PLAN-6-KANBAN-PM.md; projects/ops/assistants-replan/PLAN-7-APP-INTERFACE.md; projects/ops/assistants-replan/PLAN-PROGRAMME.md; projects/ops/zion/PLAN-FA-1-family-app-cleanup.md; projects/ops/zion/PLAN-ZION-12-team-access.md; projects/ops/zion/PLAN-ZION-14-security-audit.md; projects/ops/zion/PLAN-ZION-2-files-and-folders-management.md; projects/ops/zion/PLAN-ZION-4-hub-audit.md; projects/ops/zion/PLAN-ZION-8-approval-system-update.md; projects/ops/zion/PLAN-ZION-PROGRAMME.md; projects/personal/family-app/PLAN-CALENDAR-EVENT-SHEET.md; projects/personal/family-app/PLAN-CALENDAR-PEARL.md; projects/personal/family-app/PLAN-CALENDAR-PHASE-C.md; projects/personal/family-app/PLAN-FINANCES-WATCH-LIST.md; projects/personal/family-app/PLAN-HOME-PEARL.md; projects/personal/family-app/PLAN-PEARL-HEALTH.md; projects/personal/family-app/PROJECT.md; projects/personal/health/engine/brain-routing/PLAN-CUTOVER.md; projects/personal/health/engine/brain-routing/PLAN.md.
2026-09-18 — Nick approved in chat ("1 yes 2 yes") the destruction request filed through the one door for the gitignored side-copies that existed only on this Mac outside the record: 54 files (1.4 MB; the earlier count of 84 used the wider name pattern this lane later narrowed), among them three vault backups and two old sign-in token copies, were deleted with a last check that each was untracked and gitignored; the record and the archive were untouched. Nick also approved the Hub lane file for STEP 6 in the same words.
AFTER (2026-09-18, same module, same repo, after the moves): 84 project folders hold a plan; 107 plan files; 20 companion files remain beside a plan and every one is registry-protected or inside a lane committed to in the last 3 days; 1 banner-retired file remains (registry-protected); 0 retired by name; move list 8 rows, all `second-pass-hold` at the ops root. Moved: 239 files from 70 folders into 70 dated archive folders, by `git mv`, in 28 commits; 3 registry rows flipped to retired with `archivedTo`; 44 live files carry the dated line. Deleted: 0.
## SUMMARY
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the assistant programs that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. One correction landed this evening: the check this plan added to the set of checks that run before every save was missing a closing line, so on any computer without one particular file every later check in that set was silently skipped; a checker working on a separate review found it, and it is fixed and proven. Still to do here: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and the closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the assistant programs that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. The wider review Nick asked for the same evening is its own project with its own card and plan, following this rule from birth; its first area is with Nick for his picks. Still to do here: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and the closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the assistant programs that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. The wider review Nick asked for the same evening is its own project with its own card and plan, following this rule from birth, and its first area is being checked now. Still to do here: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and the closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the assistant programs that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. The wider review Nick asked for the same evening is now its own project with its own card and plan, following this rule from birth. Still to do here: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and the closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. This evening Nick asked for a separate, wider review of the whole setup, thirteen areas from files and rules through the business task website and the website his family uses for to-do lists, shopping and the children's lessons, on to voice and storage, each read by its own checker with a written brief, then merged into one ranked list of fixes; that review is designed and waits for his go, and it will be its own card and its own plan, not part of this one. The one gap on this project is that the desk computer in Nick's office that runs the scheduled checks is working from a copy of the shared files that fell behind by more than a thousand saved changes after two machines disagreed about the same file, so none of today's enforcement runs on that computer until its copy is brought back in line; that repair belongs to the team that looks after the shared files. Still to do here: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and the closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card on the website where he manages the business's tasks, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. Nick asked this evening whether a check, a heartbeat or a watchdog is needed for the enforcement: all three already exist, because the set of tests that runs automatically every night includes the two small tests that print a red warning when an enforcement has been unwired, the hourly retire check records each run, and a separate audit reads every job's run record three times a day. The one gap is that the desk computer in Nick's office that runs the scheduled checks is working from a copy of the shared files that fell behind by more than a thousand saved changes after two machines disagreed about the same file, so none of today's enforcement runs on that computer until its copy is brought back in line; that repair belongs to the team that looks after the shared files. Still to do: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and a short closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card in the list of tasks he manages at hub.heroesandsidekicks.io, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. One thing found this evening: the desk computer in Nick's office that runs the scheduled checks is working from a copy of the shared files that fell behind by more than a thousand saved changes after two machines disagreed about the same file, so none of today's enforcement runs on that computer until its copy is brought back in line; that repair belongs to the team that looks after the shared files. Still to do: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and a short closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card in the list of tasks he manages at hub.heroesandsidekicks.io, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are now checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; 54 leftover backup copies that were never part of the record were deleted on Nick's word today; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. Still to do: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, the two small checks that print a red warning line when an enforcement has been unwired are added to the set of checks that runs automatically every night, and a short closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card in the list of tasks he manages at hub.heroesandsidekicks.io, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are now checked by people who did not build them: the rule is written once in the single file where Nick's decisions are kept as numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or one old folder on his Mac that is no longer used, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. Two tools were repaired along the way so that this plan could be recorded at all while it sits in a separate copy of the files used by one piece of work in progress: the recording tool now reads the file that lists every project and its plan document from beside the plan itself, and the check that runs when a session ends now recognises a plan whose file is simply named PLAN.md. Still to do: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and a short closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card in the list of tasks he manages at hub.heroesandsidekicks.io, and that card names exactly one document, the project's plan, as the record of the project until it is finished. Six of this plan's eight steps are now checked by people who did not build them: the rule is written once in his numbered rules; the automated helpers that work on his files can no longer read or search finished documents, or the folder left over from his previous setup, without a one-time approval Nick taps; a second plan document cannot be saved beside a live one without the same approval; 239 stale documents from 70 project folders sit in dated folders of finished documents with their full change history and none were deleted; one generated list names all 74 retired projects with their dates and folders; and an hourly check reads the task list for finished projects whose plan is still live. Still to do: each task card shows its plan as a clickable link to a web page listing that project's steps and progress, a new task card must name its plan when it is created, and a short closing section of lessons is written into this plan.
**2026-09-18** — On 18 September 2026 Nick confirmed a rule for how his projects are recorded: each project is exactly one task card in the list of tasks he manages at hub.heroesandsidekicks.io, and that card names exactly one document, the project's plan, as the record of the project until it is finished. That rule is now written once in his list of numbered rules and is enforced in three ways. First, when a project finishes its plan is moved into a dated folder of finished documents, and the automated helpers that work on his files can no longer read or search those finished documents, or the folder left over from his previous setup, unless Nick approves a one-time exception by tapping a request. Second, a helper cannot save a second plan document beside a project's live plan unless Nick approves it the same way. Third, a live document cannot start pointing at a finished one. Today 239 stale documents from 70 project folders were moved into those dated folders with their full change history, and none were deleted. This project itself has its one task card and this one plan document. Still to do: each task card shows its plan as a clickable link to a web page that lists that project's steps and how far each has got, a new task card for a project must name its plan when it is created, and a short closing section of lessons is written into this plan.
## STEPS
```
1. [Plan] The rule written once, this lane registered, carded and ticketed — 100%
DEFINITION OF DONE: the RULE 51 addendum once in MACHINE-RULES.md, RULE 51 cited once each in CORE §5 and BUILD §5; tickets queued; registry row and bound card exist
PROOF: `command grep -c "RULE 51 ↳ 2026-09-18" projects/ops/MACHINE-RULES.md` → 1
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent on origin/main a5b3d3d7: addendum count 1, CORE 2, BUILD 1, registry row 1, plan PASS; the card was re-checked by a second Sonnet verifier with ?assignee=all and carries project_file; the CORE sentence it found short of the spec/STEPS exception was corrected in fdbdfb0e89)
VERIFIED: 2026-09-18 (100%, checked by two Sonnet verifier agents on origin/main: the addendum count, the CORE and BUILD citations, the registry row and the plan's own checker pass; the card re-checked with the right query carries the file; the CORE sentence the first checker found short of the spec and STEPS exception was corrected in fdbdfb0e89)
2. [Framing] The shared definition and the move list, measured; the harnesses written red — 100%
DEFINITION OF DONE: the module exists, its test passes, the wiring harnesses fail red, the move list and BEFORE counts are in SUMMARY
PROOF: `node projects/ops/skippy-jobs/_test-project-files.mjs`
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent in two fresh checkouts of fdbdfb0e89: PASS 5/5, both wiring harnesses red with their literal line, 247-row move list identical across runs, ten sampled files with no live reader, SUMMARY numbers match)
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent in two fresh checkouts of fdbdfb0e89: PASS 5/5, both wiring harnesses red with their literal line, a 247-row move list identical across runs, ten sampled files with no live reader, the summary's numbers matching)
3. [Fixes] The cleanup moved, with history and dated lines — 100%
DEFINITION OF DONE: move list empty afterwards, dated lines appended, AFTER counts in SUMMARY, zero deletions
PROOF: `node projects/ops/skippy-jobs/lib/project-files.mjs --measure --json`
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent on origin/main: 239 renames and 0 deletions since a5b3d3d7, history follows every sampled move, the dated line present with a count that matches, 3 registry rows flipped, 5 sampled files with no runtime reader; it also found two registry rows stale since the 2026-09-04 purge, flipped in the STEP 6 commit)
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent in a fresh checkout of origin/main: 239 renames, 0 deletions, history follows every sampled move, the dated line present with a matching count, 3 registry rows flipped, no runtime reader for any sampled moved file)
4. [Tests] The lock: hook, ignore file, commit check, wired, red then green — 100%
DEFINITION OF DONE: selftest and wiring test pass; RED and GREEN recorded by the checker; a live file reads
PROOF: `node projects/ops/skippy-jobs/lib/check-archive-lock.mjs --selftest && node projects/ops/skippy-jobs/_test-archive-lock-wired.mjs`
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent: RED recorded live — an archive file read and grepped before the lock; GREEN on origin/main — selftest 22/22, six real payloads with the right exit codes and the 🔴 message, the ticket door allows with a scratch ticket and refuses without, wiring test PASS, pointer check 5/5, a miss at 36 ms wall-clock; the one instrument it lacked was the Grep tool itself, so the ignore file's effect through that tool is corroborated, not measured)
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent: red recorded live before the lock, green on origin/main with six real payloads, the ticket door, the wiring test and the pointer check 5/5). NOTE 2026-09-18 evening: the enforcement is on main but NOT yet live on the Mac Studio, whose shared checkout sits on a per-machine side branch 1,122 commits behind main after a blocked merge; its scheduler loaded job code from that checkout at 14:52 local time, so the hourly retire check, the lock in the tracked settings and the three nightly harnesses reach this Mac only once its checkout is back on main. That is the repository lane's fault to resolve, reported to Nick.
VERIFIED: 2026-09-18 (100%, checked by a Sonnet verifier agent: red recorded live before the lock, green on origin/main with six real payloads, the ticket door, the wiring test and the pointer check 5/5; the enforcement is on main and reaches the Mac Studio's scheduler only once that machine's checkout is back on main)
5. [Tests] The birth gate, wired, red then green — 100%
DEFINITION OF DONE: selftest and wiring test pass; RED and GREEN recorded by the checker
PROOF: `node projects/ops/skippy-jobs/lib/check-project-file-birth.mjs --selftest && node projects/ops/skippy-jobs/_test-birth-gate-wired.mjs`
VERIFIED: 2026-09-18 (100%, checked by two Sonnet verifier agents in scratch clones with the tracked commit hook installed: selftest 8/8, wiring PASS; the first found the plan-quality gate answering before the birth gate, fixed in 7769cb8ad6; the second saw a second plan refused with the RULE 51 message, the git mv route refused, SPEC.md allowed, a ticketed second file allowed, and a first plan in a new folder passed the birth gate)
6. [UI] Hub PM: the link row, the empty-row door, the retire job — 40%
DEFINITION OF DONE: the link opens the live file from a card; a card without a file is refused; the dry run lists the right cards
PROOF: `node projects/ops/skippy-jobs/jobs/project-retire.mjs --dry-run`
7. [Output] The retired index generated — 100%
DEFINITION OF DONE: the generated file lists every retired project with date and archive folder
PROOF: `node projects/ops/skippy-jobs/jobs/project-retire.mjs --index-only`
VERIFIED: 2026-09-18 (100%, checked by two Sonnet verifier agents on origin/main: the list generates 74 entries equal to its own count, every named archive folder exists, the union covers every retired registry row and every dated folder; the first found the job lacked the scheduler's entry point and one row misnamed its archive, both fixed in d38ea73b86; the second saw the scheduler's entry point return the dry-run line, write nothing, and the corrected row point at a folder that exists)
VERIFIED: 2026-09-18 (100%, checked by two Sonnet verifier agents on origin/main c82deb5e17: list count 74 matches, every archive folder exists, the scheduler entry point runs the dry run and writes nothing, the corrected registry row points at a folder that exists)
8. [Proof] Postmortem, written into this file — 10%
DEFINITION OF DONE: a POSTMORTEM section exists and new failure modes are in the registry
PROOF: `command grep -c "^## POSTMORTEM" projects/ops/project-files/PLAN.md`
```
VERIFIED: not yet — steps 6 and 8 remain open; the Hub link row and the create door sit with the Hub lane until 2026-09-19 evening, then this lane makes the link row itself
VERIFIED: not yet — steps 6 and 8 remain open; the card link row and the create door sit with the lane that owns the business task website until 2026-09-19 evening, then this lane makes the link row itself
VERIFIED: not yet — steps 6 and 8 remain open; the card link row and the create door sit with the lane that owns the business task website until 2026-09-19 evening, then this lane makes the link row itself
VERIFIED: not yet — steps 6 and 8 remain open; the card link row and the create door sit with the lane that owns the business task website until 2026-09-19 evening, then this lane makes the link row itself
VERIFIED: not yet — steps 6 and 8 remain open; the card link row and the create door sit with the lane that owns the business task website until 2026-09-19 evening, then this lane makes the link row itself