docs(phase-33.5): task 12 — kit part 3: decomp-architect/SETUP.md (Step 0 contract with the write-scope guardrails; Step 1 the PA-2.0 pin, the ladder-in-constitution check, the §E precondition, Path A only, the Phase-0.5 phase file; Step 2 the interview + the answers: file contract; Step 3 the firewall with the planted-fixture negative control and the check-ignore probes; Step 4 layout; Step 5 bootstrap + the checkpoint commit; Step 6 the flywheel documents that outlive the package; Step 7 the registry seed inserted before §E′ with the renumber fallback; Step 8 the overlays by marker + config templates instead of a live settings/mcp merge + the skeletons; Step 9 the memory seed; Step 10 the leftover-placeholder audit, the sorted install manifest, PhaseEnd_Phase0.5, the close commit, the five-part final message, hard stop; install manifest; troubleshooting); class 7 of the firewall gains /.claude-state/transcripts/ (a decomp's transcripts quote the target) and the scratch block re-includes .run/README.md — wiki fence + template re-extracted (75 lines identical); pa-overlays Block 7 → config/decomp-hooks.snippet.json + config/mcp.json.template (no comment keys in JSON); PLACEHOLDERS "Filled" wording aligned with the steps; verify: kit_lint OK over 44 files, doc_links --strict rc 0, 19/19 PA installer mechanisms with counterparts, 12/12 markers present in their templates, all placeholders named, every Step reference resolves; log + checkpoint (NEXT = task 13, the dry-run, xHigh)

This commit is contained in:
Drew T
2026-09-07 19:42:41 -06:00
parent 6fb2bc7f8c
commit 4c1d5d9f7c
6 changed files with 432 additions and 97 deletions
+291
View File
@@ -0,0 +1,291 @@
# SETUP.md — decomp-architect installer (Phase 0.5 of a ProjectArchitect 2.0 project)
> **For the human:** install ProjectArchitect 2.0 first, handing its interview `decomp-architect/intake.decomp.md` (the kit's
> `README.md`, step 1). Then, with this folder at your project root and a **fresh** Claude Code session, say:
> **"Read decomp-architect/SETUP.md and do it."** For an unattended run say instead **"Read decomp-architect/SETUP.md and do
> it; answers: <path>"** (Step 2 describes the file). Expect file-write permission prompts; nothing here writes outside the
> repository. Everything below is for the agent.
## Honesty — what this installs, and what it does not
This installer stamps **documents, configuration and one script**: the ROM firewall (the ignore file, the audit with its config
and its negative control, the CI workflow), the layout and its READMEs, the decomp rules into the registry, the overlays on the
entry-point file, the digest, the phase templates, the effort map, the cookbook and the ops reference, the methodology and the
kernels into `docs/`, the tools manifest as a task list, the memory seed, and the license/notice/README/contributing skeletons.
It does **not** install a byte gate, a splitter configuration, a compiler, a disassembler, an emulator, a permuter harness, a
decompiler context or a differential harness — those are the first phases' work, listed in `docs/tools-manifest.md` as tasks
with the source project's tool named beside each. The generation-time values (the toolchain triple, the extract and fleet-check
commands, the oracle endpoints) are written as `TODO(phase-N)` lines that the named phase replaces. The one decision it cannot
make is whether the repository starts public or private; the firewall applies either way.
---
## Step 0 — Execution contract (agent: read this first, follow it exactly)
1. **You are Claude Code, running from the project's root**, with this package at `./decomp-architect/`. Resolve two
variables once and use them throughout: `KIT="./decomp-architect"` (if the folder is elsewhere, resolve its path) and
`ROOT="$(git rev-parse --show-toplevel)"`. Every git command is `git -C "$ROOT" …`. Quote every path.
2. **If you are in plan mode:** your plan is exactly *"execute SETUP.md Steps 1–10 in order."* Present that, get approval,
execute. Do not redesign, reorder or "improve" these steps.
3. **Copy templates verbatim.** Files are materialised with `cp`, then placeholders are filled with the Edit tool. **Never
retype a template's body from memory.** Placeholders come in two classes (`templates/PLACEHOLDERS.md` is the contract):
**copy-time** — answered once at Step 2 and filled wherever a template is copied in; **generation-time** — written as a
literal `TODO(phase-N)` line at Step 8 (`{{TOOLCHAIN_TRIPLE}}` → `TODO(phase-4)`, `{{EXTRACT_CMD}}` → `TODO(phase-1)`,
`{{FLEET_CHECK_CMD}}` → `TODO(phase-3)`, `{{DISASSEMBLER_MCP}}` and `{{EMULATOR_BRIDGE}}` → `TODO(phase-2)`). Step 10's
audit catches any leftover.
4. **Marked sections, never edits.** Every append lands under the block's own heading — its **marker** — at the END of the
target, or at the one insertion point a step names. A target that already contains the marker is SKIPPED. Nothing above
a marker is ever edited: ProjectArchitect's stamped content stays byte-identical.
5. **Every step self-verifies** (the ✓ line). If a verification fails: STOP, report exactly what failed, and wait — do not
improvise around it.
6. **Idempotent:** every step begins with an existence or marker check and a SKIP branch. Re-running this file after a crash
resumes at the first unticked checkbox of the Phase-0.5 `CURRENT_PHASE.md` (Step 1 creates it).
7. **Git and write scope:** commits add only the files this installer created or appended, **by explicit path** (never
`git add -A`); no attribution trailers; **never push**; never `git clean` (in a decomp the game-derived data is
ignored-but-present); never remove a directory with a relative `rm -rf` — the one deletion below is one explicit file;
**never write under the home directory** (`~/.claude` is ProjectArchitect's; the project's memory lives at the
repository's `.claude-state/memory/`).
8. **Interaction:** the developer answers once, at Step 2 — or the `answers:` file answers for them. An unanswered question
STOPs; nothing is defaulted silently.
## Step 1 — Prerequisites: the version pin, the path, the registry precondition, the phase file
1. `git -C "$ROOT" rev-parse --show-toplevel` succeeds (ProjectArchitect requires a git repository too).
2. **The version pin.** All of these must hold, else STOP with *"Install ProjectArchitect 2.0 first (its Path A), handing its
interview decomp-architect/intake.decomp.md; this kit overlays version 2.0 exactly"*:
`grep -q '^> \*\*Version:\*\* 2\.0' docs/project-architect.md` · `test -f RULES_REGISTRY.md` · `test -d phase-ends` ·
`test -f PROJECT_CONTEXT.md` · `test -f CLAUDE.md` · `test -f phase-ends/PhaseEnd_Phase0.md` (the ProjectArchitect install
phase is closed) · `test -f phase-ends/CURRENT_PHASE.template.md` · `test -f phase-ends/PhaseEnd.template.md` ·
`test -f docs/effort-map.md` · `test -f docs/ops-setup.md` · `ls docs/*cookbook*.md` lists exactly one file ·
`test -d .claude-state/memory`.
3. **The ladder is in the constitution.** `grep -q 'Governance and the firewall' PROJECT_CONTEXT.md` (the Phase-0 name from
the intake's ladder). If it fails, the intake was not handed to the generation step. STOP and give the developer the two
options: re-run ProjectArchitect's install on a fresh repository with the intake, or proceed and record, in this phase's
PhaseEnd, the constitution correction that the roadmap of record is the intake's Part B (copied to `docs/decomp-ladder.md`
at Step 6 in that case) — the constitution itself is never edited (ProjectArchitect P1). Record the choice in the log.
4. **The registry precondition.** Between the `## §E` heading and the `## §E′` heading of `RULES_REGISTRY.md` there must be no
`### G` heading (the intake's Part D asked the generation step to leave only a one-line pointer). If rules G1…Gk already
exist there, Step 7 uses its renumber-by-offset fallback; note k now in the log.
5. **Path A only.** A repository that already holds a decompilation — any `src/*.c`, a splitter configuration under
`config/`, a `Makefile` with a build target — is an explicit STOP: *"an existing decompilation repository is out of this
version's scope; the kit installs into a fresh ProjectArchitect 2.0 project only."*
6. **The phase file.** If `phase-ends/CURRENT_PHASE.md` exists and names Phase 0.5 → resume from its first unticked step.
Else `cp phase-ends/CURRENT_PHASE.template.md phase-ends/CURRENT_PHASE.md` and fill it: *"Phase 0.5 — decomp-architect:
the decomp overlay"*, started today, the milestone = Step 10's verify list, the checklist = Steps 2–10 as checkboxes.
✓ *Verify:* every test in 2 passes; 3 and 5 hold; the §E state is recorded; `CURRENT_PHASE.md` names Phase 0.5 and lists
Steps 2–10.
## Step 2 — The game interview (the copy-time answers; `answers:` for unattended runs)
1. **Read back from ProjectArchitect** (never re-ask): `{{PROJECT_NAME}}` = the title on `CLAUDE.md`'s first line (after the
dash); `{{COOKBOOK_NAME}}` = the file name of the one `docs/*cookbook*.md`; `{{INSTALL_DATE}}` = today in the format
ProjectArchitect used (an `answers:` file may pin it).
2. **Ask the developer, in ONE compact round**, offering a default where one is sane, the thirteen copy-time values:
`{{GAME_TITLE}}`, `{{PLATFORM}}`, `{{GAME_SERIAL}}`, `{{TARGET_BINARY}}` (the main executable's file name on the medium),
`{{DUMP_PATH}}` (an ABSOLUTE path to the developer's own dump; it must lie OUTSIDE the repository, and it is never copied
by this installer), `{{CONTAINER_LAYOUT}}`, `{{SDK_EVIDENCE}}`, `{{COMPILER_FAMILY}}` (a candidate set, not the pin),
`{{COMMUNITY_WORK}}` ("none found on <date>" is an answer), `{{PROJECT_GOALS}}`, `{{LICENSE_CHOICE}}` (for the project's own
work; no license is asserted over the decompiled source), `{{AI_DISCLOSURE}}` (one project-level sentence),
`{{PUBLIC_OR_PRIVATE}}` (the day-one visibility; the firewall applies either way).
3. **Unattended mode.** If the developer's instruction carried `answers: <path>`, read that file: one `KEY: value` line per
key (the placeholder name without braces; `#` starts a comment), the thirteen keys above plus the optional
`INSTALL_DATE`. Every question is answered from the file; **a missing or empty key STOPs, naming the key** — it is never
defaulted.
4. Record every answer in the Phase-0.5 log (`CURRENT_PHASE.md`), so the PhaseEnd can carry them.
✓ *Verify:* all sixteen values are non-empty; `{{DUMP_PATH}}` is absolute and not under `$ROOT`; `{{COOKBOOK_NAME}}` resolves
to an existing file; in unattended mode, the file supplied every key.
## Step 3 — The ROM firewall, in force from this commit
1. **The ignore file.** If `.gitignore` does not contain the marker line `# ROM firewall — in force from the FIRST commit`:
append one dated comment line `# ---- decomp-architect Phase 0.5, installed {{INSTALL_DATE}} ----` and then the whole of
`$KIT/templates/gitignore.decomp`. Never remove or reorder ProjectArchitect's block above it.
2. `cp "$KIT/templates/firewall.txt" config/firewall.txt`; fill `{{TARGET_BINARY}}`.
3. `cp "$KIT/templates/firewall-fixture/blob.sha1" config/firewall-fixture.sha1` (the hash only — the blob itself is never
tracked; `templates/firewall-fixture/README.md` says why).
4. `cp "$KIT/templates/audit_public.template.py" tools/audit_public.py && chmod +x tools/audit_public.py`.
5. `mkdir -p .github/workflows && cp "$KIT/templates/no-rom.template.yml" .github/workflows/no-rom.yml`.
6. **The negative control — an audit that has not failed on its fixture is not trusted to pass:**
`mkdir -p .run/firewall-control && cp "$KIT/templates/firewall-fixture/blob.bin" .run/firewall-control/planted.bin`, then
`python3 tools/audit_public.py --paths .run/firewall-control/planted.bin` **must exit 1** and print
`OFFENDER .run/firewall-control/planted.bin`. Then `rm -f .run/firewall-control/planted.bin` (the one deletion in this
installer: an explicit file), and `python3 tools/audit_public.py` (the tracked tree) **must exit 0**. If the control passes
the planted blob, STOP: the fixture hash or the config is wrong; never proceed with an audit that cannot fail.
7. **The ignore probes.** Positive — each must succeed: `git -C "$ROOT" check-ignore -q disks/x.bin`, `… asm/x.s`,
`… extracted/x`, `… dumps/x.bin`, `… ghidra/x`, `… tools/psyq/x`, `… .claude-state/transcripts/x`, `… .run/scratch/x`.
Negative — each must FAIL (exit 1): `git -C "$ROOT" check-ignore -q src/main.c`, `… config/x.yaml`,
`… extracted/retail/manifest.jsonl`, `… .run/README.md`, `… .claude-state/memory/MEMORY.md`.
✓ *Verify:* the marker is in `.gitignore` exactly once; the five files exist; the control failed then passed; every probe
behaved as listed.
## Step 4 — The layout and its two READMEs
1. `mkdir -p src config tools docs .run disks extracted/retail dumps` (the ignored ones exist so the probes above are real
directories; nothing is put in them).
2. `cp "$KIT/templates/docs-README.md" docs/README.md`; fill `{{PROJECT_NAME}}`, `{{INSTALL_DATE}}`, `{{CONTAINER_LAYOUT}}`.
3. `cp "$KIT/templates/run-README.md" .run/README.md`; fill `{{PROJECT_NAME}}`, `{{INSTALL_DATE}}` (the ignore file re-includes
exactly this one file under `.run/`).
✓ *Verify:* the directories exist; both READMEs exist and contain no `{{`; `git -C "$ROOT" check-ignore -q .run/README.md`
FAILS (the README is trackable).
## Step 5 — The bootstrap skeleton, and the checkpoint commit
1. `cp "$KIT/templates/bootstrap.template.sh" tools/bootstrap.sh && chmod +x tools/bootstrap.sh && bash -n tools/bootstrap.sh`.
2. Tick Steps 2–5 in `CURRENT_PHASE.md`; write the Step-2 answers into its log if not yet done.
3. **Checkpoint commit, by explicit path:** `.gitignore config/firewall.txt config/firewall-fixture.sha1 tools/audit_public.py
.github/workflows/no-rom.yml docs/README.md .run/README.md tools/bootstrap.sh phase-ends/CURRENT_PHASE.md` — message
`chore: decomp-architect Phase 0.5 — firewall, layout, bootstrap` (no trailer). Do not push.
✓ *Verify:* `bash -n` clean; the commit exists; `git -C "$ROOT" status --porcelain` lists none of those paths;
`git -C "$ROOT" log -1 --format=%B` contains no attribution trailer.
## Step 6 — The flywheel skeleton (documents that outlive the package)
1. `docs/wave-playbook.md` — CREATE from `pa-overlays.md` **Block 6** (the fenced body under that heading, copied verbatim);
fill `{{INSTALL_DATE}}`. SKIP if the file exists.
2. `docs/tools-manifest.md` — `cp "$KIT/tools/MANIFEST.md"` and prepend one line: *"Installed by decomp-architect on
{{INSTALL_DATE}}; every row is a Phase-N task until the tools are ported."*
3. `docs/decomp-kernels.md` — `cp "$KIT/corpus/decomp-kernels.md"` (the constitution's ladder cites kernels by id; they must
survive the package's deletion).
4. If Step 1.3 chose "proceed": `docs/decomp-ladder.md` — `cp "$KIT/intake.decomp.md"` with a banner naming it the roadmap of
record for this project.
✓ *Verify:* the files exist; `grep -c '^| [0-9]' docs/wave-playbook.md` ≥ 11 (the step table); `grep -c '^### DK-'
docs/decomp-kernels.md` = 64; `grep -c '^| \`' docs/tools-manifest.md` = 325.
## Step 7 — The registry: the decomp rules into §E
1. Marker: the seed's own heading line `## §E — Project-specific rules (a matching decompilation)`. If `RULES_REGISTRY.md`
contains it → SKIP.
2. Re-assert the precondition of Step 1.4 (no `### G` heading between `## §E` and `## §E′`).
3. Take the seed body: from the line of `$KIT/templates/registry-E.decomp.md` that starts `## §E —` to its end (the leading
HTML comment is dropped). **Insert it immediately BEFORE the `## §E′` heading line** (ProjectArchitect's own `## §E`
heading, its italic paragraph and the pointer line stay above; the registry then reads: the §E heading, the pointer, the
installed block G1–G65, then §E′ and §F).
4. **Fallback** (only if Step 1.4 found rules G1…Gk in §E): renumber the seed body — every `G<number>` token inside the body,
headings and cross-references alike — by `+k` with one scripted pass, change its heading to end `— installed as
G<k+1>–G<k+65>`, then insert as in 3. Record the offset in the log and the PhaseEnd.
✓ *Verify:* `grep -c '^### G' RULES_REGISTRY.md` = 65 (or 65 + k); the marker appears exactly once; `## §E′` still follows the
block; the session-start recitation in `CLAUDE.md` already covers "every §E project rule" — nothing to change there.
## Step 8 — The overlays and the skeletons
*For each append: grep the target for the marker first; SKIP if present. Fill copy-time placeholders; write generation-time
ones as the `TODO(phase-N)` literals of Step 0.3.*
1. **`CLAUDE.md`** ← `$KIT/templates/CLAUDE.decomp-overlay.md` from its `## Decomp fail-safes` line to the end (the leading HTML
comment dropped), APPENDED. Marker `## Decomp fail-safes`. Fill `{{INSTALL_DATE}}`, `{{COOKBOOK_NAME}}`; `{{FLEET_CHECK_CMD}}`
→ `TODO(phase-3)`.
2. **`phase-ends/DIGEST.md`** ← `pa-overlays.md` **Block 1**, CREATE if absent. Fill `{{INSTALL_DATE}}`. Then write its part 2's
first synopsis line for Phase 0 (ProjectArchitect's install, from `PhaseEnd_Phase0.md`'s recap) — one sentence.
3. **`phase-ends/CURRENT_PHASE.template.md`** ← **Block 2** APPENDED at the end. Marker `## 🛑 SESSION CHECKPOINT`. (Every phase
from 1 on inherits the replayable block; the Phase-0.5 file, already created, keeps ProjectArchitect's shape.)
4. **`phase-ends/PhaseEnd.template.md`** ← **Block 3** INSERTED immediately before the `## PhaseEnd Changelog` line. Marker =
the block's heading.
5. **`docs/effort-map.md`** ← **Block 4** APPENDED. Marker `## Per-phase effort map (decomp ladder`. Fill `{{INSTALL_DATE}}`.
6. **`docs/{{COOKBOOK_NAME}}`** ← **Block 5** APPENDED. Marker `## The decomp entry shape`. Fill `{{INSTALL_DATE}}`,
`{{SDK_EVIDENCE}}`; `{{TOOLCHAIN_TRIPLE}}` → `TODO(phase-4)`.
7. **`docs/ops-setup.md`** ← `$KIT/templates/ops-setup.decomp.md` from its `## Decomp environment` line (the HTML comment
dropped), APPENDED. Marker `## Decomp environment`. Fill every copy-time placeholder it names; the five generation-time
ones as their `TODO(phase-N)` literals.
8. **`config/decomp-hooks.snippet.json`** and **`config/mcp.json.template`** ← **Block 7**'s two JSON bodies, CREATE each if
absent; `{{DISASSEMBLER_MCP}}` → `TODO(phase-2)`. `.claude/settings.json` and `.mcp.json` are NOT touched (Phase 2 merges and
copies them when the server exists). Validate both files parse as JSON.
9. **`docs/decomp-architect.md`** ← `cp "$KIT/decomp-architect.md"` (the methodology survives the package's deletion).
10. **The skeletons.** `LICENSE`: if absent, `cp "$KIT/templates/LICENSE.skeleton.md" LICENSE` and fill `{{LICENSE_CHOICE}}`,
and flag in the final message that it must be replaced by the license's verbatim text before the first push; if present,
leave it and note it. `src/NOTICE.md` ← `templates/NOTICE.src.md` (fill `{{GAME_TITLE}}`, `{{PLATFORM}}`, `{{GAME_SERIAL}}`,
`{{LICENSE_CHOICE}}`). `README.md` and `CONTRIBUTING.md`: if absent, create from the skeletons (fill `{{PROJECT_NAME}}`,
`{{GAME_TITLE}}`, `{{PLATFORM}}`, `{{GAME_SERIAL}}`, `{{PROJECT_GOALS}}`, `{{AI_DISCLOSURE}}`, `{{PUBLIC_OR_PRIVATE}}`,
`{{COMMUNITY_WORK}}`, `{{LICENSE_CHOICE}}`); if present, write the filled skeleton beside it as `README.decomp-skeleton.md` /
`CONTRIBUTING.decomp-skeleton.md` and tell the developer to merge by hand. `.clang-format`: `cp` if absent, else SKIP with
a note. `Makefile`: if absent, create it with the content of `templates/make-format.snippet.mk`; if present, APPEND the
snippet under its marker `.PHONY: format format-check`.
✓ *Verify:* each marker appears exactly once in its target; `grep -c '{{' CLAUDE.md docs/ops-setup.md docs/effort-map.md
docs/{{COOKBOOK_NAME}} phase-ends/DIGEST.md src/NOTICE.md` = 0 for each; `grep -c 'TODO(phase-' docs/ops-setup.md` ≥ 5; both
JSON files parse; `docs/decomp-architect.md` exists.
## Step 9 — The memory seed
1. Assert the memory directory is the one ProjectArchitect configured: the `autoMemoryDirectory` value in
`.claude/settings.local.json` ends with `/.claude-state/memory`; the directory exists. **Nothing is written under the home
directory.**
2. `cp "$KIT/memory-seed/"*.md .claude-state/memory/` — every file EXCEPT `MEMORY.md`.
3. APPEND the kit's index rows to `.claude-state/memory/MEMORY.md`: a heading `## decomp-architect seed` (the marker; SKIP if
present), then every `- [` line of `$KIT/memory-seed/MEMORY.md` in order.
4. State plainly: **seeded memories activate from the NEXT session.**
✓ *Verify:* `ls .claude-state/memory/*.md | grep -vc MEMORY.md` = 32 (ProjectArchitect's 16 + the kit's 16); every link in
the appended rows resolves to a file; the marker appears once.
## Step 10 — Verify, the manifest, gitignore the package, close Phase 0.5, hard stop
1. **The leftover-placeholder audit:** `grep -rln '{{' --include='*.md' --include='*.txt' --include='*.sh' --include='*.py'
--include='*.yml' --include='*.json' --include='*.mk' --include='Makefile' . | grep -v '^./decomp-architect/'` may list
ONLY `./docs/project-architect.md`, `./phase-ends/CURRENT_PHASE.template.md` and `./phase-ends/PhaseEnd.template.md`
(ProjectArchitect's own reference spec and templates). Anything else = an unfilled placeholder → fill it, then re-run.
2. `python3 tools/audit_public.py` → exit 0. `bash -n tools/bootstrap.sh`. `python3 -m py_compile tools/audit_public.py`
(then remove the `__pycache__` it makes, or run it with `PYTHONDONTWRITEBYTECODE=1`).
3. `grep -c '^### G' RULES_REGISTRY.md` = 65 (+ the offset, if any).
4. **Gitignore the package:** append to `.gitignore` under the comment `# decomp-architect (the day-one kit's package folder —
safe to delete after install)` the line `decomp-architect/` (SKIP if present).
5. **The install manifest:** write `.run/decomp-architect-install-manifest.txt` — one line per touched path, sorted, in the
form `CREATED <path>` / `APPENDED <path> (<marker>)` / `SKIPPED <path> (<reason>)` — and print it. (An unattended run diffs it
against an expected manifest.)
6. **Close the phase.** Tick Steps 6–10. Write `phase-ends/PhaseEnd_Phase0.5.md` from `phase-ends/PhaseEnd.template.md` (which
now carries the narrative axis): the Build Log = the manifest; Deviations (an existing README/LICENSE left beside a
skeleton, a registry offset, the Step-1.3 choice); Rules Added = *"G1–G65 installed into §E — the kit's seed; the origin
of each is its provenance line"*; the narrative axis filled honestly (what the install assumed, what it found); the
Plain-English Recap last. Run `bash tools/backup-claude-state.sh` (ProjectArchitect's state sweep; the transcripts it
copies are ignored by the class-7 line, the memory files are tracked). Then `git -C "$ROOT" mv phase-ends/CURRENT_PHASE.md
phase-ends/logs/PhaseLog_0.5.md`.
7. **The close commit, by explicit path:** every path in the manifest that this step or Steps 6–9 created or appended, plus
`.gitignore`, `phase-ends/PhaseEnd_Phase0.5.md`, `phase-ends/logs/PhaseLog_0.5.md`, `.claude-state/memory/…`. Message
`chore: decomp-architect Phase 0.5 — the decomp overlay installed` (no trailer). Do not push — tell the developer to review
and push.
8. **Final message, in order:** (a) the install manifest; (b) *"You may delete `decomp-architect/` from this repository (it is
gitignored; keep the master copy elsewhere) — `docs/decomp-architect.md`, `docs/decomp-kernels.md`, `docs/tools-manifest.md`
and the registry carry what matters"*; (c) if `LICENSE` was written from the skeleton: *"Replace `LICENSE` with the license's
verbatim text before the first push"*; (d) *"Start a **fresh session** (the seeded memories activate at startup) and say
**'Begin Phase 1'**"*; (e) the plain-English recap, last. Then **🛑 HARD STOP** — no previewing Phase 1, no continuing.
✓ *Verify (before the final message):* the PhaseEnd exists; `CURRENT_PHASE.md` is archived, not deleted; both commits are
present and trailer-free; `git -C "$ROOT" status --porcelain` is empty apart from intentionally uncommitted items (none).
---
## Install manifest (what exists after a completed install)
```
.gitignore (+ the firewall block, + decomp-architect/) config/firewall.txt config/firewall-fixture.sha1
tools/audit_public.py .github/workflows/no-rom.yml tools/bootstrap.sh docs/README.md .run/README.md
docs/wave-playbook.md docs/tools-manifest.md docs/decomp-kernels.md docs/decomp-architect.md
RULES_REGISTRY.md (+ §E G1–G65) CLAUDE.md (+ Decomp fail-safes, Session-start extras)
phase-ends/DIGEST.md phase-ends/CURRENT_PHASE.template.md (+ the checkpoint block)
phase-ends/PhaseEnd.template.md (+ the narrative axis) docs/effort-map.md (+ the decomp rows)
docs/<cookbook> (+ the entry shape and the triage table) docs/ops-setup.md (+ Decomp environment)
config/decomp-hooks.snippet.json config/mcp.json.template LICENSE (skeleton, or untouched) src/NOTICE.md
README.md, CONTRIBUTING.md (created, or *.decomp-skeleton.md beside the existing ones) .clang-format Makefile (+ format)
.claude-state/memory/ (+ 16 seeds, + the index rows) phase-ends/PhaseEnd_Phase0.5.md phase-ends/logs/PhaseLog_0.5.md
```
## Troubleshooting
- **The version line is not found** → the project is not a ProjectArchitect 2.0 install; install it first (its Path A) with the
intake, then re-run this file.
- **§E already holds rules** → Step 7's renumber-by-offset fallback; the offset goes in the log and the PhaseEnd.
- **A README, LICENSE, CONTRIBUTING or `.clang-format` already exists** → the skeleton is written beside it (or skipped) and
named in the final message; merging is the developer's.
- **The control passes the planted blob** → STOP; `config/firewall-fixture.sha1` or `config/firewall.txt` is wrong. An audit
that cannot fail proves nothing.
- **The `answers:` file lacks a key** → STOP, naming the key; unattended runs never default.
- **Interrupted mid-install** → say "Read decomp-architect/SETUP.md and do it" again; Step 1.6 resumes at the first unticked
checkbox of the Phase-0.5 `CURRENT_PHASE.md`.
- **The disassembler or emulator is not reachable** → not an install concern; Phase 2 sets them up, and `docs/ops-setup.md`
carries their `TODO(phase-2)` rows until then.
+11 -11
View File
@@ -7,10 +7,10 @@
> the kit's Step 10) must find none of these anywhere in the project outside the kit's own package folder and the
> reference copy of the methodology.
>
> **Two classes**, following ProjectArchitect: **copy-time** placeholders are filled while the templates are copied in
> (the kit's SETUP Steps 2–5, from the game interview and from values ProjectArchitect already stamped); **generation-time**
> placeholders are filled when the overlays are generated (Steps 7–9), and some legitimately stay a `TODO` until the phase
> that produces their value — those say so.
> **Two classes**, following ProjectArchitect: **copy-time** placeholders are answered at the game interview (the kit's
> SETUP Step 2, plus three values read back from what ProjectArchitect already stamped) and filled wherever a template is copied
> in (Steps 3–9); **generation-time** placeholders have no value at Phase 0.5 — the installer writes each as a literal
> `TODO(phase-N)` line at Step 8, and the phase that produces the value replaces the line.
## Shared with ProjectArchitect (read back from the files it already stamped; never re-asked)
@@ -21,7 +21,7 @@
| `{{COOKBOOK_NAME}}` | the cookbook file ProjectArchitect created under `docs/` | the CLAUDE overlay's flywheel line, the cookbook overlay |
| `{{DOMAIN_FAILSAFES}}` | **referenced only, never filled by the kit** — ProjectArchitect's own CLAUDE.md placeholder, which its generation step fills from the intake's Part D | `intake.decomp.md` Part D names it so the generation step knows which four fail-safes to write |
## Copy-time (the game interview — SETUP Step 2)
## Copy-time (answered at SETUP Step 2; filled at Steps 3–9)
| Placeholder | What it is | Used in |
|---|---|---|
@@ -39,15 +39,15 @@
| `{{AI_DISCLOSURE}}` | the project-level sentence disclosing how AI is used | the README skeleton, CONTRIBUTING |
| `{{PUBLIC_OR_PRIVATE}}` | the day-one visibility decision (the firewall applies either way) | the README skeleton, the ops-setup git posture |
## Generation-time (the overlays — SETUP Steps 7–9)
## Generation-time (written as `TODO(phase-N)` at SETUP Step 8; replaced by the phase that produces the value)
| Placeholder | What it is | Filled when | Used in |
|---|---|---|---|
| `{{TOOLCHAIN_TRIPLE}}` | the pinned compiler → assembler shim → binutils triple with flags | **Phase 4** — installed as a literal `TODO(phase-4)` line that the pin task replaces | the ops-setup version pins, the cookbook overlay's pinned context |
| `{{EXTRACT_CMD}}` | the one command that extracts the medium and verifies the manifest | Step 9 (as `TODO(phase-1)` until the extractor exists) | the ops-setup build/run/test block |
| `{{FLEET_CHECK_CMD}}` | the clean fleet verification (`clean → extract → build` over every binary, exit code read) | Step 9 (`TODO(phase-3)` until the baseline exists) | the ops-setup gate line, the CLAUDE overlay's fail-safe wording |
| `{{DISASSEMBLER_MCP}}` | the disassembler server's endpoint and the command that starts it | Step 9 (`TODO(phase-2)`) | the ops-setup MCP/hooks row |
| `{{EMULATOR_BRIDGE}}` | the runtime oracle's scripting interface or bridge endpoint | Step 9 (`TODO(phase-2)`) | the ops-setup MCP/hooks row |
| `{{TOOLCHAIN_TRIPLE}}` | the pinned compiler → assembler shim → binutils triple with flags | Step 8 as `TODO(phase-4)`; Phase 4's pin task replaces it | the ops-setup version pins, the cookbook overlay's pinned context |
| `{{EXTRACT_CMD}}` | the one command that extracts the medium and verifies the manifest | Step 8 as `TODO(phase-1)` | the ops-setup build/run/test block |
| `{{FLEET_CHECK_CMD}}` | the clean fleet verification (`clean → extract → build` over every binary, exit code read) | Step 8 as `TODO(phase-3)` | the ops-setup gate line, the CLAUDE overlay's fail-safe wording |
| `{{DISASSEMBLER_MCP}}` | the disassembler server's endpoint and the command that starts it | Step 8 as `TODO(phase-2)` | the ops-setup MCP/hooks row, `config/mcp.json.template` |
| `{{EMULATOR_BRIDGE}}` | the runtime oracle's scripting interface or bridge endpoint | Step 8 as `TODO(phase-2)` | the ops-setup MCP/hooks row |
## Not placeholders (by design)
@@ -35,7 +35,10 @@
/tools/psyq/
# 7. Session transcripts — they quote the target's disassembly; keep them out of any public tree
# (a governance system that keeps the agent's transcripts inside the repository writes them under
# .claude-state/transcripts/ — ignored here; the memory files beside them stay tracked)
/session-archive/
/.claude-state/transcripts/
# 8. Training data and weights derived from the target
/datasets/
@@ -54,6 +57,7 @@
# ---- irreplaceable work. Rule of thumb: commit what a rerun CANNOT reproduce (hand analysis, ----
# ---- harnesses, ledgers, the recorded contract run); leave what a script regenerates ignored. ----
/.run/*
!/.run/README.md
# One dated block per exception — re-include the directory, re-exclude its contents, re-include
# the wanted files — under a comment naming the phase, the session and the rule. For example:
# # P<N> <task> (<session>, <date>): the recorded contract run's per-step logs. Evidence, tracked.
+8 -8
View File
@@ -198,11 +198,13 @@ the reconcile ladder without a redraft; the gate number is not the close rate un
---
## Block 7 — `.claude/settings.json` (MERGE at Step 8; add only absent keys) and `.mcp.json` (CREATE at Step 8)
## Block 7 — `config/decomp-hooks.snippet.json` and `config/mcp.json.template` (CREATE at Step 8; activated at Phase 2)
*ProjectArchitect already wrote the `SessionEnd` backup hook; the kit adds a `SessionStart` slot for the disassembler
server (filled at Phase 2) and the MCP client entry. Merge rule: add a key only if absent; never overwrite; validate
the JSON afterwards.*
*ProjectArchitect already wrote the `SessionEnd` backup hook into `.claude/settings.json`. The kit does NOT merge a hook or an
MCP entry at Phase 0.5 — a hook that runs a stub every session and an MCP client entry pointing at nothing would only add
noise and prompts. It installs the two snippets below as config templates; Phase 2 (the oracles) writes the server-start
script, merges the hook (add only absent keys, validate the JSON afterwards) and copies the MCP template to `.mcp.json` with
the real loopback endpoint. Generation-time values are written as `TODO(phase-2)` at install.*
````json
{
@@ -212,8 +214,7 @@ the JSON afterwards.*
"hooks": [
{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR\"/tools/disassembler_mcp_start.sh",
"_comment": "TODO(phase-2): the script that starts the disassembler's headless server and prints 'serving'; until it exists this hook is a no-op stub the kit installs"
"command": "bash \"$CLAUDE_PROJECT_DIR\"/tools/disassembler_mcp_start.sh"
}
]
}
@@ -227,8 +228,7 @@ the JSON afterwards.*
"mcpServers": {
"disassembler": {
"type": "sse",
"url": "{{DISASSEMBLER_MCP}}",
"_comment": "TODO(phase-2): the loopback SSE endpoint of the disassembler's MCP server; after any restart, the developer reconnects the client"
"url": "{{DISASSEMBLER_MCP}}"
}
}
}
+4
View File
@@ -83,7 +83,10 @@ copies are identical). Adjust the path names to your layout; do not delete a cla
/tools/psyq/
# 7. Session transcripts — they quote the target's disassembly; keep them out of any public tree
# (a governance system that keeps the agent's transcripts inside the repository writes them under
# .claude-state/transcripts/ — ignored here; the memory files beside them stay tracked)
/session-archive/
/.claude-state/transcripts/
# 8. Training data and weights derived from the target
/datasets/
@@ -102,6 +105,7 @@ copies are identical). Adjust the path names to your layout; do not delete a cla
# ---- irreplaceable work. Rule of thumb: commit what a rerun CANNOT reproduce (hand analysis, ----
# ---- harnesses, ledgers, the recorded contract run); leave what a script regenerates ignored. ----
/.run/*
!/.run/README.md
# One dated block per exception — re-include the directory, re-exclude its contents, re-include
# the wanted files — under a comment naming the phase, the session and the rule. For example:
# # P<N> <task> (<session>, <date>): the recorded contract run's per-step logs. Evidence, tracked.
+114 -78
View File
@@ -50,7 +50,7 @@ in-tree links to `docs/wiki/<Page>.md`. 8. `.run/`: only what git tracks; no sca
- [x] **9** Memory reconciliation (the off-project file parked; the 7 stale updated in place; `bfm-decomp-context-system` refreshed; the seed set — 16 files — under `decomp-architect/memory-seed/` with `upstream: PA` tags) — xHigh — see Log 2026-09-07 Task 9
- [x] **10** Kit part 1: `README.md`, `intake.decomp.md`, `decomp-architect.md`, `templates/registry-E.decomp.md`, `corpus/decomp-kernels.md`, `templates/PLACEHOLDERS.md` — Max — see Log 2026-09-07 Task 10
- [x] **11** Kit part 2: the firewall pack, docs/run READMEs, ops-setup, bootstrap, CLAUDE overlay, `pa-overlays.md`, LICENSE/NOTICE/README/CONTRIBUTING skeletons, `.clang-format` + format snippet, `tools/MANIFEST.md`; `tools/kit_lint.py` in tools-health — xHigh — see Log 2026-09-07 Task 11
- [ ] **12** Kit part 3: `SETUP.md` (§0–§10, `--answers`, the PA-2.0 version pin, the honesty section, Path A only) — Max — **then P6 rules check**
- [x] **12** Kit part 3: `SETUP.md` (Step 0–Step 10, `answers:`, the PA-2.0 version pin, the honesty section, Path A only) — Max — **then P6 rules check** — see Log 2026-09-07 Task 12
- [ ] **13** Dry-run install under D6's guardrails; fix; re-run to green; fixture + expected manifest + logs tracked under `.run/P33.5/kit-dryrun/` — xHigh
- [ ] **13.5** *(added 2026-09-07 by Drew — plan amendment, P5d)* **Tools audit + the derived tool index:** `tools/tool_census.py` — for every file under `tools/` outside submodules/vendored code: the docstring line, its consumers (Makefile/`.mk` targets, CI, the wave playbook, its SETUP row, other tools by import or subprocess), its class (LIVE · RETIRED-CAMPAIGN · ONE-OFF · PORTABLE vs PROJECT-ONLY) and its ladder phase; coverage-asserted against `find` (R32) → the generated `docs/tool-index.md` keyed by workflow step (KEEP-GEN, `--check` in tools-health, a Reference-index row, linked from The-matching-workflow + Toolchain-setup, one pointer line in how-to ch.04/05/10); the kit's `tools/MANIFEST.md` RE-DERIVED from the census (`--manifest`, freshness asserted) instead of transcribed; the hand review of the no-consumer class (91 of 326 at S91) under **Drew's criterion: a tool that served a purpose and was REQUIRED to complete the decomp is judged on its value to a FUTURE decomp — still needed (stays live and/or becomes a port task in the kit manifest), superseded by a better tool (retired, the row NAMING the successor), or a one-off (retired, the row naming what it produced)**; retirement = `git mv` → `tools/sunset/` only after the consumer census proves nothing imports it, an archive-index-style row per tool, its SETUP row moved to a retired section; Drew reviews and deletes later, as with `docs/sunset/` — xHigh (the classification draft is breadth-shaped: one read-only Explore agent, verified against the consumer list) — verify: rows == `find` count (326/326 at S91); `tool-index --check` green; every retired tool has 0 consumers AND a named successor or product; the MANIFEST regenerated byte-equal; `kit_lint` OK; `doc_links --strict` rc 0
- [ ] **14** Wiki `Start-a-new-decomp-project.md` + README/`Tools-from-this-project.md` rows + SETUP rows (R21) + decision-log entry (R31) + accelerators entry if earned — xHigh
@@ -530,91 +530,125 @@ config separate from the code so a project edits the config only).
### 2026-09-07 — Plan amendment (Drew, S91): task 13.5 added
Asked whether `tools/` had been audited the way `docs/`, `.run/` and the memory store were, the measured answer was no: of 326 tool files (submodules/vendored excluded) 224 have a SETUP row, 54 a Makefile consumer, 14 CI, 34 the playbook, 4 the how-to chapters, 58 a wiki page, 210 another tool; **91 have no runtime consumer at all**; `tools/README.md` is 1 KB; the kit's MANIFEST is an agent-transcribed table. Drew: add task 13.5 (the audit + a derived tool index + the MANIFEST re-derived), and retire only on his criterion — a tool that was required to finish the decomp is judged on its value to a future decomp: still needed, superseded (name the successor), or one-off (name what it produced). Inserted after the dry-run and before the wiki page so task 14 can link the index.
## 🛑 SESSION CHECKPOINT — Tasks 0–11 ✓; NEXT = task 12 (kit part 3: `decomp-architect/SETUP.md`; **Max** — prompt Drew, R27; then the P6 rules check)
### 2026-09-07 — Task 12 — Kit part 3: `decomp-architect/SETUP.md` (Max; S91)
**Written:** `SETUP.md` (25 KB): the human header (the exact instruction; `answers: <path>` for unattended runs); the **honesty
section** near the top (documents, configuration and one script; no gate/splitter/compiler/disassembler/emulator/permuter/context/
harness — those are `docs/tools-manifest.md`'s tasks; the generation-time values as `TODO(phase-N)` lines; the visibility decision is
the developer's); **Step 0** the execution contract (`KIT`/`ROOT`, `git -C "$ROOT"`; plan mode = "execute Steps 1–10"; copy verbatim +
Edit-tool fills, the two placeholder classes with the five generation-time literals; marked sections never edits; per-step ✓;
idempotent via the Phase-0.5 `CURRENT_PHASE.md`; explicit-path commits, no trailers, never push, never `git clean`, no relative
`rm -rf`, **never under the home directory**; the interview once or the answers file — a missing key STOPs, never defaults); **Step 1**
the PA-2.0 pin (twelve assertions incl. `PhaseEnd_Phase0.md` closed and exactly one cookbook), the ladder-in-constitution check with
the two owner options if absent (the constitution is never edited), the §E precondition (record k), Path A only (an existing decomp
repo is a STOP), the Phase-0.5 phase file from PA's template; **Step 2** the interview: 3 read-backs (PROJECT_NAME from CLAUDE.md's
title, COOKBOOK_NAME from the one `docs/*cookbook*.md`, INSTALL_DATE) + the 13 copy-time answers in one round (DUMP_PATH absolute and
outside the repo, never copied) + the `KEY: value` answers-file contract; **Step 3** the firewall (the ignore block APPENDED under a
dated line, never replacing PA's; `config/firewall.txt`, `config/firewall-fixture.sha1`, `tools/audit_public.py`, the CI workflow; **the
negative control** — plant the blob under scratch, the audit MUST exit 1 naming it, remove the one explicit file, the audit MUST exit 0;
eight positive and five negative `check-ignore` probes); **Step 4** layout + the two READMEs; **Step 5** the bootstrap skeleton + **the
checkpoint commit** (PA's own mid-install precedent); **Step 6** the flywheel documents that outlive the package (the wave playbook from
Block 6, `docs/tools-manifest.md`, `docs/decomp-kernels.md`, optionally `docs/decomp-ladder.md`); **Step 7** the registry: the seed body
from its `## §E —` line INSERTED before `## §E′` (PA's heading + pointer stay above), the renumber-by-offset fallback; **Step 8** the
overlays by marker (CLAUDE, DIGEST create, the CURRENT_PHASE template append, the PhaseEnd template INSERT before "PhaseEnd Changelog",
effort map, cookbook, ops-setup), `config/decomp-hooks.snippet.json` + `config/mcp.json.template` (Block 7 — **not** a live merge), the
methodology copy, the skeletons with the present/absent rules (`*.decomp-skeleton.md` beside an existing file; LICENSE flagged for the
verbatim text), `.clang-format`, the Makefile snippet; **Step 9** the memory seed (16 files + the index rows under a marker; the
memory dir asserted to be PA's `.claude-state/memory`; nothing under `~/.claude`); **Step 10** the leftover-placeholder audit (allowed
hits = PA's three), the audit/bash -n/py_compile checks, G-count, gitignore the package, the sorted `CREATED/APPENDED/SKIPPED` manifest
to `.run/decomp-architect-install-manifest.txt`, PhaseEnd_Phase0.5 from the template with the narrative axis, the state sweep, the
`git mv` to `logs/PhaseLog_0.5.md`, the close commit by explicit path, the five-part final message, 🛑; the install manifest;
troubleshooting (seven rows).
**Three supporting changes (X1, each a correctness fix):** (1) **class 7 of the firewall** — ProjectArchitect keeps the agent's
transcripts INSIDE the repository (`.claude-state/transcripts/`, committed while private under its H8) and a decomp's transcripts quote
the target's disassembly (the source project purged ~260,000 lines of `.s` from its session archive): `/.claude-state/transcripts/`
added under class 7 in the wiki page's fence AND the template (re-extracted, 71 → 75 lines, `gitignore_template_check` OK), with
`!/.run/README.md` under the scratch block so Step 4's README is trackable; (2) **Block 7 is no longer a live merge** — a SessionStart
hook running a stub every session and an MCP entry pointing at nothing would only add noise/prompts, and `_comment` keys inside the
hook/MCP objects risk the harness's schema; the block now installs `config/decomp-hooks.snippet.json` + `config/mcp.json.template`,
activated at Phase 2 (the JSON bodies carry no comment keys); (3) `PLACEHOLDERS.md`'s "Filled" wording aligned with the steps (answered
at Step 2, filled at Steps 3–9; generation-time as `TODO(phase-N)` at Step 8).
**Verify:** `kit_lint` OK over 44 files (leak 0; placeholders 22 == 22; syntax 0/3; gitignore 75 identical; `TODO(platform)` 7,
`TODO(phase-N)` 38); `doc_links --strict` rc 0; the structural read-through as a script — 19/19 PA installer mechanisms have a
counterpart (contract, plan-mode line, verbatim copy, per-step ✓, idempotent resume, explicit-path commits, no trailers, never push, one
interview round, the phase file, the placeholder audit, the manifest, troubleshooting, hard stop, the delete note, the fresh session,
the version pin, the write-scope guardrails, the negative control); 12/12 markers SETUP greps for exist verbatim in their templates;
SETUP names all 21 non-PA placeholders and no unlisted one; every `Step N` reference resolves (0–10); PLACEHOLDERS' step refs (2, 8,
10) exist; 0 `§`+digit. **Deviation from the plan's wording:** `§0–§10` → `Step 0 … Step 10` (the lint), `--answers` → the
`answers: <path>` clause of the instruction (a Claude Code prompt has no flags). No build input changed.
## 🛑 SESSION CHECKPOINT — Tasks 0–12 ✓; NEXT = task 13 (the dry-run install under D6's guardrails; **xHigh** — prompt Drew, R27)
### 0. How to use this block
You are a FRESH SESSION that has read `PROJECT_CONTEXT.md`, `phase-ends/DIGEST.md`, `PhaseEnd_Phase31/32/33.md` and this file, and
nothing else (R64). Replay this block verbatim, state phase / done / NEXT / effort, list the rules from the digest (R1–R83), then
WAIT for Drew. Rebuild the harness task list (17 rows incl. task 13.5, R28) marking tasks 0–11 completed and task 12 in progress.
WAIT for Drew. Rebuild the harness task list (17 rows incl. task 13.5, R28) marking tasks 0–12 completed and task 13 in progress.
### 1. Where we are
**Phase 33.5** (sub-phase; v1.32.0 → v1.32.1), gate 1 approved 2026-09-07 by Drew in plan mode at Max; effort follows the plan's
column (Max for tasks 12 and 15 — prompt at each transition, R27). Baseline HEAD `80d45b29b`; task 0 = `39d524991`; task 1 =
`a0cf302e5`; task 2 = `d06923a06`; task 3 = `5d10a0d12`; task 4 = `9970f1e62`; task 5 = `a0d4ae836`; task 6 = `6ec4786bd`; task 7 =
`21c98ed5a`; task 8 = `ae71efe56`; task 9 = `caefe9872`; S90 checkpoint = `e1463d430`; task 10 = `83de29c02`; task 11 = the commit
after this block (session S91, 2026-09-07). No build input changed; the fleet is 218/218 at the Phase-33 close and
**`make tools-health` is OK on this tree (S91, `.run/P33.5/tools_health_t11.log`)**. Tracked `.run/` = 868; `audit_public` OK;
`gate_scan` PASS; `doc_links --strict` rc 0; pending list empty. **The kit directory holds everything except `SETUP.md`:** `README.md`,
`intake.decomp.md`, `decomp-architect.md`, `corpus/decomp-kernels.md` (DK-1…DK-64), `memory-seed/` (16 + MEMORY.md),
`tools/MANIFEST.md` (325 rows by phase), and `templates/` — `registry-E.decomp.md` (G1–G65), `PLACEHOLDERS.md` (the 22-set),
`gitignore.decomp`, `firewall.txt`, `audit_public.template.py`, `firewall-fixture/{blob.bin,blob.sha1,README.md}`,
`no-rom.template.yml`, `docs-README.md`, `run-README.md`, `ops-setup.decomp.md`, `bootstrap.template.sh`, `CLAUDE.decomp-overlay.md`,
`pa-overlays.md` (7 blocks), `LICENSE.skeleton.md`, `NOTICE.src.md`, `README.skeleton.md`, `CONTRIBUTING.skeleton.md`, `.clang-format`,
`make-format.snippet.mk`. `tools/kit_lint.py` runs in tools-health (selftest + real). Tasks 12–13 finish the kit; 14–15 close.
column (Max for task 15 — prompt at each transition, R27; tasks 13, 13.5 and 14 are xHigh). Baseline HEAD `80d45b29b`; task 0 =
`39d524991`; task 1 = `a0cf302e5`; task 2 = `d06923a06`; task 3 = `5d10a0d12`; task 4 = `9970f1e62`; task 5 = `a0d4ae836`; task 6 =
`6ec4786bd`; task 7 = `21c98ed5a`; task 8 = `ae71efe56`; task 9 = `caefe9872`; S90 checkpoint = `e1463d430`; task 10 = `83de29c02`;
task 11 = `9235800fb`; the plan amendment (task 13.5 added by Drew) = `6fb2bc7f8`; task 12 = the commit after this block (session S91,
2026-09-07). No build input changed; the fleet is 218/218 at the Phase-33 close and `make tools-health` was OK at task 11 on this tree
(`.run/P33.5/tools_health_t11.log`); since then only kit files, the wiki fence (class 7) and this file changed. Tracked `.run/` = 868;
`audit_public` OK; `gate_scan` PASS; `doc_links --strict` rc 0; pending list empty. **The kit is complete on paper:** `README.md`,
`intake.decomp.md`, `SETUP.md`, `decomp-architect.md`, `corpus/decomp-kernels.md`, `memory-seed/`, `tools/MANIFEST.md`, `templates/`
(22 files incl. `firewall-fixture/`). `tools/kit_lint.py` is in tools-health. **The P6 rules check was done after task 12 (S91).**
**Already banked for task 14 (R31):** the `docs/decision-log.md` entry "P33.5 S90" — task 14 must NOT write a second one; it still owes
the wiki page `Start-a-new-decomp-project.md`, the README/`Tools-from-this-project.md` rows, the SETUP rows for the kit (the kit_lint
row exists), and an accelerators entry if the dry-run earns one. Nothing runs in the background; the headless Ghidra MCP was never
used (no RE work; nothing under `ghidra/` is tracked). The plan file `~/.claude/plans/max-effort-set-plan-encapsulated-muffin.md` is a
copy of the "Approved plan" section at the end of this file — this file is the one that counts.
the wiki page `Start-a-new-decomp-project.md`, the README/`Tools-from-this-project.md` rows, the SETUP rows for the kit, and an
accelerators entry if the dry-run earns one. **Task 13.5 (added 2026-09-07 by Drew)** follows task 13: the tools audit + the derived
tool index, the kit MANIFEST re-derived, retirement only under his criterion (still needed for a future decomp / superseded by a named
successor / one-off) — its row in the Tasks list carries the full spec. Nothing runs in the background; the headless Ghidra MCP was
never used (no RE work; nothing under `ghidra/` is tracked). The plan file `~/.claude/plans/max-effort-set-plan-encapsulated-muffin.md`
is a copy of the "Approved plan" section at the end of this file — this file is the one that counts.
### 2. What NEXT does (task 12, **Max**) — exact steps (plan D5, "Kit part 3 — SETUP.md")
**Read first:** `/mnt/z/Storage/git/ProjectArchitect/project-architect-2.0/SETUP.md` in full (THE SHAPE TO MIRROR: the execution
contract, `✓ Verify` per step, idempotent via CURRENT_PHASE.md checkboxes, commit by explicit path, never push, the install run as a
phase, the hard stop) and its `templates/CURRENT_PHASE.template.md` + `PhaseEnd.template.md` (the kit's Phase 0.5 uses them);
`decomp-architect/README.md` (the promises SETUP must keep: what it installs / does NOT, the version pin, Path A only);
`decomp-architect/templates/PLACEHOLDERS.md` (which step fills which placeholder — SETUP's steps must match its "Filled" column);
`decomp-architect/templates/pa-overlays.md` (each block's target/marker/step — SETUP applies them by marker, idempotently);
`decomp-architect/templates/firewall-fixture/README.md` (the control's exact procedure); `decomp-architect/intake.decomp.md` Part D
(the §E-empty precondition SETUP Step 7 asserts) and Part C; the plan's D5 + D6 in the "Approved plan" section below (the dry-run's
guardrails shape what SETUP may write: never under `~/.claude`, every git call `git -C <abs>`, no `git clean`, no relative `rm -rf`).
**Write `decomp-architect/SETUP.md`** — headings `## Step 0` … `## Step 10` (NOT `§N`: the lint bans `§`+digit; refer to PA's sections as
"step N" too). Contents per step: **Step 0** the execution contract (Claude Code from the project root with `KIT=./decomp-architect`;
in plan mode the plan is "execute Steps 1–10 in order", no redesign; templates copied verbatim with `cp`, placeholders filled with the
Edit tool, never retyped; every step self-verifies, STOP on a failed verify; idempotent — re-run resumes from the first unticked
checkbox of the Phase-0.5 CURRENT_PHASE; commits by explicit path, no trailers, never push; the developer answers Step 2 once — or
`--answers <file>`: "if the file exists every question is answered from it; an unanswered question STOPs, never defaults");
**Step 1** prerequisites — assert `grep -q '^> \*\*Version:\*\* 2\.0' docs/project-architect.md`, `RULES_REGISTRY.md` and
`phase-ends/` exist, `PROJECT_CONTEXT.md` exists and carries the ladder (grep "Phase 0.5" or the intake's phase names), the PA install
phase is closed (a `PhaseEnd_Phase0.md`), registry §E holds only the one-line pointer (else STOP with the renumber-by-offset fallback
spelled out), and the repo is a PA Path-A project — an existing decomp repository (any `src/*.c`, a splitter config, a `Makefile` with a
build) is an explicit STOP; then create the Phase-0.5 `CURRENT_PHASE.md` from PA's template with Steps 2–10 as checkboxes;
**Step 2** the game interview → the 13 copy-time placeholders (one compact round; `--answers` unattended; record the answers into the
Phase-0.5 log); **Step 3** the firewall — append `templates/gitignore.decomp` to `.gitignore` under a dated marker (NEVER replace PA's
block), copy `firewall.txt` → `config/firewall.txt` (fill `{{TARGET_BINARY}}`), copy `firewall-fixture/blob.sha1` →
`config/firewall-fixture.sha1`, copy `audit_public.template.py` → `tools/audit_public.py` (+x), copy `no-rom.template.yml` →
`.github/workflows/no-rom.yml`; **the control**: `mkdir -p .run/firewall-control && cp $KIT/templates/firewall-fixture/blob.bin
.run/firewall-control/planted.bin && python3 tools/audit_public.py --paths .run/firewall-control/planted.bin` must exit 1 naming the
planted file; `rm` it; `python3 tools/audit_public.py` must exit 0 (`git check-ignore` positive probes `disks/x.bin asm/x.s
extracted/x` and negative probes `src/main.c config/x.yaml`); **Step 4** layout — `mkdir -p src config tools docs .run disks
extracted dumps` + `docs/README.md` from `docs-README.md`, `.run/README.md` from `run-README.md` (fill PROJECT_NAME/INSTALL_DATE/
CONTAINER_LAYOUT); **Step 5** `bootstrap.template.sh` → `tools/bootstrap.sh` (+x, `bash -n`); **Step 6** the flywheel skeleton —
`pa-overlays.md` block 6 → `docs/wave-playbook.md` (CREATE), `tools/MANIFEST.md` → `docs/tools-manifest.md` (the Phase-1 task list),
`corpus/decomp-kernels.md` → `docs/decomp-kernels.md` (the intake's ladder cites DK ids — they must survive package deletion);
**Step 7** registry — append `registry-E.decomp.md`'s body under §E after asserting the pointer line (marker = the seed's `## §E —` line;
idempotent); **Step 8** overlays + skeletons — `CLAUDE.decomp-overlay.md` appended to `CLAUDE.md` (marker `## Decomp fail-safes`);
`pa-overlays.md` blocks 1 (CREATE `phase-ends/DIGEST.md`), 2 (APPEND to `phase-ends/CURRENT_PHASE.template.md`), 3 (APPEND to
`phase-ends/PhaseEnd.template.md`), 4 (APPEND to `docs/effort-map.md`), 5 (APPEND to `docs/<cookbook>`), 7 (MERGE `.claude/settings.json`
adding only absent keys, CREATE `.mcp.json`); `ops-setup.decomp.md` appended to `docs/ops-setup.md`; `decomp-architect.md` →
`docs/decomp-architect.md`; the skeletons → `LICENSE` (only if absent — PA does not create one; else a `LICENSE.decomp-note.md`?) NO:
write `LICENSE` from the skeleton only when no LICENSE exists, otherwise STOP and ask; `src/NOTICE.md`, `README.md` (PA creates none —
create; if one exists, append under a marker), `CONTRIBUTING.md`, `.clang-format`, `make-format.snippet.mk` appended to `Makefile`
(create a minimal Makefile if absent); generation-time placeholders written as literal `TODO(phase-N)` lines; **Step 9** memory seed
(`memory-seed/*.md` → `.claude-state/memory/`, MEMORY.md rows APPENDED — PA's 16 + the kit's 16; the `upstream: PA` files included) +
"seeded memories activate from the NEXT session"; **Step 10** verify — the leftover-placeholder audit `grep -rn "{{" --include="*.md"
--include="*.txt" --include="*.json" --include="*.sh" --include="*.py" .` must hit ONLY `decomp-architect/` and `docs/decomp-architect.md`;
`tools/audit_public.py` OK; `bash -n tools/bootstrap.sh`; JSON parses; the registry recites G1–G65; the install MANIFEST (the file list)
printed and written to `.run/decomp-architect-install-manifest.txt`; append `decomp-architect/` to `.gitignore`; write
`phase-ends/PhaseEnd_Phase0.5.md` (PA's template + the narrative axis) and `git mv` the Phase-0.5 CURRENT_PHASE to
`phase-ends/logs/PhaseLog_0.5.md`; commit by explicit path (`chore: decomp-architect Phase 0.5 — the decomp overlay installed`); the
final message: the manifest, "you may delete decomp-architect/", "start a fresh session and say Begin Phase 1", the plain-English
recap; **🛑 HARD STOP**. **The honesty section** (near the top): the installer verifies documents, configuration and the firewall audit;
it does not install a byte gate, a splitter config, a permuter harness, a decompiler context or a differential harness — those are
`docs/tools-manifest.md`'s Phase-N tasks. **Verify (task 12):** `kit_lint` clean (SETUP.md is in the package — the lint runs over it:
no `§`+digit, no `R`+digits, no source-project literals; every `{{…}}` it names is in the 22-set); a structural read-through against
PA's SETUP.md (every PA mechanism has its counterpart: contract, verify lines, idempotence, explicit-path commits, the phase file,
the hard stop); every "Filled" column of PLACEHOLDERS.md names a step that exists. Log + checkpoint; commit by explicit path.
**Then the P6 rules check** (re-read CLAUDE.md's Mandatory Behavior + the fail-safes + DIGEST §3, state "Rules check — re-read
complete. Continuing with task 13"). Task 13 is xHigh — prompt Drew to drop back (R27).
### 2. What NEXT does (task 13, **xHigh**) — exact steps (plan D6)
**Read first:** the plan's D6 in the "Approved plan" section below (the guardrails are binding); `decomp-architect/SETUP.md` in full
(the thing under test — Step 2's answers-file contract, Step 10's manifest format); `decomp-architect/README.md` step 1 (the PA
install is handed the intake); `/mnt/z/Storage/git/ProjectArchitect/project-architect-2.0/SETUP.md` (PA's own steps the subagent
must drive: its Path question, its dev interview, its Mode-1 intake + Gate 1 review + Gate 2 effort prompt, its home-directory step,
its Phase-0 close); `docs/wave-playbook.md`'s S80 addendum-2 (per-agent work dirs; the final message is one JSON line).
**Do, in this order:**
1. **Record the BEFORE values** (R57 — the dry-run must not touch the real tree or the home directory):
`sha1sum ~/.claude/settings.json ~/.claude/statusline.sh`; `ls ~/.claude/projects/-home-musashi-bfm-decomp/memory | wc -l`;
`git -C ~/bfm-decomp status --porcelain | wc -l` (0); `ls ghidra | wc -l`; `ls dumps/*.bin | wc -l` (28). Save them to
`.run/P33.5/kit-dryrun/before.txt`.
2. **The fixture** under `.run/P33.5/kit-dryrun/` (create the dir): `answers.md` — the kit's 13 keys + `INSTALL_DATE: 2026-09-07`
(fictional title, a fictional serial in the platform's format, a `DUMP_PATH` that does not exist e.g. `/nonexistent/dryrun.bin`
— SETUP only asserts it is absolute and outside the repo, container/SDK-evidence strings, goals, a license choice, a disclosure
sentence, `PUBLIC_OR_PRIVATE: private until the contract run`) PLUS a section `## For ProjectArchitect's own installer` with PA's
answers (Path A; the dev interview: advanced / decompilation / autonomous, recommendation-first, breadth welcome; the Mode-1
intake = "read decomp-architect/intake.decomp.md; the game values are above"; Gate 2: "effort Max is already set — proceed, log it
as a deviation"; **"skip PA's home-directory step entirely (no writes under ~/.claude)"**; PA's §E: the one-line pointer per the
intake's Part D); `expected-manifest.txt` — the `CREATED/APPENDED/SKIPPED` lines you expect from SETUP Step 10's format
(derive it from SETUP's install manifest section; sorted); a `.gitignore` block in the REPO's `.gitignore` under a dated comment:
`!/.run/P33.5/` `/.run/P33.5/*` `!/.run/P33.5/kit-dryrun/` `/.run/P33.5/kit-dryrun/*` `!/.run/P33.5/kit-dryrun/answers.md`
`!/.run/P33.5/kit-dryrun/expected-manifest.txt` `!/.run/P33.5/kit-dryrun/*.log` `!/.run/P33.5/kit-dryrun/*.txt` (the nested
`repo/` stays ignored).
3. **The throwaway repo:** `R=$HOME/bfm-decomp/.run/P33.5/kit-dryrun/repo` — `git -C ... init` a fresh dir; `cp -r
/mnt/z/Storage/git/ProjectArchitect/project-architect-2.0 "$R/"`; `cp -r ~/bfm-decomp/decomp-architect "$R/"` (the committed
kit); `git -C "$R" config user.name/user.email` (local). Re-runs: remove ONLY `"$R"` by its ABSOLUTE path (log it), recreate.
4. **ONE subagent** (general-purpose) with a brief that: gives `$R` as its working directory and forbids any write outside it and
any write under the home directory; requires every git call to be `git -C "$R" …`; forbids `git clean` and relative `rm -rf`;
says to run PA's `SETUP.md` first (as the installing agent, answering every question from `answers.md` — never wait for a
human; skip its home-directory step; hand its intake the kit's `intake.decomp.md`), then the kit's SETUP with `answers: <abs path
of answers.md>`; writes deliverables EARLY into `.run/P33.5/kit-dryrun/`: `install.log` (its narration, appended as it goes),
`manifest.txt` (a copy of the produced install manifest), then `verdict.json` LAST and as its ONLY final message — one JSON line
`{"status": "PASS|FAIL", "pa_install": "...", "kit_steps_completed": N, "defects": [{"step": "...", "what": "...", "fix": "..."}]}`.
Model: the session default; budget: one attempt per run; if it dies, recover its verdict from the transcript by
`tools/agent_verdicts.py`.
5. **Judge the run yourself (R14):** `diff "$R"/../manifest.txt expected-manifest.txt`; the placeholder grep of SETUP Step 10.1 run
BY YOU in `$R`; the check-ignore probes in `$R`; `grep -c '^### G' "$R"/RULES_REGISTRY.md` = 65; `ls "$R"/.claude-state/memory/*.md
| grep -vc MEMORY.md` = 32; `git -C "$R" log --format=%B | grep -ci 'co-authored'` = 0; the two commits present; **the AFTER
values equal the BEFORE values** (re-run step 1's commands; any difference = the run wrote where it must not — a defect of the
brief or the kit, fixed before anything else).
6. **Fix defects in the KIT** (SETUP/templates — never in the throwaway), re-run from step 3 to green; each re-run appends to
`install.log`'s successor (`install.2.log`, …). Every kit fix re-runs `kit_lint`.
7. Log + checkpoint (the defects found and fixed, with the step that caught each; the run count; the final diff empty); commit by
explicit path: the kit fixes, `.gitignore`, `.run/P33.5/kit-dryrun/{answers.md,expected-manifest.txt,before.txt,after.txt,*.log,
manifest.txt}`, this file. **Cut line (D6):** if still red at the end of session 3 of the phase, ship
`decomp-architect/KNOWN-DEFECTS.md` naming exactly what did not, make the re-run the split phase's first task, and the PhaseEnd
says so (R66). Task 13.5 is xHigh — no effort prompt needed after this task.
### 3. Standing facts for every task of this phase
- One commit per task, after this file's log line (R8/R42 form); commit by explicit path; no trailers (R5); Drew pushes (R6).
@@ -624,12 +658,14 @@ complete. Continuing with task 13"). Task 13 is xHigh — prompt Drew to drop ba
- Nothing moves while a wiki page / how-to chapter / `doc_links` DEFAULT document / tool docstring cites it — the referrer census
command in the plan's D3 runs before every `git mv`.
- `purge_set.txt` is never edited in this phase. Never `git clean -x`. The untracked 29 GB of `.run/` is out of scope.
- Effort transitions are prompted and waited for (R27): Max for tasks 12 and 15; xHigh otherwise.
- Effort transitions are prompted and waited for (R27): Max for task 15; xHigh otherwise (13, 13.5, 14).
- The kit's vocabulary (task 10): rules by G-id, kernels by DK-id, PA's sections as "step N", the kit's SETUP as "Step N"; source
numbers only in ```` ```calibration ```` fences; the placeholder set is `PLACEHOLDERS.md`'s 22 and nothing else (`kit_lint` enforces).
- **`make tools-health` runs longer than the 10-minute foreground cap:** launch it detached (`setsid nohup make tools-health >
.run/P33.5/<log> 2>&1 < /dev/null &`), then wait on the pid from a background Bash (`while kill -0 <pid>; do sleep 10; done`); never
as a harness background task (the memory guard killed one in S88), never sleep-poll in the foreground.
- The wiki fence and `templates/gitignore.decomp` are ONE source in two copies: edit the page, re-extract the template by script,
`gitignore_template_check` must read OK (75 lines since task 12).
---