Files
BFM-decomp/decomp-architect/SETUP.md
T
Drew T 8594081d86 kit+docs(phase-33.5): task 14.5 part 3a — dry-run 5 of the final kit (fresh throwaway, fresh Opus agent): PASS, 0 failed verify lines; the run-5 rows
- run 5 under BRIEF-run5.md (the D6 guardrails restated): ProjectArchitect 2.0 §1–§9 then the kit Steps 0–10, unattended from
  answers.md; 4 trailer-free commits; stopped_at null; manifest 57 == 57 (docs/inherited-record.md included); G 67; seeds 34/34;
  check-ignore 9/9 + 5/5; placeholder audit clean; the audit exits 0 in the throwaway; PhaseEnd_Phase0.5 + the archived log; tree
  clean; settings/statusline/memory/ghidra/dumps/~/.claude guardrails unchanged
- the agent's notes, acted on: the installer named pa-overlays.md without its templates/ folder at Steps 6 and 8 → `$KIT/templates/…`;
  its own write-scope slip (two staging files under /tmp, deleted) recorded; the manifest rule's silence on a file the installer
  creates and deletes itself noted
- the judge: my run-5 BEFORE snapshot stripped the first porcelain line's status space and so failed to exclude a deletion under the
  dry-run's own directory (the false flag of the first judge pass — re-filtered, not re-snapshotted); the judge's reader crashed on an
  empty dirty set (a one-token line) → tolerated; run-4 evidence kept under the .run4 suffix
- wiki page (five dry-runs, the run-5 row), Home/Tools/README/SETUP rows: five runs
2026-09-07 23:53:11 -06:00

29 KiB
Raw Blame History

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: " (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 — with ONE named exception, Step 3.0: ProjectArchitect's bare .run/ ignore line is rewritten to /.run/* (the two forms ignore the same files; without it no re-include under .run/ can ever work). Everything else ProjectArchitect stamped 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 " 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 one edit above a marker. ProjectArchitect's own ignore block writes the directory form .run/. Git does not descend into an excluded directory, so beneath that line no ! re-include under .run/ — the README of Step 4, the dated-exception convention for tracking irreplaceable scratch evidence — could ever take effect. If .gitignore contains a line that is exactly .run/, rewrite THAT ONE LINE to /.run/* (same files ignored; the by-contents form). SKIP if no such line exists (idempotent; runs even when Step 3.1's marker is already present). This is the single edit this installer makes above a marker (Step 0.4). ✓ git -C "$ROOT" check-ignore -v .run/x names a /.run/* line; grep -cx '\.run/' .gitignore prints 0.
  2. 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.
  3. cp "$KIT/templates/firewall.txt" config/firewall.txt; fill {{TARGET_BINARY}}.
  4. 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).
  5. cp "$KIT/templates/audit_public.template.py" tools/audit_public.py && chmod +x tools/audit_public.py.
  6. mkdir -p .github/workflows && cp "$KIT/templates/no-rom.template.yml" .github/workflows/no-rom.yml.
  7. 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.
  8. 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 $KIT/templates/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 task for its phase; the verbatim reference implementation of each is in the kit's corpus/tools/<phase>/ (the kit master copy — see the ops reference's corpus row)." 2b. docs/knowledge-corpus.md — cp "$KIT/corpus/cookbook/README.md" (the front page that says what transfers from the inherited cookbook, its symptom index and its codegen map — the files themselves stay in the kit master copy beside it). 2c. docs/inherited-record.md — cp "$KIT/corpus/record/README.md" (the front page of the inherited record: the source project's how-to, decision log, accelerators, retrospective, playbook, effort doctrine, readability charter and every phase-end — the files stay in the kit master copy beside it; a rule's or kernel's provenance: line is followed there).
  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 equals the "In all" figure of that file's own Coverage section (both derived, never typed here); the manifest's row count equals the total its own header states (grep -c '^| \' docs/tools-manifest.md== the "Table rows in all: N" figure in its Coverage line — the live rows plus the superseded pointer rows, both derived, never typed here);docs/knowledge-corpus.mdanddocs/inherited-record.md` exist.

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–G67, 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+67>, then insert as in 3. Record the offset in the log and the PhaseEnd.

✓ Verify: grep -c '^### G' RULES_REGISTRY.md = 67 (or 67 + 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 ← $KIT/templates/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 = 34 (ProjectArchitect's 16 + the kit's 18); 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: command grep -rln '{{' --include='*.md' --include='*.txt' --include='*.sh' --include='*.py' --include='*.yml' --include='*.json' --include='*.mk' --include='Makefile' . | grep -vE '^\./(decomp-architect|project-architect-2\.0)/' — with a grep that does NOT honour ignore files (plain GNU grep via command grep; a wrapper that honours .gitignore silently narrows the result — if in doubt, find . -type f | xargs grep -l '{{' and filter the same way); both package folders are dropped by the filter, never by ignore rules. The result 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. The audit cannot tell an unfilled placeholder from prose that QUOTES the token, so the rule that keeps it a true signal is: a tracked document never pastes a literal double-brace token — it names the placeholder in prose (this installer's own phase file and PhaseEnd included; the dry-run tripped on both).
  2. python3 tools/audit_public.py → exit 0. bash -n tools/bootstrap.sh. Syntax-check the audit WITHOUT writing bytecode: python3 -c "compile(open('tools/audit_public.py').read(), 'tools/audit_public.py', 'exec')" (the py_compile module always writes a __pycache__, whatever the environment says; a __pycache__ left in a fresh install is untracked litter).
  3. grep -c '^### G' RULES_REGISTRY.md = 67 (+ 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, sorted, one line per FILE, and print it. Exactly these lines and no others: CREATED <path> for every file this installer created (Steps 1–9, plus this step's own manifest file, the PhaseEnd and the archived phase log of step 6 — write the manifest after step 6 so they are in it; a file created and then moved is listed once, under its final path, so the phase file appears only as phase-ends/logs/PhaseLog_0.5.md); APPENDED <path> (<marker>) for every file it appended a marked section to (.gitignore once, with both markers named); SKIPPED <path> (<reason>) for every OPTIONAL artifact this run did not write — the two *.decomp-skeleton.md beside an existing README/CONTRIBUTING, docs/decomp-ladder.md, .claude/settings.json and .mcp.json (never touched at Phase 0.5) — so the reader sees the decision, not an absence. Directories are never listed. (An unattended run diffs the manifest against an expected one, so the set of lines must be derivable from this rule alone.)
  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–G67 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. Append the Phase-0.5 synopsis (one paragraph) to phase-ends/DIGEST.md part 2 — the digest's own maintenance rule. 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–G67)                              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 negative probe for .run/README.md fails (the path is ignored) → ProjectArchitect's bare .run/ line is still in .gitignore; Step 3.0 did not run. Re-run Step 3.
  • 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.