diff --git a/.claude/skills/porch/SKILL.md b/.claude/skills/porch/SKILL.md index 24dd63d9e..9ed38959c 100644 --- a/.claude/skills/porch/SKILL.md +++ b/.claude/skills/porch/SKILL.md @@ -49,8 +49,9 @@ porch pending # List all gates waiting for approval ## Critical rules -- **Builders must NEVER call `porch approve`** — only humans approve gates -- **Never edit `status.yaml` directly** — porch manages all state +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Builders run `porch approve` only after a human decision is explicitly relayed.) +- Never hand-edit `status.yaml` — only porch commands modify project state. - Builders signal completion with `porch done`, not `porch approve` - `porch run` is for strict mode only — soft mode builders follow the protocol document manually - When running `porch approve` from the architect, use a subshell if you need worktree context: `(cd /path/to/worktree && porch approve ...)` diff --git a/.codex/skills/porch/SKILL.md b/.codex/skills/porch/SKILL.md index 24dd63d9e..9ed38959c 100644 --- a/.codex/skills/porch/SKILL.md +++ b/.codex/skills/porch/SKILL.md @@ -49,8 +49,9 @@ porch pending # List all gates waiting for approval ## Critical rules -- **Builders must NEVER call `porch approve`** — only humans approve gates -- **Never edit `status.yaml` directly** — porch manages all state +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Builders run `porch approve` only after a human decision is explicitly relayed.) +- Never hand-edit `status.yaml` — only porch commands modify project state. - Builders signal completion with `porch done`, not `porch approve` - `porch run` is for strict mode only — soft mode builders follow the protocol document manually - When running `porch approve` from the architect, use a subshell if you need worktree context: `(cd /path/to/worktree && porch approve ...)` diff --git a/AGENTS.md b/AGENTS.md index a483432ac..a48db2522 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,7 @@ map to open the full arch.md / lessons-learned.md when relevant. **THIS IS THE CODEV SOURCE REPOSITORY - WE ARE SELF-HOSTED** -This project IS Codev itself, and we use our own methodology for development. All new features and improvements to Codev should follow the SPIR protocol defined in `codev/protocols/spir/protocol.md`. +This project IS Codev itself, and we use our own methodology for development. All new features and improvements to Codev should follow the SPIR protocol defined in `codev-skeleton/protocols/spir/protocol.md` (this repo's shadow copies were removed by Spec 1252 — the skeleton is the single owner and the runtime resolves it). ### Important: Understanding This Repository's Structure @@ -47,7 +47,7 @@ This repository has a dual nature that's important to understand: ### Release Process -To release a new version, tell the AI: `Let's release v1.6.0`. The AI follows the **RELEASE protocol** (`codev/protocols/release/protocol.md`). Release candidate workflow and local testing procedures are documented there. For local testing shortcuts, see `codev/resources/testing-guide.md`. +To release a new version, tell the AI: `Let's release v1.6.0`. The AI follows the **RELEASE protocol** (`codev/protocols/release/protocol.md` — a codev-local protocol, deliberately not shipped). Release candidate workflow and local testing procedures are documented there. For local testing shortcuts, see `codev/resources/testing-guide.md`. ### Local Build Testing @@ -84,14 +84,14 @@ When making changes to UI code (tower, dashboard, terminal), you MUST test using You are working in the Codev project itself, with multiple development protocols available: **Available Protocols**: -- **SPIR**: Multi-phase development with consultation - `codev/protocols/spir/protocol.md` -- **ASPIR**: Autonomous SPIR (no human gates on spec/plan) - `codev/protocols/aspir/protocol.md` -- **AIR**: Autonomous Implement & Review for small features - `codev/protocols/air/protocol.md` -- **BUGFIX**: Bug fixes from GitHub issues - `codev/protocols/bugfix/protocol.md` -- **PIR**: Plan / Implement / Review — issue-driven with two pre-PR human gates (plan-approval, dev-approval) plus a post-PR `pr` gate. Lighter than SPIR; stronger than BUGFIX/AIR. Useful when a change needs design review before coding OR pre-PR testing of running code (e.g., mobile / UI / cross-platform). See `codev/protocols/pir/protocol.md`. -- **EXPERIMENT**: Disciplined experimentation - `codev/protocols/experiment/protocol.md` -- **MAINTAIN**: Codebase maintenance (code hygiene + documentation sync) - `codev/protocols/maintain/protocol.md` -- **RESEARCH**: Multi-agent research with 3-way investigation, synthesis, and critique - `codev/protocols/research/protocol.md` +- **SPIR**: Multi-phase development with consultation - `codev-skeleton/protocols/spir/protocol.md` +- **ASPIR**: Autonomous SPIR (no human gates on spec/plan) - `codev-skeleton/protocols/aspir/protocol.md` +- **AIR**: Autonomous Implement & Review for small features - `codev-skeleton/protocols/air/protocol.md` +- **BUGFIX**: Bug fixes from GitHub issues - `codev-skeleton/protocols/bugfix/protocol.md` +- **PIR**: Plan / Implement / Review — issue-driven with two pre-PR human gates (plan-approval, dev-approval) plus a post-PR `pr` gate. Lighter than SPIR; stronger than BUGFIX/AIR. Useful when a change needs design review before coding OR pre-PR testing of running code (e.g., mobile / UI / cross-platform). See `codev-skeleton/protocols/pir/protocol.md`. +- **EXPERIMENT**: Disciplined experimentation - `codev-skeleton/protocols/experiment/protocol.md` +- **MAINTAIN**: Codebase maintenance (code hygiene + documentation sync) - `codev-skeleton/protocols/maintain/protocol.md` +- **RESEARCH**: Multi-agent research with 3-way investigation, synthesis, and critique - `codev-skeleton/protocols/research/protocol.md` ### File Resolution (How Codev Finds Protocols and Templates) @@ -121,7 +121,7 @@ afx spawn --protocol --help This succeeds if the protocol is registered (including via the skeleton fallback in tier 4 of the resolution chain) and errors helpfully otherwise. The CLI is the source of truth — defer to it when in doubt. Key locations: -- Protocol details: `codev/protocols/` (Choose appropriate protocol) +- Protocol details: `codev-skeleton/protocols/` (single owner; the runtime resolves the embedded skeleton — `codev/protocols/` holds only local-only protocols like RELEASE) - **Project tracking**: GitHub Issues (source of truth for all projects) - Specifications go in: `codev/specs/` - Plans go in: `codev/plans/` @@ -209,7 +209,7 @@ validated: [gemini, codex, claude] - No spec/plan artifacts needed - Single builder can fix independently -**BUGFIX uses GitHub Issues as source of truth.** See `codev/protocols/bugfix/protocol.md`. +**BUGFIX uses GitHub Issues as source of truth.** See `codev-skeleton/protocols/bugfix/protocol.md`. ### Use AIR for (small features from GitHub issues): - Small features (< 300 LOC) fully described in a **GitHub Issue** @@ -217,7 +217,7 @@ validated: [gemini, codex, claude] - No spec/plan artifacts — review goes in the PR body - Would be overkill for full SPIR/ASPIR ceremony -**AIR uses GitHub Issues as source of truth.** Two phases: Implement → Review. See `codev/protocols/air/protocol.md`. +**AIR uses GitHub Issues as source of truth.** Two phases: Implement → Review. See `codev-skeleton/protocols/air/protocol.md`. ### Use PIR for (engineer-judged — based on the nature of the work, not its size): @@ -237,7 +237,7 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - User-journey changes that need a full-flow exercise - Performance-sensitive changes that need profiling on the running app -**PIR uses GitHub Issues as source of truth.** Three phases: Plan (gated by `plan-approval`) → Implement (gated by `dev-approval`) → Review (PR + CMAP-2 at PR, then gated by `pr` for merge synchronization — matching SPIR's pr-gate pattern but with no post-merge verify phase). Plan and review artifacts live in `codev/plans/` and `codev/reviews/` on the builder branch, ship to main with the merge. Review file is shaped identically to SPIR's (Summary + Architecture Updates + Lessons Learned + supporting sections) so `codev/reviews/` stays semantically consistent across protocols. Lighter than SPIR (no spec phase — the issue body is the implicit spec; consult footprint matches BUGFIX/AIR's "one consult at PR" pattern). Stronger than BUGFIX/AIR (two human gates pre-PR — the human reviews the running worktree at the `dev-approval` gate, not the PR diff post-creation). CMAP at the PR is a **single advisory pass** (`max_iterations: 1`) — no iterate-until-APPROVE loop; a `REQUEST_CHANGES` is escalated to the human at the `pr` gate, not auto-re-reviewed. The CMAP-2 footprint is a design invariant: porch's model precedence is *config > protocol*, so a project-wide `porch.consultation.models` (e.g. a SPIR-tuned 3-model list) silently inflates PIR — leave it unset or scope it per-protocol to preserve the BUGFIX/AIR-parity cost. See `codev/protocols/pir/protocol.md`. +**PIR uses GitHub Issues as source of truth.** Three phases: Plan (gated by `plan-approval`) → Implement (gated by `dev-approval`) → Review (PR + CMAP-2 at PR, then gated by `pr` for merge synchronization — matching SPIR's pr-gate pattern but with no post-merge verify phase). Plan and review artifacts live in `codev/plans/` and `codev/reviews/` on the builder branch, ship to main with the merge. Review file is shaped identically to SPIR's (Summary + Architecture Updates + Lessons Learned + supporting sections) so `codev/reviews/` stays semantically consistent across protocols. Lighter than SPIR (no spec phase — the issue body is the implicit spec; consult footprint matches BUGFIX/AIR's "one consult at PR" pattern). Stronger than BUGFIX/AIR (two human gates pre-PR — the human reviews the running worktree at the `dev-approval` gate, not the PR diff post-creation). CMAP at the PR is a **single advisory pass** (`max_iterations: 1`) — no iterate-until-APPROVE loop; a `REQUEST_CHANGES` is escalated to the human at the `pr` gate, not auto-re-reviewed. The CMAP-2 footprint is a design invariant: porch's model precedence is *config > protocol*, so a project-wide `porch.consultation.models` (e.g. a SPIR-tuned 3-model list) silently inflates PIR — leave it unset or scope it per-protocol to preserve the BUGFIX/AIR-parity cost. See `codev-skeleton/protocols/pir/protocol.md`. ### Use SPIR for (new features): - Creating a **new feature from scratch** (no existing spec to amend) @@ -252,7 +252,7 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - Builder runs autonomously through Specify → Plan → Implement → Review (→ Verify) - Human approval still required at the PR gate before merge -**ASPIR is identical to SPIR** except `spec-approval` and `plan-approval` gates are removed. Both include an optional verify phase after review. See `codev/protocols/aspir/protocol.md`. +**ASPIR is identical to SPIR** except `spec-approval` and `plan-approval` gates are removed. Both include an optional verify phase after review. See `codev-skeleton/protocols/aspir/protocol.md`. ### Use EXPERIMENT for: - Testing new approaches or techniques @@ -278,6 +278,19 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - Small bug fixes in templates - Dependency updates +## Scar Rules (always in force) + +Hard-won prohibitions from real incidents. Registered in +`codev/resources/scar-rules.yaml` (Spec 1252); CI fails if any is deleted or +reworded. The worktree, workspace-root, and staging rules appear in their +topical sections below; the rest live here: + +- Never run `git reset --hard`, `git checkout -- .`, `git clean -fd`, or `git stash` without explicit human permission — they destroy uncommitted work. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never kill a shellper process without verifying it is an orphan (match each PID to its workspace via Tower) — an 'extra' shellper may be a live architect session. +- Never restart or stop Tower without explicit human permission — it kills every running builder session. + ## Core Workflow 1. **When asked to build NEW FEATURES FOR CODEV**: Start with the Specification phase @@ -289,10 +302,8 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change ``` project-root/ ├── codev/ -│ ├── protocols/ # Development protocols -│ │ ├── spir/ # Multi-phase development with consultation -│ │ ├── experiment/ # Disciplined experimentation -│ │ └── maintain/ # Codebase maintenance (code + docs) +│ ├── protocols/ # LOCAL-ONLY protocols (e.g. release/) — framework +│ │ └── release/ # protocols resolve from codev-skeleton/ (Spec 1252) │ ├── maintain/ # MAINTAIN protocol runtime artifacts │ │ └── .trash/ # Soft-deleted files (gitignored, 30-day retention) │ ├── projects/ # Active project state (managed by porch) @@ -383,151 +394,15 @@ Codev provides five CLI tools. For complete reference documentation, see: ## Runnable Worktrees -When configured, each builder worktree (`.builders//`) becomes runnable — reviewers can run whatever your dev command starts against the builder's branch — a dev server, `cargo run`, `expo start`, a test watcher, a build script, whatever iterates on your project — without `cd`'ing, manually installing, or finding the right command. Opt-in via `.codev/config.json`; unconfigured repos see zero behavior change. - -### Config: the `worktree` block - -```jsonc -{ - "worktree": { - "symlinks": ["..."], // glob patterns of files to symlink from root into each new worktree - "postSpawn": ["..."], // shell commands run inside each new worktree after createWorktree - "devCommand": "..." // consumed by `afx dev ` - } -} -``` - -- `symlinks`: globs resolve from the workspace root; matches symlink into the worktree at the same relative path. Root `.env` and `.codev/config.json` are *always* symlinked regardless. **Symlinks, not copies** — edits to main's env files reflect instantly in any running dev session. A directory match is silently skipped (so a glob can't mask the worktree's own source) **unless** the entry ends with a trailing slash: `".local-user-data/"` is treated as a literal path and symlinks the directory whole (shared with the parent, not branch-isolated; a dangling link is fine if the source doesn't exist yet). -- `postSpawn`: each command runs sequentially with `cwd` = worktree path. Non-zero exit aborts the spawn loud (half-built worktree stays for inspection). -- `devCommand`: the foreground command that starts your dev process (a server, a watcher, `cargo run`, `expo start`, a build script — whatever iterates on your project). Required for `afx dev` to work. - -**Codev does not auto-detect your stack.** Pick the recipe below that matches your toolchain. - -### CLI - -```bash -afx dev # start dev in 's worktree -afx dev main # start dev in the MAIN workspace (Codev-managed) -afx dev --stop # stop the currently running dev PTY (builder or main) -``` - -Only one dev PTY runs at a time (by design — see "URLs are load-bearing" below), across **{main + all builders}**. `main` is a reserved target: it runs `worktree.devCommand` in the main checkout as a Codev-managed, swappable PTY, symmetric with builders. Starting any target while another is up prompts for swap (`afx dev ` while `main` runs, or vice-versa); same-target requests print the existing terminal URL and exit. Like builder dev, main dev is a **non-persistent** PTY — a Tower restart (`pnpm -w run local-install`, crash) kills it; re-run to restart. - -**Launch main dev via `afx dev main`, not a bare `pnpm dev`.** A manually-run `pnpm dev` at the repo root is invisible to Codev (the deliberate "never kill what it didn't spawn" policy) — start a builder dev while it holds the ports and the builder dev silently fails to bind, or worse serves main's code under the worktree URL. `afx dev main` makes it a managed PTY that swap-detection can cleanly stop first. This only helps if you use it *consistently*; a hand-started `pnpm dev` stays unmanaged. - -### VSCode - -The same actions are available via right-click on any builder row in the Codev sidebar (Builders or Needs Attention view): - -- **Codev: Open Builder Terminal** — opens that builder's AI terminal in a VSCode tab (same as left-clicking the row). -- **Codev: Open Worktree Folder** — opens `.builders//` in the OS file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux). -- **Codev: Run Worktree Setup** — applies the configured `worktree.symlinks` and runs the `worktree.postSpawn` commands against the existing worktree (mirrors what spawn does, minus the git steps). Idempotent: existing symlinks are skipped, missing ones added. Useful when the lockfile changed (reinstall deps), `symlinks` or `postSpawn` was extended after the builder spawned, a symlink was accidentally deleted, or the original setup aborted mid-run. Opens a fresh VSCode terminal so install output streams live. Available via CLI too: `afx setup `. -- **Codev: View Diff** — opens a single unified diff editor for `main...HEAD` of that builder's worktree, with a file-list pane on the left (matches VSCode's built-in Source Control "Working Tree" view). Status icons indicate added / modified / deleted. Empty diff → friendly toast. -- **Codev: Run Dev** — reads `worktree.devCommand` from `.codev/config.json`, asks Tower to spawn a dev PTY in the builder's worktree, and opens it as a VSCode terminal tab named `Codev: (dev)`. If another builder's dev is already running, you get a modal asking whether to swap. -- **Codev: Stop Dev** — kills the running dev PTY and closes its tab. - -The Codev sidebar's **Workspace** view also carries a dev control for *whatever folder this VSCode window is rooted at* (it is not "main"-specific): - -- **Start Dev** — runs `worktree.devCommand` for the current workspace. Target is resolved from the open folder: the main checkout → `main`; a `.builders//` worktree opened as its own window (e.g. via *Open Worktree as Workspace*) → that builder. Same single-slot swap model as builder dev (prompts if another dev is running). The row tooltip names the resolved target. -- **Stop Dev** — stops this workspace's dev; the row appears only while it is running. Scoped to the resolved target — it does not touch other devs. - -The three commands are also available from the command palette (Cmd+Shift+P). No default keybindings; bind via `keybindings.json` if you use them often. - -### URLs are load-bearing - -The dev PTY uses **the same ports and URLs as main** intentionally. OAuth callbacks, CORS allowlists, cookie scoping, CSP `connect-src`, webhook URLs are all keyed off origin — running the worktree on a different port would break them. Consequence: stop main's `pnpm dev` before `afx dev`. If you don't, the spawned dev fails at bind time with its own `EADDRINUSE`. Prefer `afx dev main` (or the Workspace view's *Start Dev* row) over a hand-run `pnpm dev` so Codev owns the PTY and swap-detection can stop it for you automatically. - -### Cleanup semantics - -`afx dev --stop` and the swap path kill the entire PTY process group (SIGTERM, escalating to SIGKILL after 5s via `PtySession.kill`). That signals every grandchild of a monorepo dev orchestrator (`pnpm dev`, `turbo dev`, `pnpm -r --parallel run dev`, etc.) simultaneously. The OS reclaims ports as a consequence — Codev never touches ports directly. - -**Orphan recovery** — if Tower itself hard-crashes mid-dev and a process is left holding a port outside Codev's records: - -```bash -lsof -ti : | xargs kill # one port -lsof -ti :3000,:3001,:4000 | xargs kill # several at once -``` - -### Runnable Worktree Recipes - -Ready-to-paste blocks per stack. Adjust ports / paths to your project. - -**pnpm monorepo (Next.js + Turbo style):** -```json -{ - "worktree": { - "symlinks": [".env.local", ".env.development.local", "packages/*/.env", "packages/*/.env.local", "turbo.json"], - "postSpawn": ["pnpm install --frozen-lockfile"], - "devCommand": "pnpm dev" - } -} -``` - -**npm (single package):** -```json -{ - "worktree": { - "symlinks": [".env.local", ".env.development"], - "postSpawn": ["npm ci"], - "devCommand": "npm run dev" - } -} -``` - -**yarn:** -```json -{ - "worktree": { - "symlinks": [".env.local"], - "postSpawn": ["yarn install --frozen-lockfile"], - "devCommand": "yarn dev" - } -} -``` - -**bun:** -```json -{ - "worktree": { - "symlinks": [".env.local"], - "postSpawn": ["bun install --frozen-lockfile"], - "devCommand": "bun dev" - } -} -``` - -**cargo (Rust):** -```json -{ - "worktree": { - "symlinks": [".env"], - "postSpawn": [], - "devCommand": "cargo run" - } -} -``` - -**poetry / uv (Python):** -```json -{ - "worktree": { - "symlinks": [".env", ".env.local"], - "postSpawn": ["uv sync"], - "devCommand": "uv run python -m myapp" - } -} -``` +Builder worktrees (and `main`) can run your dev command via `afx dev +` — symlinked env, `postSpawn` install hooks, single dev PTY +with swap-on-conflict, VSCode commands, and same-ports-as-main URL semantics +(OAuth/CORS/cookies are origin-keyed, so worktree devs bind main's ports). +Configure via the `worktree` block in `.codev/config.json`. -**go mod:** -```json -{ - "worktree": { - "symlinks": [".env"], - "postSpawn": ["go mod download"], - "devCommand": "go run ./cmd/server" - } -} -``` +Full reference — config schema, per-stack recipes, CLI/VSCode surfaces, +cleanup and orphan recovery: `codev/resources/commands/agent-farm.md` +§ "Runnable Worktrees". ## Architect-Builder Pattern @@ -540,30 +415,12 @@ For detailed commands, configuration, and architecture, see: - `codev/resources/arch.md` - Terminal architecture, state management - `codev/resources/workflow-reference.md` - Stage-by-stage workflow -### 🚨 NEVER DESTROY BUILDER WORKTREES 🚨 - -**When a worktree already exists for a project:** -1. Use `afx spawn XXXX --resume` -2. If `--resume` fails → **ASK THE USER** -3. Only destroy if the user explicitly says to - -**NEVER run without EXPLICIT user request:** -- `git worktree remove` (with or without --force) -- `git branch -D` on builder branches -- `afx cleanup` followed by fresh spawn - -**You are NOT qualified to judge what's expendable.** It is NEVER your call to delete a worktree. - -### 🚨 ALWAYS Operate From the Main Workspace Root 🚨 +### Scar rules — worktrees and the workspace root -**ALL `afx` commands (`afx spawn`, `afx send`, `afx status`, `afx workspace`, `afx cleanup`) MUST be run from the repository root on the `main` branch.** +Never destroy builder worktrees (`git worktree remove`, `git branch -D` on builder branches, `afx cleanup` + respawn). Use `afx spawn --resume`; if it fails, ask the human — what is expendable is never your call. -- **NEVER** run `afx spawn` from inside a builder worktree — builders will get nested inside that worktree, breaking everything -- **NEVER** run `afx workspace start` from a worktree — there is no separate workspace per worktree -- **NEVER** `cd` into a worktree to run afx commands -- The **only exception** is `porch` commands that need worktree context (e.g. `porch approve` from a builder's worktree) - -**What happened**: On 2026-02-21, `afx spawn` was run from inside a builder's worktree. All new builders were nested inside that worktree, `afx send` couldn't find them, and `afx status` showed "not active in tower". Multiple builders had to be killed and respawned. +Run `afx` commands only from the main workspace root, never from inside a builder worktree — spawning from a worktree nests builders and breaks the workspace. +(The only exception is `porch` commands that need worktree context, e.g. `porch approve` from a builder's worktree.) ### Pre-Spawn Rule @@ -589,36 +446,17 @@ Agent Farm is configured via `.codev/config.json` at the project root. Created d ## Inter-agent messaging -Agents within a workspace communicate through `afx send`. Four addressing forms are supported: - -### Addressing forms - -| Form | Meaning | Allowed from | -|---|---|---| -| `afx send "msg"` | Send to a specific builder (e.g. `afx send 0823 "..."`). | Any sender. | -| `afx send architect "msg"` | From a builder: routes to the spawning architect via affinity (per #774). From an architect (or any non-builder sender): routes to the architect named `main` if present, else the first registered architect. | Any sender. | -| `afx send architect: "msg"` | Explicit per-architect addressing. **Architects (including `main`)**: open address grammar — any architect can address any other architect. This is the sibling-architect messaging form. **Builders**: allowed ONLY when `` matches the builder's own `spawnedByArchitect`. Mismatches are rejected by the spoofing check at `tower-messages.ts:213-218`. From a builder, this is an explicit form of the affinity routing, NOT an override. | Any sender (with the spoofing constraint above for builders). | -| `afx send :architect "msg"` | Cross-workspace addressing (e.g. `afx send marketmaker:architect "..."`). | Any sender. | - -### Sibling-architect messaging - -When a workspace hosts more than one architect (added via `afx workspace add-architect --name `), sibling architects message each other via the `architect:` form. Example: - -```bash -# From main's terminal to a sibling architect named ob-refine -afx send architect:ob-refine "PR-iter-2 feedback ready" -``` +Agents message each other with `afx send`: `afx send "msg"`, +`afx send architect "msg"` (routes to the spawning architect via affinity), +`afx send architect:` (explicit; builders may only name their spawning +architect — the spoofing check rejects others), and +`afx send :architect` (cross-workspace). Discover active agents +with `afx status`; each builder also keeps a narrative thread at +`codev/state/_thread.md` (in-flight: under `.builders//`; +post-merge: on `main`). -This works because sender = architect bypasses the spoofing check. - -### Builder spoofing-check (verified at `tower-messages.ts:213-218`) - -Builder `spir-823` running `afx send architect:ob-refine "..."` is rejected unless its `spawnedByArchitect == 'ob-refine'`. A builder cannot use `architect:` to address an architect other than its spawning architect — that's an attempted spoof. - -### Discovering active agents - -- `afx status` lists all architects (post-#786) alongside builders, with names, terminal IDs, and PIDs where available. -- Each active builder maintains a free-text narrative log at `codev/state/_thread.md` (relative to its worktree, so `.builders//codev/state/_thread.md` from the main workspace root). **In-flight discovery**: `ls .builders/*/codev/state/*.md` and `cat .builders//codev/state/_thread.md`. **Post-merge discovery**: after a builder's PR merges, its thread lands in `codev/state/` on `main`, alongside `codev/reviews/` — list with `ls codev/state/` and read with `cat codev/state/_thread.md` from the main checkout. +Full addressing grammar, sibling-architect messaging, and the spoofing-check +details: `codev/resources/commands/agent-farm.md` § "afx send". ## Porch - Protocol Orchestrator @@ -640,23 +478,15 @@ State is stored in `codev/projects/-/status.yaml`, managed automatical ## Git Workflow -### 🚨 ABSOLUTE PROHIBITION: NEVER USE `git add -A` or `git add .` 🚨 +### Staging (scar rule) -**THIS IS A CRITICAL SECURITY REQUIREMENT - NO EXCEPTIONS** - -```bash -git add -A # ABSOLUTELY FORBIDDEN -git add . # ABSOLUTELY FORBIDDEN -git add --all # ABSOLUTELY FORBIDDEN -``` +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. -**MANDATORY APPROACH - ALWAYS ADD FILES EXPLICITLY**: ```bash -git add codev/specs/42-feature.md -git add src/components/TodoList.tsx +git add codev/specs/42-feature.md src/components/TodoList.tsx ``` -**BEFORE EVERY COMMIT**: Run `git status`, add each file explicitly by name. +Before every commit: run `git status`, add each file by name. ### Commit Messages ``` @@ -727,8 +557,8 @@ git log --oneline --all | grep -i "feature-name" ## Important Notes -1. **ALWAYS check `codev/protocols/spir/protocol.md`** for detailed phase instructions -2. **Use provided templates** from `codev/protocols/spir/templates/` +1. **Detailed phase instructions arrive with the work** — the full SPIR protocol text is inlined into every spawn prompt, and porch delivers each phase's instructions. Don't fetch protocol files by path (the resolver serves them; see File Resolution above). For orientation reading, the source is `codev-skeleton/protocols/spir/protocol.md`. +2. **Templates are delivered by porch phase prompts** — the spec/plan/review structures arrive in the phase task; no need to fetch them from the skeleton by path. 3. **Document all deviations** from the plan with reasoning 4. **Create atomic commits** for each phase completion 5. **Maintain >90% test coverage** where possible diff --git a/CLAUDE.md b/CLAUDE.md index a483432ac..a48db2522 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,7 +24,7 @@ map to open the full arch.md / lessons-learned.md when relevant. **THIS IS THE CODEV SOURCE REPOSITORY - WE ARE SELF-HOSTED** -This project IS Codev itself, and we use our own methodology for development. All new features and improvements to Codev should follow the SPIR protocol defined in `codev/protocols/spir/protocol.md`. +This project IS Codev itself, and we use our own methodology for development. All new features and improvements to Codev should follow the SPIR protocol defined in `codev-skeleton/protocols/spir/protocol.md` (this repo's shadow copies were removed by Spec 1252 — the skeleton is the single owner and the runtime resolves it). ### Important: Understanding This Repository's Structure @@ -47,7 +47,7 @@ This repository has a dual nature that's important to understand: ### Release Process -To release a new version, tell the AI: `Let's release v1.6.0`. The AI follows the **RELEASE protocol** (`codev/protocols/release/protocol.md`). Release candidate workflow and local testing procedures are documented there. For local testing shortcuts, see `codev/resources/testing-guide.md`. +To release a new version, tell the AI: `Let's release v1.6.0`. The AI follows the **RELEASE protocol** (`codev/protocols/release/protocol.md` — a codev-local protocol, deliberately not shipped). Release candidate workflow and local testing procedures are documented there. For local testing shortcuts, see `codev/resources/testing-guide.md`. ### Local Build Testing @@ -84,14 +84,14 @@ When making changes to UI code (tower, dashboard, terminal), you MUST test using You are working in the Codev project itself, with multiple development protocols available: **Available Protocols**: -- **SPIR**: Multi-phase development with consultation - `codev/protocols/spir/protocol.md` -- **ASPIR**: Autonomous SPIR (no human gates on spec/plan) - `codev/protocols/aspir/protocol.md` -- **AIR**: Autonomous Implement & Review for small features - `codev/protocols/air/protocol.md` -- **BUGFIX**: Bug fixes from GitHub issues - `codev/protocols/bugfix/protocol.md` -- **PIR**: Plan / Implement / Review — issue-driven with two pre-PR human gates (plan-approval, dev-approval) plus a post-PR `pr` gate. Lighter than SPIR; stronger than BUGFIX/AIR. Useful when a change needs design review before coding OR pre-PR testing of running code (e.g., mobile / UI / cross-platform). See `codev/protocols/pir/protocol.md`. -- **EXPERIMENT**: Disciplined experimentation - `codev/protocols/experiment/protocol.md` -- **MAINTAIN**: Codebase maintenance (code hygiene + documentation sync) - `codev/protocols/maintain/protocol.md` -- **RESEARCH**: Multi-agent research with 3-way investigation, synthesis, and critique - `codev/protocols/research/protocol.md` +- **SPIR**: Multi-phase development with consultation - `codev-skeleton/protocols/spir/protocol.md` +- **ASPIR**: Autonomous SPIR (no human gates on spec/plan) - `codev-skeleton/protocols/aspir/protocol.md` +- **AIR**: Autonomous Implement & Review for small features - `codev-skeleton/protocols/air/protocol.md` +- **BUGFIX**: Bug fixes from GitHub issues - `codev-skeleton/protocols/bugfix/protocol.md` +- **PIR**: Plan / Implement / Review — issue-driven with two pre-PR human gates (plan-approval, dev-approval) plus a post-PR `pr` gate. Lighter than SPIR; stronger than BUGFIX/AIR. Useful when a change needs design review before coding OR pre-PR testing of running code (e.g., mobile / UI / cross-platform). See `codev-skeleton/protocols/pir/protocol.md`. +- **EXPERIMENT**: Disciplined experimentation - `codev-skeleton/protocols/experiment/protocol.md` +- **MAINTAIN**: Codebase maintenance (code hygiene + documentation sync) - `codev-skeleton/protocols/maintain/protocol.md` +- **RESEARCH**: Multi-agent research with 3-way investigation, synthesis, and critique - `codev-skeleton/protocols/research/protocol.md` ### File Resolution (How Codev Finds Protocols and Templates) @@ -121,7 +121,7 @@ afx spawn --protocol --help This succeeds if the protocol is registered (including via the skeleton fallback in tier 4 of the resolution chain) and errors helpfully otherwise. The CLI is the source of truth — defer to it when in doubt. Key locations: -- Protocol details: `codev/protocols/` (Choose appropriate protocol) +- Protocol details: `codev-skeleton/protocols/` (single owner; the runtime resolves the embedded skeleton — `codev/protocols/` holds only local-only protocols like RELEASE) - **Project tracking**: GitHub Issues (source of truth for all projects) - Specifications go in: `codev/specs/` - Plans go in: `codev/plans/` @@ -209,7 +209,7 @@ validated: [gemini, codex, claude] - No spec/plan artifacts needed - Single builder can fix independently -**BUGFIX uses GitHub Issues as source of truth.** See `codev/protocols/bugfix/protocol.md`. +**BUGFIX uses GitHub Issues as source of truth.** See `codev-skeleton/protocols/bugfix/protocol.md`. ### Use AIR for (small features from GitHub issues): - Small features (< 300 LOC) fully described in a **GitHub Issue** @@ -217,7 +217,7 @@ validated: [gemini, codex, claude] - No spec/plan artifacts — review goes in the PR body - Would be overkill for full SPIR/ASPIR ceremony -**AIR uses GitHub Issues as source of truth.** Two phases: Implement → Review. See `codev/protocols/air/protocol.md`. +**AIR uses GitHub Issues as source of truth.** Two phases: Implement → Review. See `codev-skeleton/protocols/air/protocol.md`. ### Use PIR for (engineer-judged — based on the nature of the work, not its size): @@ -237,7 +237,7 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - User-journey changes that need a full-flow exercise - Performance-sensitive changes that need profiling on the running app -**PIR uses GitHub Issues as source of truth.** Three phases: Plan (gated by `plan-approval`) → Implement (gated by `dev-approval`) → Review (PR + CMAP-2 at PR, then gated by `pr` for merge synchronization — matching SPIR's pr-gate pattern but with no post-merge verify phase). Plan and review artifacts live in `codev/plans/` and `codev/reviews/` on the builder branch, ship to main with the merge. Review file is shaped identically to SPIR's (Summary + Architecture Updates + Lessons Learned + supporting sections) so `codev/reviews/` stays semantically consistent across protocols. Lighter than SPIR (no spec phase — the issue body is the implicit spec; consult footprint matches BUGFIX/AIR's "one consult at PR" pattern). Stronger than BUGFIX/AIR (two human gates pre-PR — the human reviews the running worktree at the `dev-approval` gate, not the PR diff post-creation). CMAP at the PR is a **single advisory pass** (`max_iterations: 1`) — no iterate-until-APPROVE loop; a `REQUEST_CHANGES` is escalated to the human at the `pr` gate, not auto-re-reviewed. The CMAP-2 footprint is a design invariant: porch's model precedence is *config > protocol*, so a project-wide `porch.consultation.models` (e.g. a SPIR-tuned 3-model list) silently inflates PIR — leave it unset or scope it per-protocol to preserve the BUGFIX/AIR-parity cost. See `codev/protocols/pir/protocol.md`. +**PIR uses GitHub Issues as source of truth.** Three phases: Plan (gated by `plan-approval`) → Implement (gated by `dev-approval`) → Review (PR + CMAP-2 at PR, then gated by `pr` for merge synchronization — matching SPIR's pr-gate pattern but with no post-merge verify phase). Plan and review artifacts live in `codev/plans/` and `codev/reviews/` on the builder branch, ship to main with the merge. Review file is shaped identically to SPIR's (Summary + Architecture Updates + Lessons Learned + supporting sections) so `codev/reviews/` stays semantically consistent across protocols. Lighter than SPIR (no spec phase — the issue body is the implicit spec; consult footprint matches BUGFIX/AIR's "one consult at PR" pattern). Stronger than BUGFIX/AIR (two human gates pre-PR — the human reviews the running worktree at the `dev-approval` gate, not the PR diff post-creation). CMAP at the PR is a **single advisory pass** (`max_iterations: 1`) — no iterate-until-APPROVE loop; a `REQUEST_CHANGES` is escalated to the human at the `pr` gate, not auto-re-reviewed. The CMAP-2 footprint is a design invariant: porch's model precedence is *config > protocol*, so a project-wide `porch.consultation.models` (e.g. a SPIR-tuned 3-model list) silently inflates PIR — leave it unset or scope it per-protocol to preserve the BUGFIX/AIR-parity cost. See `codev-skeleton/protocols/pir/protocol.md`. ### Use SPIR for (new features): - Creating a **new feature from scratch** (no existing spec to amend) @@ -252,7 +252,7 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - Builder runs autonomously through Specify → Plan → Implement → Review (→ Verify) - Human approval still required at the PR gate before merge -**ASPIR is identical to SPIR** except `spec-approval` and `plan-approval` gates are removed. Both include an optional verify phase after review. See `codev/protocols/aspir/protocol.md`. +**ASPIR is identical to SPIR** except `spec-approval` and `plan-approval` gates are removed. Both include an optional verify phase after review. See `codev-skeleton/protocols/aspir/protocol.md`. ### Use EXPERIMENT for: - Testing new approaches or techniques @@ -278,6 +278,19 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change - Small bug fixes in templates - Dependency updates +## Scar Rules (always in force) + +Hard-won prohibitions from real incidents. Registered in +`codev/resources/scar-rules.yaml` (Spec 1252); CI fails if any is deleted or +reworded. The worktree, workspace-root, and staging rules appear in their +topical sections below; the rest live here: + +- Never run `git reset --hard`, `git checkout -- .`, `git clean -fd`, or `git stash` without explicit human permission — they destroy uncommitted work. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never kill a shellper process without verifying it is an orphan (match each PID to its workspace via Tower) — an 'extra' shellper may be a live architect session. +- Never restart or stop Tower without explicit human permission — it kills every running builder session. + ## Core Workflow 1. **When asked to build NEW FEATURES FOR CODEV**: Start with the Specification phase @@ -289,10 +302,8 @@ Pick PIR when ONE or BOTH of the following apply to a GitHub-issue-driven change ``` project-root/ ├── codev/ -│ ├── protocols/ # Development protocols -│ │ ├── spir/ # Multi-phase development with consultation -│ │ ├── experiment/ # Disciplined experimentation -│ │ └── maintain/ # Codebase maintenance (code + docs) +│ ├── protocols/ # LOCAL-ONLY protocols (e.g. release/) — framework +│ │ └── release/ # protocols resolve from codev-skeleton/ (Spec 1252) │ ├── maintain/ # MAINTAIN protocol runtime artifacts │ │ └── .trash/ # Soft-deleted files (gitignored, 30-day retention) │ ├── projects/ # Active project state (managed by porch) @@ -383,151 +394,15 @@ Codev provides five CLI tools. For complete reference documentation, see: ## Runnable Worktrees -When configured, each builder worktree (`.builders//`) becomes runnable — reviewers can run whatever your dev command starts against the builder's branch — a dev server, `cargo run`, `expo start`, a test watcher, a build script, whatever iterates on your project — without `cd`'ing, manually installing, or finding the right command. Opt-in via `.codev/config.json`; unconfigured repos see zero behavior change. - -### Config: the `worktree` block - -```jsonc -{ - "worktree": { - "symlinks": ["..."], // glob patterns of files to symlink from root into each new worktree - "postSpawn": ["..."], // shell commands run inside each new worktree after createWorktree - "devCommand": "..." // consumed by `afx dev ` - } -} -``` - -- `symlinks`: globs resolve from the workspace root; matches symlink into the worktree at the same relative path. Root `.env` and `.codev/config.json` are *always* symlinked regardless. **Symlinks, not copies** — edits to main's env files reflect instantly in any running dev session. A directory match is silently skipped (so a glob can't mask the worktree's own source) **unless** the entry ends with a trailing slash: `".local-user-data/"` is treated as a literal path and symlinks the directory whole (shared with the parent, not branch-isolated; a dangling link is fine if the source doesn't exist yet). -- `postSpawn`: each command runs sequentially with `cwd` = worktree path. Non-zero exit aborts the spawn loud (half-built worktree stays for inspection). -- `devCommand`: the foreground command that starts your dev process (a server, a watcher, `cargo run`, `expo start`, a build script — whatever iterates on your project). Required for `afx dev` to work. - -**Codev does not auto-detect your stack.** Pick the recipe below that matches your toolchain. - -### CLI - -```bash -afx dev # start dev in 's worktree -afx dev main # start dev in the MAIN workspace (Codev-managed) -afx dev --stop # stop the currently running dev PTY (builder or main) -``` - -Only one dev PTY runs at a time (by design — see "URLs are load-bearing" below), across **{main + all builders}**. `main` is a reserved target: it runs `worktree.devCommand` in the main checkout as a Codev-managed, swappable PTY, symmetric with builders. Starting any target while another is up prompts for swap (`afx dev ` while `main` runs, or vice-versa); same-target requests print the existing terminal URL and exit. Like builder dev, main dev is a **non-persistent** PTY — a Tower restart (`pnpm -w run local-install`, crash) kills it; re-run to restart. - -**Launch main dev via `afx dev main`, not a bare `pnpm dev`.** A manually-run `pnpm dev` at the repo root is invisible to Codev (the deliberate "never kill what it didn't spawn" policy) — start a builder dev while it holds the ports and the builder dev silently fails to bind, or worse serves main's code under the worktree URL. `afx dev main` makes it a managed PTY that swap-detection can cleanly stop first. This only helps if you use it *consistently*; a hand-started `pnpm dev` stays unmanaged. - -### VSCode - -The same actions are available via right-click on any builder row in the Codev sidebar (Builders or Needs Attention view): - -- **Codev: Open Builder Terminal** — opens that builder's AI terminal in a VSCode tab (same as left-clicking the row). -- **Codev: Open Worktree Folder** — opens `.builders//` in the OS file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux). -- **Codev: Run Worktree Setup** — applies the configured `worktree.symlinks` and runs the `worktree.postSpawn` commands against the existing worktree (mirrors what spawn does, minus the git steps). Idempotent: existing symlinks are skipped, missing ones added. Useful when the lockfile changed (reinstall deps), `symlinks` or `postSpawn` was extended after the builder spawned, a symlink was accidentally deleted, or the original setup aborted mid-run. Opens a fresh VSCode terminal so install output streams live. Available via CLI too: `afx setup `. -- **Codev: View Diff** — opens a single unified diff editor for `main...HEAD` of that builder's worktree, with a file-list pane on the left (matches VSCode's built-in Source Control "Working Tree" view). Status icons indicate added / modified / deleted. Empty diff → friendly toast. -- **Codev: Run Dev** — reads `worktree.devCommand` from `.codev/config.json`, asks Tower to spawn a dev PTY in the builder's worktree, and opens it as a VSCode terminal tab named `Codev: (dev)`. If another builder's dev is already running, you get a modal asking whether to swap. -- **Codev: Stop Dev** — kills the running dev PTY and closes its tab. - -The Codev sidebar's **Workspace** view also carries a dev control for *whatever folder this VSCode window is rooted at* (it is not "main"-specific): - -- **Start Dev** — runs `worktree.devCommand` for the current workspace. Target is resolved from the open folder: the main checkout → `main`; a `.builders//` worktree opened as its own window (e.g. via *Open Worktree as Workspace*) → that builder. Same single-slot swap model as builder dev (prompts if another dev is running). The row tooltip names the resolved target. -- **Stop Dev** — stops this workspace's dev; the row appears only while it is running. Scoped to the resolved target — it does not touch other devs. - -The three commands are also available from the command palette (Cmd+Shift+P). No default keybindings; bind via `keybindings.json` if you use them often. - -### URLs are load-bearing - -The dev PTY uses **the same ports and URLs as main** intentionally. OAuth callbacks, CORS allowlists, cookie scoping, CSP `connect-src`, webhook URLs are all keyed off origin — running the worktree on a different port would break them. Consequence: stop main's `pnpm dev` before `afx dev`. If you don't, the spawned dev fails at bind time with its own `EADDRINUSE`. Prefer `afx dev main` (or the Workspace view's *Start Dev* row) over a hand-run `pnpm dev` so Codev owns the PTY and swap-detection can stop it for you automatically. - -### Cleanup semantics - -`afx dev --stop` and the swap path kill the entire PTY process group (SIGTERM, escalating to SIGKILL after 5s via `PtySession.kill`). That signals every grandchild of a monorepo dev orchestrator (`pnpm dev`, `turbo dev`, `pnpm -r --parallel run dev`, etc.) simultaneously. The OS reclaims ports as a consequence — Codev never touches ports directly. - -**Orphan recovery** — if Tower itself hard-crashes mid-dev and a process is left holding a port outside Codev's records: - -```bash -lsof -ti : | xargs kill # one port -lsof -ti :3000,:3001,:4000 | xargs kill # several at once -``` - -### Runnable Worktree Recipes - -Ready-to-paste blocks per stack. Adjust ports / paths to your project. - -**pnpm monorepo (Next.js + Turbo style):** -```json -{ - "worktree": { - "symlinks": [".env.local", ".env.development.local", "packages/*/.env", "packages/*/.env.local", "turbo.json"], - "postSpawn": ["pnpm install --frozen-lockfile"], - "devCommand": "pnpm dev" - } -} -``` - -**npm (single package):** -```json -{ - "worktree": { - "symlinks": [".env.local", ".env.development"], - "postSpawn": ["npm ci"], - "devCommand": "npm run dev" - } -} -``` - -**yarn:** -```json -{ - "worktree": { - "symlinks": [".env.local"], - "postSpawn": ["yarn install --frozen-lockfile"], - "devCommand": "yarn dev" - } -} -``` - -**bun:** -```json -{ - "worktree": { - "symlinks": [".env.local"], - "postSpawn": ["bun install --frozen-lockfile"], - "devCommand": "bun dev" - } -} -``` - -**cargo (Rust):** -```json -{ - "worktree": { - "symlinks": [".env"], - "postSpawn": [], - "devCommand": "cargo run" - } -} -``` - -**poetry / uv (Python):** -```json -{ - "worktree": { - "symlinks": [".env", ".env.local"], - "postSpawn": ["uv sync"], - "devCommand": "uv run python -m myapp" - } -} -``` +Builder worktrees (and `main`) can run your dev command via `afx dev +` — symlinked env, `postSpawn` install hooks, single dev PTY +with swap-on-conflict, VSCode commands, and same-ports-as-main URL semantics +(OAuth/CORS/cookies are origin-keyed, so worktree devs bind main's ports). +Configure via the `worktree` block in `.codev/config.json`. -**go mod:** -```json -{ - "worktree": { - "symlinks": [".env"], - "postSpawn": ["go mod download"], - "devCommand": "go run ./cmd/server" - } -} -``` +Full reference — config schema, per-stack recipes, CLI/VSCode surfaces, +cleanup and orphan recovery: `codev/resources/commands/agent-farm.md` +§ "Runnable Worktrees". ## Architect-Builder Pattern @@ -540,30 +415,12 @@ For detailed commands, configuration, and architecture, see: - `codev/resources/arch.md` - Terminal architecture, state management - `codev/resources/workflow-reference.md` - Stage-by-stage workflow -### 🚨 NEVER DESTROY BUILDER WORKTREES 🚨 - -**When a worktree already exists for a project:** -1. Use `afx spawn XXXX --resume` -2. If `--resume` fails → **ASK THE USER** -3. Only destroy if the user explicitly says to - -**NEVER run without EXPLICIT user request:** -- `git worktree remove` (with or without --force) -- `git branch -D` on builder branches -- `afx cleanup` followed by fresh spawn - -**You are NOT qualified to judge what's expendable.** It is NEVER your call to delete a worktree. - -### 🚨 ALWAYS Operate From the Main Workspace Root 🚨 +### Scar rules — worktrees and the workspace root -**ALL `afx` commands (`afx spawn`, `afx send`, `afx status`, `afx workspace`, `afx cleanup`) MUST be run from the repository root on the `main` branch.** +Never destroy builder worktrees (`git worktree remove`, `git branch -D` on builder branches, `afx cleanup` + respawn). Use `afx spawn --resume`; if it fails, ask the human — what is expendable is never your call. -- **NEVER** run `afx spawn` from inside a builder worktree — builders will get nested inside that worktree, breaking everything -- **NEVER** run `afx workspace start` from a worktree — there is no separate workspace per worktree -- **NEVER** `cd` into a worktree to run afx commands -- The **only exception** is `porch` commands that need worktree context (e.g. `porch approve` from a builder's worktree) - -**What happened**: On 2026-02-21, `afx spawn` was run from inside a builder's worktree. All new builders were nested inside that worktree, `afx send` couldn't find them, and `afx status` showed "not active in tower". Multiple builders had to be killed and respawned. +Run `afx` commands only from the main workspace root, never from inside a builder worktree — spawning from a worktree nests builders and breaks the workspace. +(The only exception is `porch` commands that need worktree context, e.g. `porch approve` from a builder's worktree.) ### Pre-Spawn Rule @@ -589,36 +446,17 @@ Agent Farm is configured via `.codev/config.json` at the project root. Created d ## Inter-agent messaging -Agents within a workspace communicate through `afx send`. Four addressing forms are supported: - -### Addressing forms - -| Form | Meaning | Allowed from | -|---|---|---| -| `afx send "msg"` | Send to a specific builder (e.g. `afx send 0823 "..."`). | Any sender. | -| `afx send architect "msg"` | From a builder: routes to the spawning architect via affinity (per #774). From an architect (or any non-builder sender): routes to the architect named `main` if present, else the first registered architect. | Any sender. | -| `afx send architect: "msg"` | Explicit per-architect addressing. **Architects (including `main`)**: open address grammar — any architect can address any other architect. This is the sibling-architect messaging form. **Builders**: allowed ONLY when `` matches the builder's own `spawnedByArchitect`. Mismatches are rejected by the spoofing check at `tower-messages.ts:213-218`. From a builder, this is an explicit form of the affinity routing, NOT an override. | Any sender (with the spoofing constraint above for builders). | -| `afx send :architect "msg"` | Cross-workspace addressing (e.g. `afx send marketmaker:architect "..."`). | Any sender. | - -### Sibling-architect messaging - -When a workspace hosts more than one architect (added via `afx workspace add-architect --name `), sibling architects message each other via the `architect:` form. Example: - -```bash -# From main's terminal to a sibling architect named ob-refine -afx send architect:ob-refine "PR-iter-2 feedback ready" -``` +Agents message each other with `afx send`: `afx send "msg"`, +`afx send architect "msg"` (routes to the spawning architect via affinity), +`afx send architect:` (explicit; builders may only name their spawning +architect — the spoofing check rejects others), and +`afx send :architect` (cross-workspace). Discover active agents +with `afx status`; each builder also keeps a narrative thread at +`codev/state/_thread.md` (in-flight: under `.builders//`; +post-merge: on `main`). -This works because sender = architect bypasses the spoofing check. - -### Builder spoofing-check (verified at `tower-messages.ts:213-218`) - -Builder `spir-823` running `afx send architect:ob-refine "..."` is rejected unless its `spawnedByArchitect == 'ob-refine'`. A builder cannot use `architect:` to address an architect other than its spawning architect — that's an attempted spoof. - -### Discovering active agents - -- `afx status` lists all architects (post-#786) alongside builders, with names, terminal IDs, and PIDs where available. -- Each active builder maintains a free-text narrative log at `codev/state/_thread.md` (relative to its worktree, so `.builders//codev/state/_thread.md` from the main workspace root). **In-flight discovery**: `ls .builders/*/codev/state/*.md` and `cat .builders//codev/state/_thread.md`. **Post-merge discovery**: after a builder's PR merges, its thread lands in `codev/state/` on `main`, alongside `codev/reviews/` — list with `ls codev/state/` and read with `cat codev/state/_thread.md` from the main checkout. +Full addressing grammar, sibling-architect messaging, and the spoofing-check +details: `codev/resources/commands/agent-farm.md` § "afx send". ## Porch - Protocol Orchestrator @@ -640,23 +478,15 @@ State is stored in `codev/projects/-/status.yaml`, managed automatical ## Git Workflow -### 🚨 ABSOLUTE PROHIBITION: NEVER USE `git add -A` or `git add .` 🚨 +### Staging (scar rule) -**THIS IS A CRITICAL SECURITY REQUIREMENT - NO EXCEPTIONS** - -```bash -git add -A # ABSOLUTELY FORBIDDEN -git add . # ABSOLUTELY FORBIDDEN -git add --all # ABSOLUTELY FORBIDDEN -``` +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. -**MANDATORY APPROACH - ALWAYS ADD FILES EXPLICITLY**: ```bash -git add codev/specs/42-feature.md -git add src/components/TodoList.tsx +git add codev/specs/42-feature.md src/components/TodoList.tsx ``` -**BEFORE EVERY COMMIT**: Run `git status`, add each file explicitly by name. +Before every commit: run `git status`, add each file by name. ### Commit Messages ``` @@ -727,8 +557,8 @@ git log --oneline --all | grep -i "feature-name" ## Important Notes -1. **ALWAYS check `codev/protocols/spir/protocol.md`** for detailed phase instructions -2. **Use provided templates** from `codev/protocols/spir/templates/` +1. **Detailed phase instructions arrive with the work** — the full SPIR protocol text is inlined into every spawn prompt, and porch delivers each phase's instructions. Don't fetch protocol files by path (the resolver serves them; see File Resolution above). For orientation reading, the source is `codev-skeleton/protocols/spir/protocol.md`. +2. **Templates are delivered by porch phase prompts** — the spec/plan/review structures arrive in the phase task; no need to fetch them from the skeleton by path. 3. **Document all deviations** from the plan with reasoning 4. **Create atomic commits** for each phase completion 5. **Maintain >90% test coverage** where possible diff --git a/codev-skeleton/.claude/skills/porch/SKILL.md b/codev-skeleton/.claude/skills/porch/SKILL.md index ef5cc17dc..03d0b97d5 100644 --- a/codev-skeleton/.claude/skills/porch/SKILL.md +++ b/codev-skeleton/.claude/skills/porch/SKILL.md @@ -49,8 +49,9 @@ porch pending # List all gates waiting for approval ## Critical rules -- **Builders must NEVER call `porch approve`** — only humans approve gates -- **Never edit `status.yaml` directly** — porch manages all state +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Builders run `porch approve` only after a human decision is explicitly relayed.) +- Never hand-edit `status.yaml` — only porch commands modify project state. - Builders signal completion with `porch done`, not `porch approve` - `porch run` is for strict mode only — soft mode builders follow the protocol document manually - When running `porch approve` from the architect, use a subshell if you need worktree context: `(cd /path/to/worktree && porch approve ...)` diff --git a/codev-skeleton/.codex/skills/porch/SKILL.md b/codev-skeleton/.codex/skills/porch/SKILL.md index ef5cc17dc..03d0b97d5 100644 --- a/codev-skeleton/.codex/skills/porch/SKILL.md +++ b/codev-skeleton/.codex/skills/porch/SKILL.md @@ -49,8 +49,9 @@ porch pending # List all gates waiting for approval ## Critical rules -- **Builders must NEVER call `porch approve`** — only humans approve gates -- **Never edit `status.yaml` directly** — porch manages all state +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Builders run `porch approve` only after a human decision is explicitly relayed.) +- Never hand-edit `status.yaml` — only porch commands modify project state. - Builders signal completion with `porch done`, not `porch approve` - `porch run` is for strict mode only — soft mode builders follow the protocol document manually - When running `porch approve` from the architect, use a subshell if you need worktree context: `(cd /path/to/worktree && porch approve ...)` diff --git a/codev-skeleton/partials/baked-decisions.md b/codev-skeleton/partials/baked-decisions.md new file mode 100644 index 000000000..3e9efb4f7 --- /dev/null +++ b/codev-skeleton/partials/baked-decisions.md @@ -0,0 +1,5 @@ +## Baked Decisions + +If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. + +If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. \ No newline at end of file diff --git a/codev-skeleton/partials/builder-notifications.md b/codev-skeleton/partials/builder-notifications.md new file mode 100644 index 000000000..f33fab29e --- /dev/null +++ b/codev-skeleton/partials/builder-notifications.md @@ -0,0 +1,5 @@ +Always use `afx send architect "..."` to notify the architect at key moments: +- **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` +- **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` +- **PR merged**: `afx send architect "Project {{project_id}} PR merged. Entering verify phase."` +- **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` \ No newline at end of file diff --git a/codev-skeleton/partials/flaky-test-handling.md b/codev-skeleton/partials/flaky-test-handling.md new file mode 100644 index 000000000..f1e04d207 --- /dev/null +++ b/codev-skeleton/partials/flaky-test-handling.md @@ -0,0 +1,4 @@ +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work \ No newline at end of file diff --git a/codev-skeleton/partials/multi-pr-mechanics.md b/codev-skeleton/partials/multi-pr-mechanics.md new file mode 100644 index 000000000..98fa82d20 --- /dev/null +++ b/codev-skeleton/partials/multi-pr-mechanics.md @@ -0,0 +1,13 @@ +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: + +1. Cut a branch, open a PR, wait for merge +2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) +3. Continue to the next slice, open another PR +4. Repeat + +**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. + +Record PRs in status.yaml: `porch done {{project_id}} --pr --branch ` +Record merges: `porch done {{project_id}} --merged ` \ No newline at end of file diff --git a/codev-skeleton/partials/no-skip-3way-review.md b/codev-skeleton/partials/no-skip-3way-review.md new file mode 100644 index 000000000..86340e2e9 --- /dev/null +++ b/codev-skeleton/partials/no-skip-3way-review.md @@ -0,0 +1 @@ +- **NEVER skip the 3-way review** — always follow porch next → porch done cycle \ No newline at end of file diff --git a/codev-skeleton/partials/no-time-estimates.md b/codev-skeleton/partials/no-time-estimates.md new file mode 100644 index 000000000..752a77d67 --- /dev/null +++ b/codev-skeleton/partials/no-time-estimates.md @@ -0,0 +1 @@ +- Don't estimate time — AI development makes time estimates meaningless \ No newline at end of file diff --git a/codev-skeleton/partials/porch-workflow-fidelity.md b/codev-skeleton/partials/porch-workflow-fidelity.md new file mode 100644 index 000000000..3256c81cc --- /dev/null +++ b/codev-skeleton/partials/porch-workflow-fidelity.md @@ -0,0 +1 @@ +- Do not deviate from the porch-driven workflow \ No newline at end of file diff --git a/codev-skeleton/partials/pr-strategy.md b/codev-skeleton/partials/pr-strategy.md new file mode 100644 index 000000000..fb9a0cbd2 --- /dev/null +++ b/codev-skeleton/partials/pr-strategy.md @@ -0,0 +1,11 @@ +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +{{> partials/multi-pr-mechanics.md}} \ No newline at end of file diff --git a/codev-skeleton/partials/soft-mode-compliance.md b/codev-skeleton/partials/soft-mode-compliance.md new file mode 100644 index 000000000..c0713e889 --- /dev/null +++ b/codev-skeleton/partials/soft-mode-compliance.md @@ -0,0 +1 @@ +- You have flexibility in execution, but must stay compliant with the protocol \ No newline at end of file diff --git a/codev-skeleton/partials/strict-mode-restrictions.md b/codev-skeleton/partials/strict-mode-restrictions.md new file mode 100644 index 000000000..e124ac198 --- /dev/null +++ b/codev-skeleton/partials/strict-mode-restrictions.md @@ -0,0 +1,2 @@ +{{> partials/no-skip-3way-review.md}} +- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval \ No newline at end of file diff --git a/codev-skeleton/porch/prompts/implement.md b/codev-skeleton/porch/prompts/implement.md index 690b2cf9d..dee870005 100644 --- a/codev-skeleton/porch/prompts/implement.md +++ b/codev-skeleton/porch/prompts/implement.md @@ -74,11 +74,8 @@ Before signaling completion: ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Anti-Patterns to Avoid diff --git a/codev-skeleton/protocols/air/builder-prompt.md b/codev-skeleton/protocols/air/builder-prompt.md index f17ab40ad..67dd024c1 100644 --- a/codev-skeleton/protocols/air/builder-prompt.md +++ b/codev-skeleton/protocols/air/builder-prompt.md @@ -8,7 +8,7 @@ You are running in SOFT mode. This means: - You follow the AIR protocol yourself (no porch orchestration) - The architect monitors your work and verifies you're adhering to the protocol - Consultation is optional — use your judgement based on complexity -- You have flexibility in execution, but must stay compliant with the protocol +{{> partials/soft-mode-compliance.md}} {{/if}} {{#if mode_strict}} @@ -19,8 +19,9 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) {{/if}} ## Protocol @@ -63,11 +64,8 @@ Always use `afx send architect "..."` to notify the architect at key moments: ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in the PR body under a "Flaky Tests" section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the AIR protocol diff --git a/codev-skeleton/protocols/air/prompts/implement.md b/codev-skeleton/protocols/air/prompts/implement.md index 301641962..118822808 100644 --- a/codev-skeleton/protocols/air/prompts/implement.md +++ b/codev-skeleton/protocols/air/prompts/implement.md @@ -63,7 +63,7 @@ Fix any failures before proceeding. If build/test commands don't exist, check `p ### 5. Commit Stage and commit your changes: -- Use explicit file paths (never `git add -A` or `git add .`) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. - Commit message: `[Air #{{issue.number}}] feat: ` ## Signals diff --git a/codev-skeleton/protocols/aspir/builder-prompt.md b/codev-skeleton/protocols/aspir/builder-prompt.md index d303da59e..20ca470e1 100644 --- a/codev-skeleton/protocols/aspir/builder-prompt.md +++ b/codev-skeleton/protocols/aspir/builder-prompt.md @@ -8,7 +8,7 @@ You are running in SOFT mode. This means: - You follow the protocol document yourself (no porch orchestration) - The architect monitors your work and verifies you're adhering to the protocol - Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol +{{> partials/soft-mode-compliance.md}} {{/if}} {{#if mode_strict}} @@ -17,23 +17,20 @@ You are running in STRICT mode. This means: - Porch orchestrates your work - Run: `porch next` to get your next tasks - Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow +{{> partials/porch-workflow-fidelity.md}} ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +{{> partials/strict-mode-restrictions.md}} {{/if}} ## Protocol Follow the ASPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. -## Baked Decisions +{{> partials/baked-decisions.md}} -If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. - -If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. {{#if spec}} ## Spec @@ -58,28 +55,7 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} -## PR Strategy - -**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. - -By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. - -### Architect-requested PRs - -The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. - -### Multi-PR Mechanics (when the architect requests sequential PRs) - -Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: - -1. Cut a branch, open a PR, wait for merge -2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) -3. Continue to the next slice, open another PR - -**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. - -Record PRs: `porch done {{project_id}} --pr --branch ` -Record merges: `porch done {{project_id}} --merged ` +{{> partials/pr-strategy.md}} ## Verify Phase @@ -91,20 +67,13 @@ After the final PR merges, the project enters the **verify** phase. You stay ali If verification is not needed: `porch verify {{project_id}} --skip "reason"` ## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` -- **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} PR merged. Entering verify phase."` -- **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` +{{> partials/builder-notifications.md}} ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the protocol document thoroughly diff --git a/codev-skeleton/protocols/aspir/prompts/implement.md b/codev-skeleton/protocols/aspir/prompts/implement.md index bacc8502e..ce9e01ff5 100644 --- a/codev-skeleton/protocols/aspir/prompts/implement.md +++ b/codev-skeleton/protocols/aspir/prompts/implement.md @@ -191,7 +191,7 @@ Your specific questions here - Don't add features not in the spec - Don't leave TODO comments for later (fix now or note as blocker) - Don't skip writing tests -- Don't use `git add .` or `git add -A` when you commit (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Handling Problems @@ -208,7 +208,7 @@ Signal `BLOCKED` with details about what's missing. Signal `BLOCKED` with the error message. **If you encounter pre-existing flaky tests** (tests that fail intermittently but are unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks +1. Never hand-edit `status.yaml` — only porch commands modify project state. 2. **DO NOT** skip porch checks or use workarounds to avoid the failure 3. **DO** mark the flaky test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: intermittent timeout, skipped pending investigation`) 4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section so the team can follow up diff --git a/codev-skeleton/protocols/aspir/prompts/plan.md b/codev-skeleton/protocols/aspir/prompts/plan.md index 2c12250dd..adb642ac8 100644 --- a/codev-skeleton/protocols/aspir/prompts/plan.md +++ b/codev-skeleton/protocols/aspir/prompts/plan.md @@ -95,14 +95,14 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Plan with user feedback` 4. `[Spec {{project_id}}] Final approved plan` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/plans/{{artifact_name}}.md ``` ## Important Notes -1. **No time estimates** - Don't include hours/days/weeks +{{> partials/no-time-estimates.md}} 3. **Be specific about files** - Exact paths, not "the config file" 4. **Keep phases small** - 1-3 files per phase is ideal 5. **Document dependencies clearly** - Prevents blocked work @@ -111,8 +111,7 @@ git add codev/plans/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't write code (that's for Implement phase) -- Don't estimate time (meaningless in AI development) - Don't create phases that can't be independently tested - Don't skip dependency analysis - Don't make phases too large (if >5 files, split it) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/codev-skeleton/protocols/aspir/prompts/review.md b/codev-skeleton/protocols/aspir/prompts/review.md index 22af9aec4..ca104f66a 100644 --- a/codev-skeleton/protocols/aspir/prompts/review.md +++ b/codev-skeleton/protocols/aspir/prompts/review.md @@ -263,7 +263,7 @@ changes, you'll be respawned with their feedback. - Don't leave uncommitted changes - Don't forget to update documentation - Don't rush this phase - it's valuable for learning -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Review Prompts for Reflection diff --git a/codev-skeleton/protocols/aspir/prompts/specify.md b/codev-skeleton/protocols/aspir/prompts/specify.md index 3716f7969..45c9bf7c7 100644 --- a/codev-skeleton/protocols/aspir/prompts/specify.md +++ b/codev-skeleton/protocols/aspir/prompts/specify.md @@ -125,7 +125,7 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Specification with user feedback` 4. `[Spec {{project_id}}] Final approved specification` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/specs/{{artifact_name}}.md ``` @@ -140,6 +140,6 @@ git add codev/specs/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) +{{> partials/no-time-estimates.md}} - Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/codev-skeleton/protocols/bugfix/builder-prompt.md b/codev-skeleton/protocols/bugfix/builder-prompt.md index aefa35a25..96e782442 100644 --- a/codev-skeleton/protocols/bugfix/builder-prompt.md +++ b/codev-skeleton/protocols/bugfix/builder-prompt.md @@ -8,7 +8,7 @@ You are running in SOFT mode. This means: - You follow the BUGFIX protocol yourself (no porch orchestration) - The architect monitors your work and verifies you're adhering to the protocol - Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol +{{> partials/soft-mode-compliance.md}} {{/if}} {{#if mode_strict}} @@ -19,9 +19,10 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +{{> partials/no-skip-3way-review.md}} {{/if}} ## Protocol @@ -57,11 +58,8 @@ Always use `afx send architect "..."` to notify the architect at key moments: ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the BUGFIX protocol diff --git a/codev-skeleton/protocols/bugfix/prompts/fix.md b/codev-skeleton/protocols/bugfix/prompts/fix.md index afecc3343..5a462594e 100644 --- a/codev-skeleton/protocols/bugfix/prompts/fix.md +++ b/codev-skeleton/protocols/bugfix/prompts/fix.md @@ -52,7 +52,7 @@ Fix any failures before proceeding. If build/test commands don't exist, check `p ### 4. Commit Stage and commit your changes: -- Use explicit file paths (never `git add -A` or `git add .`) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. - Commit message: `Fix #{{issue.number}}: ` ## Signals diff --git a/codev-skeleton/protocols/experiment/builder-prompt.md b/codev-skeleton/protocols/experiment/builder-prompt.md index 31c5581e5..f18e69d3f 100644 --- a/codev-skeleton/protocols/experiment/builder-prompt.md +++ b/codev-skeleton/protocols/experiment/builder-prompt.md @@ -18,9 +18,10 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +{{> partials/no-skip-3way-review.md}} {{/if}} ## Protocol @@ -64,11 +65,8 @@ PR closes it. ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the EXPERIMENT protocol document diff --git a/codev-skeleton/protocols/maintain/builder-prompt.md b/codev-skeleton/protocols/maintain/builder-prompt.md index 6a2deda0d..080fc8e1f 100644 --- a/codev-skeleton/protocols/maintain/builder-prompt.md +++ b/codev-skeleton/protocols/maintain/builder-prompt.md @@ -18,8 +18,9 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) {{/if}} ## Protocol @@ -38,16 +39,13 @@ Two phases: - Don't remove anything actively used - One removal at a time — commit after each - Document every deletion with justification -- Never use `git add -A` or `git add .` +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your maintenance run file -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the MAINTAIN protocol document diff --git a/codev-skeleton/protocols/maintain/prompts/maintain.md b/codev-skeleton/protocols/maintain/prompts/maintain.md index 3c83f404d..62427b512 100644 --- a/codev-skeleton/protocols/maintain/prompts/maintain.md +++ b/codev-skeleton/protocols/maintain/prompts/maintain.md @@ -47,7 +47,8 @@ For each audit finding: 3. Build and test: `cd packages/codev && pnpm build && pnpm test` 4. Commit: `git add && git commit -m "[Maintain] Remove unused X"` -One removal at a time. Verify after each. Never use `git add -A`. +One removal at a time. Verify after each. +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Step 4: Sync Documentation diff --git a/codev-skeleton/protocols/maintain/protocol.md b/codev-skeleton/protocols/maintain/protocol.md index 7e91d118d..fe56e319a 100644 --- a/codev-skeleton/protocols/maintain/protocol.md +++ b/codev-skeleton/protocols/maintain/protocol.md @@ -105,7 +105,7 @@ For each finding from the audit: - One removal at a time — don't batch unrelated changes - Verify after each removal — build must pass - Use soft deletion for untracked files: `mv file codev/maintain/.trash/$(date +%Y-%m-%d)/` -- Never use `git add -A` or `git add .` +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ### Step 3: Sync Documentation diff --git a/codev-skeleton/protocols/pir/builder-prompt.md b/codev-skeleton/protocols/pir/builder-prompt.md index 86016f310..4b366a9cd 100644 --- a/codev-skeleton/protocols/pir/builder-prompt.md +++ b/codev-skeleton/protocols/pir/builder-prompt.md @@ -8,7 +8,7 @@ You are running in SOFT mode. This means: - You follow the PIR protocol document yourself (no porch orchestration) - The architect monitors your work and verifies you're adhering to the protocol - Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol +{{> partials/soft-mode-compliance.md}} {{/if}} {{#if mode_strict}} @@ -17,11 +17,12 @@ You are running in STRICT mode. This means: - Porch orchestrates your work - Run: `porch next` to get your next tasks - Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow +{{> partials/porch-workflow-fidelity.md}} ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) - **NEVER skip consultations** — porch handles them via the verify step - **NEVER advance phases manually** — porch handles phase transitions on gate approval {{/if}} @@ -70,11 +71,8 @@ Use `afx send architect "..."` at key moments: ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in the review file under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Resumption After Crash diff --git a/codev-skeleton/protocols/pir/prompts/implement.md b/codev-skeleton/protocols/pir/prompts/implement.md index 9d7f88a8c..f65090dcc 100644 --- a/codev-skeleton/protocols/pir/prompts/implement.md +++ b/codev-skeleton/protocols/pir/prompts/implement.md @@ -61,7 +61,7 @@ Follow the plan's "Files to Change" section. Apply the changes. [PIR #{{issue.number}}] ``` -**Never use `git add .` or `git add -A`.** Stage files explicitly: +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add path/to/changed-file.ts @@ -143,7 +143,7 @@ Then **stay in the interactive session**. Do not exit. Wait for the user's next - Don't run `porch approve` yourself - Don't push to the default branch — only to your builder branch - Don't squash commits — let the merge commit preserve history -- Don't use `git add .` or `git add -A` +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. - Don't open the PR yet — that's the `review` phase - Don't exit the interactive session at the gate diff --git a/codev-skeleton/protocols/pir/prompts/plan.md b/codev-skeleton/protocols/pir/prompts/plan.md index a40cdee2d..041e8b1a3 100644 --- a/codev-skeleton/protocols/pir/prompts/plan.md +++ b/codev-skeleton/protocols/pir/prompts/plan.md @@ -87,7 +87,7 @@ git commit -m "[PIR #{{issue.number}}] Plan draft" git push -u origin "$(git branch --show-current)" ``` -**Never use `git add .` or `git add -A`.** +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ### 5. Signal Phase Complete @@ -118,7 +118,7 @@ Then **stay in the interactive session**. Do not exit. Wait for the user's next - Don't write code — that's the implement phase - Don't run `porch approve` yourself — only the human can approve the gate - Don't post the plan content as a GitHub issue comment — the plan lives in the file, not the issue thread. A one-line pointer comment on the issue is fine if you think it helps the discussion. -- Don't use `git add .` or `git add -A` +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. - Don't exit the interactive session at the gate ## Handling Feedback diff --git a/codev-skeleton/protocols/research/builder-prompt.md b/codev-skeleton/protocols/research/builder-prompt.md index 088262853..64bd033f2 100644 --- a/codev-skeleton/protocols/research/builder-prompt.md +++ b/codev-skeleton/protocols/research/builder-prompt.md @@ -18,8 +18,9 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) - **NEVER skip the 3-way consultation** — always follow porch next → porch done cycle {{/if}} diff --git a/codev-skeleton/protocols/spike/builder-prompt.md b/codev-skeleton/protocols/spike/builder-prompt.md index 6d30dc649..6cd242786 100644 --- a/codev-skeleton/protocols/spike/builder-prompt.md +++ b/codev-skeleton/protocols/spike/builder-prompt.md @@ -50,11 +50,8 @@ Follow this 3-step workflow. You can skip or reorder steps as the investigation ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your findings under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the SPIKE protocol document diff --git a/codev-skeleton/protocols/spir/builder-prompt.md b/codev-skeleton/protocols/spir/builder-prompt.md index 437287968..bde926221 100644 --- a/codev-skeleton/protocols/spir/builder-prompt.md +++ b/codev-skeleton/protocols/spir/builder-prompt.md @@ -8,7 +8,7 @@ You are running in SOFT mode. This means: - You follow the protocol document yourself (no porch orchestration) - The architect monitors your work and verifies you're adhering to the protocol - Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol +{{> partials/soft-mode-compliance.md}} {{/if}} {{#if mode_strict}} @@ -17,23 +17,20 @@ You are running in STRICT mode. This means: - Porch orchestrates your work - Run: `porch next` to get your next tasks - Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow +{{> partials/porch-workflow-fidelity.md}} ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +{{> partials/strict-mode-restrictions.md}} {{/if}} ## Protocol Follow the SPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. -## Baked Decisions +{{> partials/baked-decisions.md}} -If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. - -If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. {{#if spec}} ## Spec @@ -58,29 +55,7 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} -## PR Strategy - -**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. - -By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. - -### Architect-requested PRs - -The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. - -### Multi-PR Mechanics (when the architect requests sequential PRs) - -Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: - -1. Cut a branch, open a PR, wait for merge -2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) -3. Continue to the next slice, open another PR -4. Repeat - -**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. - -Record PRs in status.yaml: `porch done {{project_id}} --pr --branch ` -Record merges: `porch done {{project_id}} --merged ` +{{> partials/pr-strategy.md}} ## Verify Phase @@ -92,20 +67,13 @@ After the final PR merges, the project enters the **verify** phase. You stay ali If verification is not needed: `porch verify {{project_id}} --skip "reason"` ## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` -- **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} PR merged. Entering verify phase."` -- **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` +{{> partials/builder-notifications.md}} ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work +1. Never hand-edit `status.yaml` — only porch commands modify project state. +{{> partials/flaky-test-handling.md}} ## Getting Started 1. Read the protocol document thoroughly diff --git a/codev-skeleton/protocols/spir/prompts/implement.md b/codev-skeleton/protocols/spir/prompts/implement.md index bacc8502e..ce9e01ff5 100644 --- a/codev-skeleton/protocols/spir/prompts/implement.md +++ b/codev-skeleton/protocols/spir/prompts/implement.md @@ -191,7 +191,7 @@ Your specific questions here - Don't add features not in the spec - Don't leave TODO comments for later (fix now or note as blocker) - Don't skip writing tests -- Don't use `git add .` or `git add -A` when you commit (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Handling Problems @@ -208,7 +208,7 @@ Signal `BLOCKED` with details about what's missing. Signal `BLOCKED` with the error message. **If you encounter pre-existing flaky tests** (tests that fail intermittently but are unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks +1. Never hand-edit `status.yaml` — only porch commands modify project state. 2. **DO NOT** skip porch checks or use workarounds to avoid the failure 3. **DO** mark the flaky test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: intermittent timeout, skipped pending investigation`) 4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section so the team can follow up diff --git a/codev-skeleton/protocols/spir/prompts/plan.md b/codev-skeleton/protocols/spir/prompts/plan.md index 2c12250dd..adb642ac8 100644 --- a/codev-skeleton/protocols/spir/prompts/plan.md +++ b/codev-skeleton/protocols/spir/prompts/plan.md @@ -95,14 +95,14 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Plan with user feedback` 4. `[Spec {{project_id}}] Final approved plan` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/plans/{{artifact_name}}.md ``` ## Important Notes -1. **No time estimates** - Don't include hours/days/weeks +{{> partials/no-time-estimates.md}} 3. **Be specific about files** - Exact paths, not "the config file" 4. **Keep phases small** - 1-3 files per phase is ideal 5. **Document dependencies clearly** - Prevents blocked work @@ -111,8 +111,7 @@ git add codev/plans/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't write code (that's for Implement phase) -- Don't estimate time (meaningless in AI development) - Don't create phases that can't be independently tested - Don't skip dependency analysis - Don't make phases too large (if >5 files, split it) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/codev-skeleton/protocols/spir/prompts/review.md b/codev-skeleton/protocols/spir/prompts/review.md index 22af9aec4..ca104f66a 100644 --- a/codev-skeleton/protocols/spir/prompts/review.md +++ b/codev-skeleton/protocols/spir/prompts/review.md @@ -263,7 +263,7 @@ changes, you'll be respawned with their feedback. - Don't leave uncommitted changes - Don't forget to update documentation - Don't rush this phase - it's valuable for learning -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Review Prompts for Reflection diff --git a/codev-skeleton/protocols/spir/prompts/specify.md b/codev-skeleton/protocols/spir/prompts/specify.md index 3716f7969..45c9bf7c7 100644 --- a/codev-skeleton/protocols/spir/prompts/specify.md +++ b/codev-skeleton/protocols/spir/prompts/specify.md @@ -125,7 +125,7 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Specification with user feedback` 4. `[Spec {{project_id}}] Final approved specification` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/specs/{{artifact_name}}.md ``` @@ -140,6 +140,6 @@ git add codev/specs/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) +{{> partials/no-time-estimates.md}} - Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/codev-skeleton/resources/commands/agent-farm.md b/codev-skeleton/resources/commands/agent-farm.md index dfa36678f..0b6ec87bb 100644 --- a/codev-skeleton/resources/commands/agent-farm.md +++ b/codev-skeleton/resources/commands/agent-farm.md @@ -662,3 +662,152 @@ afx spawn 42 --protocol spir --builder-cmd "claude --model haiku" - [codev](codev.md) - Project management commands - [consult](consult.md) - AI consultation - [overview](overview.md) - CLI overview + +## Runnable Worktrees (afx dev) + +When configured, each builder worktree (`.builders//`) becomes runnable — reviewers can run whatever your dev command starts against the builder's branch — a dev server, `cargo run`, `expo start`, a test watcher, a build script, whatever iterates on your project — without `cd`'ing, manually installing, or finding the right command. Opt-in via `.codev/config.json`; unconfigured repos see zero behavior change. + +### Config: the `worktree` block + +```jsonc +{ + "worktree": { + "symlinks": ["..."], // glob patterns of files to symlink from root into each new worktree + "postSpawn": ["..."], // shell commands run inside each new worktree after createWorktree + "devCommand": "..." // consumed by `afx dev ` + } +} +``` + +- `symlinks`: globs resolve from the workspace root; matches symlink into the worktree at the same relative path. Root `.env` and `.codev/config.json` are *always* symlinked regardless. **Symlinks, not copies** — edits to main's env files reflect instantly in any running dev session. A directory match is silently skipped (so a glob can't mask the worktree's own source) **unless** the entry ends with a trailing slash: `".local-user-data/"` is treated as a literal path and symlinks the directory whole (shared with the parent, not branch-isolated; a dangling link is fine if the source doesn't exist yet). +- `postSpawn`: each command runs sequentially with `cwd` = worktree path. Non-zero exit aborts the spawn loud (half-built worktree stays for inspection). +- `devCommand`: the foreground command that starts your dev process (a server, a watcher, `cargo run`, `expo start`, a build script — whatever iterates on your project). Required for `afx dev` to work. + +**Codev does not auto-detect your stack.** Pick the recipe below that matches your toolchain. + +### CLI + +```bash +afx dev # start dev in 's worktree +afx dev main # start dev in the MAIN workspace (Codev-managed) +afx dev --stop # stop the currently running dev PTY (builder or main) +``` + +Only one dev PTY runs at a time (by design — see "URLs are load-bearing" below), across **{main + all builders}**. `main` is a reserved target: it runs `worktree.devCommand` in the main checkout as a Codev-managed, swappable PTY, symmetric with builders. Starting any target while another is up prompts for swap (`afx dev ` while `main` runs, or vice-versa); same-target requests print the existing terminal URL and exit. Like builder dev, main dev is a **non-persistent** PTY — a Tower restart (`pnpm -w run local-install`, crash) kills it; re-run to restart. + +**Launch main dev via `afx dev main`, not a bare `pnpm dev`.** A manually-run `pnpm dev` at the repo root is invisible to Codev (the deliberate "never kill what it didn't spawn" policy) — start a builder dev while it holds the ports and the builder dev silently fails to bind, or worse serves main's code under the worktree URL. `afx dev main` makes it a managed PTY that swap-detection can cleanly stop first. This only helps if you use it *consistently*; a hand-started `pnpm dev` stays unmanaged. + +### VSCode + +The same actions are available via right-click on any builder row in the Codev sidebar (Builders or Needs Attention view): + +- **Codev: Open Builder Terminal** — opens that builder's AI terminal in a VSCode tab (same as left-clicking the row). +- **Codev: Open Worktree Folder** — opens `.builders//` in the OS file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux). +- **Codev: Run Worktree Setup** — applies the configured `worktree.symlinks` and runs the `worktree.postSpawn` commands against the existing worktree (mirrors what spawn does, minus the git steps). Idempotent: existing symlinks are skipped, missing ones added. Useful when the lockfile changed (reinstall deps), `symlinks` or `postSpawn` was extended after the builder spawned, a symlink was accidentally deleted, or the original setup aborted mid-run. Opens a fresh VSCode terminal so install output streams live. Available via CLI too: `afx setup `. +- **Codev: View Diff** — opens a single unified diff editor for `main...HEAD` of that builder's worktree, with a file-list pane on the left (matches VSCode's built-in Source Control "Working Tree" view). Status icons indicate added / modified / deleted. Empty diff → friendly toast. +- **Codev: Run Dev** — reads `worktree.devCommand` from `.codev/config.json`, asks Tower to spawn a dev PTY in the builder's worktree, and opens it as a VSCode terminal tab named `Codev: (dev)`. If another builder's dev is already running, you get a modal asking whether to swap. +- **Codev: Stop Dev** — kills the running dev PTY and closes its tab. + +The Codev sidebar's **Workspace** view also carries a dev control for *whatever folder this VSCode window is rooted at* (it is not "main"-specific): + +- **Start Dev** — runs `worktree.devCommand` for the current workspace. Target is resolved from the open folder: the main checkout → `main`; a `.builders//` worktree opened as its own window (e.g. via *Open Worktree as Workspace*) → that builder. Same single-slot swap model as builder dev (prompts if another dev is running). The row tooltip names the resolved target. +- **Stop Dev** — stops this workspace's dev; the row appears only while it is running. Scoped to the resolved target — it does not touch other devs. + +The three commands are also available from the command palette (Cmd+Shift+P). No default keybindings; bind via `keybindings.json` if you use them often. + +### URLs are load-bearing + +The dev PTY uses **the same ports and URLs as main** intentionally. OAuth callbacks, CORS allowlists, cookie scoping, CSP `connect-src`, webhook URLs are all keyed off origin — running the worktree on a different port would break them. Consequence: stop main's `pnpm dev` before `afx dev`. If you don't, the spawned dev fails at bind time with its own `EADDRINUSE`. Prefer `afx dev main` (or the Workspace view's *Start Dev* row) over a hand-run `pnpm dev` so Codev owns the PTY and swap-detection can stop it for you automatically. + +### Cleanup semantics + +`afx dev --stop` and the swap path kill the entire PTY process group (SIGTERM, escalating to SIGKILL after 5s via `PtySession.kill`). That signals every grandchild of a monorepo dev orchestrator (`pnpm dev`, `turbo dev`, `pnpm -r --parallel run dev`, etc.) simultaneously. The OS reclaims ports as a consequence — Codev never touches ports directly. + +**Orphan recovery** — if Tower itself hard-crashes mid-dev and a process is left holding a port outside Codev's records: + +```bash +lsof -ti : | xargs kill # one port +lsof -ti :3000,:3001,:4000 | xargs kill # several at once +``` + +### Runnable Worktree Recipes + +Ready-to-paste blocks per stack. Adjust ports / paths to your project. + +**pnpm monorepo (Next.js + Turbo style):** +```json +{ + "worktree": { + "symlinks": [".env.local", ".env.development.local", "packages/*/.env", "packages/*/.env.local", "turbo.json"], + "postSpawn": ["pnpm install --frozen-lockfile"], + "devCommand": "pnpm dev" + } +} +``` + +**npm (single package):** +```json +{ + "worktree": { + "symlinks": [".env.local", ".env.development"], + "postSpawn": ["npm ci"], + "devCommand": "npm run dev" + } +} +``` + +**yarn:** +```json +{ + "worktree": { + "symlinks": [".env.local"], + "postSpawn": ["yarn install --frozen-lockfile"], + "devCommand": "yarn dev" + } +} +``` + +**bun:** +```json +{ + "worktree": { + "symlinks": [".env.local"], + "postSpawn": ["bun install --frozen-lockfile"], + "devCommand": "bun dev" + } +} +``` + +**cargo (Rust):** +```json +{ + "worktree": { + "symlinks": [".env"], + "postSpawn": [], + "devCommand": "cargo run" + } +} +``` + +**poetry / uv (Python):** +```json +{ + "worktree": { + "symlinks": [".env", ".env.local"], + "postSpawn": ["uv sync"], + "devCommand": "uv run python -m myapp" + } +} +``` + +**go mod:** +```json +{ + "worktree": { + "symlinks": [".env"], + "postSpawn": ["go mod download"], + "devCommand": "go run ./cmd/server" + } +} +``` + diff --git a/codev-skeleton/roles/architect.md b/codev-skeleton/roles/architect.md index 56cac231d..ce1be5156 100644 --- a/codev-skeleton/roles/architect.md +++ b/codev-skeleton/roles/architect.md @@ -52,7 +52,7 @@ afx send 0001 "message" # Short message to builder > **Note:** `--protocol` is REQUIRED for all numbered spawns. Only `--task`, `--shell`, and `--worktree` spawns skip it. -**Note:** `afx`, `consult`, `porch`, and `codev` are global commands. They work from any directory. +**Note:** `consult`, `porch`, and `codev` are global commands that work from any directory. `afx` is installed globally too, but run it only from the main workspace root (scar rule — see Critical Rules). ### Porch CLI (for strict mode) @@ -243,8 +243,8 @@ afx cleanup -p 0042 1. **DO NOT merge PRs yourself** - Let builders merge their own PRs 2. **DO NOT commit directly to main** - All changes go through builder PRs 3. **DO NOT use `afx send` for long messages** - Use GitHub PR comments instead -4. **DO NOT run `afx` commands from inside a builder worktree** - All `afx` commands must be run from the repository root on `main`. Spawning from a worktree nests builders inside it, breaking everything. -5. **DO NOT `cd` into a builder worktree** - All CLI tools (`afx`, `porch`, `consult`, `codev`) are global commands that work from any directory. If a command fails, debug it — don't cd into the worktree. Use absolute paths with the Read tool to inspect builder files (e.g., `Read /path/to/.builders/0042/codev/specs/...`). +4. Run `afx` commands only from the main workspace root, never from inside a builder worktree — spawning from a worktree nests builders and breaks the workspace. +5. **DO NOT `cd` into a builder worktree** - `porch`, `consult`, and `codev` are global commands that work from any directory (`afx` is the exception — rule 4). If a command fails, debug it — don't cd into the worktree. Use absolute paths with the Read tool to inspect builder files (e.g., `Read /path/to/.builders/0042/codev/specs/...`). ### ALWAYS Do These: 1. **Create GitHub Issues first** - Track projects as issues before spawning diff --git a/codev-skeleton/roles/builder.md b/codev-skeleton/roles/builder.md index be5d7cbf5..78c92613d 100644 --- a/codev-skeleton/roles/builder.md +++ b/codev-skeleton/roles/builder.md @@ -62,7 +62,7 @@ You must: - **Don't manually follow SPIR steps** - Porch handles this - **Don't run consult directly** - Porch runs 3-way reviews -- **Don't edit status.yaml phase/iteration** - Only porch modifies state +- Never hand-edit `status.yaml` — only porch commands modify project state. - **Don't call porch approve** - Only humans approve gates - **Don't skip gates** - Always stop and wait for approval @@ -228,5 +228,5 @@ Rules: - **Keep worktree clean** - No untracked files, no debug code - **(Strict mode)** Run porch, don't bypass it - **(Strict mode)** Stop at gates - Human approval is required -- **(Strict mode)** NEVER edit status.yaml directly +- **(Strict mode)** Never hand-edit `status.yaml` — only porch commands modify project state. - **(Strict mode)** NEVER call porch approve diff --git a/codev-skeleton/templates/AGENTS.md b/codev-skeleton/templates/AGENTS.md index 35d705ccf..db5107903 100644 --- a/codev-skeleton/templates/AGENTS.md +++ b/codev-skeleton/templates/AGENTS.md @@ -101,7 +101,7 @@ Use sequential numbering with descriptive names: ## Git Workflow -**NEVER use `git add -A` or `git add .`** - Always add files explicitly. +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. Commit messages format: ``` diff --git a/codev-skeleton/templates/CLAUDE.md b/codev-skeleton/templates/CLAUDE.md index 07e5fc4a1..48820cf39 100644 --- a/codev-skeleton/templates/CLAUDE.md +++ b/codev-skeleton/templates/CLAUDE.md @@ -99,7 +99,7 @@ Use sequential numbering with descriptive names: ## Git Workflow -**NEVER use `git add -A` or `git add .`** - Always add files explicitly. +Never `git add -A` / `--all` / `.` — stage each file explicitly by path. Commit messages format: ``` diff --git a/codev/consult-types/integration-review.md b/codev/consult-types/integration-review.md deleted file mode 100644 index d522de2ca..000000000 --- a/codev/consult-types/integration-review.md +++ /dev/null @@ -1,75 +0,0 @@ -# Integration Review Prompt - -## Context -You are performing an integration review of a pull request. The builder has created a PR and you are evaluating whether this change fits well into the broader system. This is the architect's review, focusing on how the change integrates rather than whether it works. - -## Focus Areas - -1. **Architectural Fit** - - Does this change follow existing patterns in the codebase? - - Are there inconsistencies with how similar things are done elsewhere? - - Does it introduce new patterns that should be adopted more broadly? - - Are dependencies appropriate and minimal? - -2. **System Impact** - - What other parts of the system might be affected? - - Are there potential side effects not addressed? - - Does this break any existing functionality? - - Are there performance implications? - -3. **API/Interface Quality** - - Are new interfaces well-designed and consistent? - - Will this be easy for other developers to use? - - Is it properly documented for consumers? - - Does it follow existing conventions? - -4. **Maintenance Burden** - - Is this code maintainable by others? - - Are there any "clever" solutions that should be simplified? - - Is the complexity justified? - - Will this be easy to debug when issues arise? - -5. **Migration/Compatibility** - - Are there backward compatibility concerns? - - Is migration path clear for existing users? - - Are breaking changes properly communicated? - -6. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - Compare spec's "Goals" section and flow diagrams to actual behavior - - If spec says "async/non-blocking", verify the code is actually async - - If spec says "immediate response", verify user isn't blocked waiting - - **CRITICAL:** Tests passing does NOT mean UX requirements are met - verify manually - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... - -INTEGRATION_NOTES: -- [Note about system integration] -- [Note about follow-up work needed] -``` - -**Verdict meanings:** -- `APPROVE`: Ready to merge -- `REQUEST_CHANGES`: Integration issues that must be addressed -- `COMMENT`: Suggestions for improvement, can merge but consider feedback - -## Notes - -- The implementation has already been reviewed - don't re-review code quality -- Focus on "how does this fit the system" not "does this work" -- Consider: Will I regret merging this in 6 months? -- If requesting changes, be specific about what needs to change -- INTEGRATION_NOTES can include suggestions for follow-up specs diff --git a/codev/plans/1252-prompt-architecture-single-own.md b/codev/plans/1252-prompt-architecture-single-own.md new file mode 100644 index 000000000..a6f6a5fc9 --- /dev/null +++ b/codev/plans/1252-prompt-architecture-single-own.md @@ -0,0 +1,745 @@ +--- +approved: 2026-07-27 +validated: [gemini, codex, claude] +--- + +# Plan: Prompt Architecture — Single-Owner Rule for Instruction Content + +## Metadata + +- **ID**: plan-2026-07-27-prompt-architecture-single-owner +- **Status**: approved (plan-approval gate, 2026-07-28, jointly with the D5 spec delta) +- **Specification**: [`codev/specs/1252-prompt-architecture-single-own.md`](../specs/1252-prompt-architecture-single-own.md) +- **Issue**: #1252 +- **Created**: 2026-07-27 + +--- + +## Executive Summary + +The spec establishes that Codev's instruction surface carries ~76 shadow copies +of skeleton files, 17 of them drifted, and that the drift is already live — this +project's own spawn prompt lost its `Verify Phase` section. It also establishes +that a detector for exactly this (`protocol-drift-audit`, #1210) has been +shipping the finding to `codev doctor` all along, unread, because nothing fails +the build. + +The implementation follows the spec's **B → A → C** sequencing: make drift fail +CI, then remove the shadow tree, then deduplicate the remaining single surface. +Eight phases, each independently committable. + +**One ordering decision beyond the spec's stated constraints.** The spec fixes +two orderings — `M11 → M3 → M8` (audit before reconcile before delete) and +"M5 green before Approach C." It does not say where the scar-rule work sits +relative to deletion. Compressing eight scar rules across every surface *before* +deleting the shadow tree would mean carefully rewriting ~36 files, roughly half +of which get deleted two phases later — wasted work, and a real chance of +reconciling a compression edit against a skeleton that never received it. So +**scar compression (Phase 5) runs after shadow-tree removal (Phase 4)** and +still lands well before deduplication (Phase 7), satisfying the spec's actual +constraint. + +```json +{ + "phases": [ + {"id": "phase_1", "title": "Drift gate + measurement baseline"}, + {"id": "phase_2", "title": "Local-unique content audit (M11)"}, + {"id": "phase_3", "title": "Reconcile the 17 drifted files (M3)"}, + {"id": "phase_4", "title": "Compatibility audit + shadow-tree removal"}, + {"id": "phase_5", "title": "Scar-rule registry with compressed wordings"}, + {"id": "phase_6", "title": "Ownership map + completeness enforcement"}, + {"id": "phase_7", "title": "Deduplication and measurement"}, + {"id": "phase_8", "title": "Governance sync + end-to-end verification"} + ] +} +``` + +### Criteria-to-phase map + +| Phase | Delivers | Verified by | +|---|---|---| +| 1 | M2 (gate), M6, **M12a (behavioural baseline)** | T5, T1, T14 | +| 2 | M11 (audit + escalations) | T11 | +| 3 | M3 (D1 reconciliation) | T2, T3, allowlist decay | +| 4 | M7, M8, M9, M10 | T8, T9, T10 | +| 5 | M5 (D3 registry, eight compressed rules) | T6 | +| 6 | M1, M4 | T7, T12 | +| 7 | S1, N1 | T4, T13(a) | +| 8 | C6 retirement, N2, N3, N4, **M12c follow-up** | T10, T13(a)+(b) | +| verify | **M12b** (post-merge behavioural comparison) | Appendix D §4 | + +--- + +## Success Metrics + +Carried from the spec: + +- [ ] **M1** Ownership map, machine-readable, with completeness rule +- [ ] **M2** Drift fails CI; allowlist decays to empty +- [ ] **M3** All 17 drifted files reconciled per D1 +- [ ] **M4** Single-owner enforcement derived from the map +- [ ] **M5** Eight scar rules registered in compressed canonical form +- [ ] **M6** Measurement script committed +- [ ] **M7** Compatibility audit complete +- [ ] **M8** Shadow copies removed, local-only entries preserved +- [ ] **M9** `copyProtocols`/`copyRoles` removed +- [ ] **M10** Post-deletion resolver equivalence +- [ ] **M11** All 76 shadow copies in a terminal state TS1–TS4, zero open escalations +- [ ] **S1** Non-scar duplicated classes reduced to owner + references +- [ ] **N1** Always-on word reduction reported (target ≥ 20% of ~24,600) +- [ ] **N2** Full suite green +- [ ] **N3** CLAUDE.md ≡ AGENTS.md +- [ ] **N4** Spec 987 hot-tier caps respected + +--- + +## Phase Breakdown + +### Phase 1: Drift gate + measurement baseline + +**Dependencies**: None +**Delivers**: M2, M6 + +#### Objective + +Make shadow drift fail the build, and capture the before-measurement that N1 is +scored against. This is the spec's Approach B — cheap, and the safety net that +makes every later phase auditable. + +#### Implementation + +- **New** `packages/codev/src/__tests__/shadow-drift-gate.test.ts`: + - Call the existing `auditProtocolDrift()` from + `packages/codev/src/lib/protocol-drift-audit.ts`. **Do not reimplement + detection** — #1210 already classifies each shadow copy `identical | differs`. + - Fail on any `differs` finding absent from the allowlist. + - Assert the gate bites: construct a fixture workspace with a seeded + divergence and confirm the check reports failure. A gate that only ever sees + a clean tree is indistinguishable from a no-op. +- **New** `packages/codev/src/__tests__/fixtures/shadow-drift-allowlist.ts`: + - Seeded with the **17 currently-drifted files**, each carrying a + justification comment `// pending reconciliation — Phase 3 (D1)`. + - Starting populated is deliberate: the tree is dirty today, and a gate that + fails on commit is a gate someone disables. Phase 3 empties it. + - Include the allowlist **lifecycle assertion** (Gemini's iteration-2 point): + every entry needs a justification string, and entries citing "pending + reconciliation" must be gone once Phase 3 lands. +- **New** `scripts/measure-prompt-surface.sh`: + - Emits the spec's inventory table — per-surface word counts, the always-on + subtotal, and the ~24,600 baseline arithmetic. + - Committed and re-run in Phase 7; both outputs recorded in the review. + +**Step 1b — behavioural baseline (M12a).** *Added by directive D5.* + +This must complete **in Phase 1**, because every later phase alters served +prompt content — Phase 3 restores sections, Phase 5 compresses scar rules, +Phase 7 dedups. Once any of those land there is no clean "before." + +- **New** `packages/codev/src/lib/prompt-behavior-metrics.ts` (logic) + + `packages/codev/scripts/measure-prompt-behavior.ts` (thin CLI runner), + implementing metrics **B1–B4** from spec Appendix D. *Placed in the package, + not root `scripts/`: it needs `js-yaml`, which a root-level script cannot + resolve in this pnpm workspace, and it belongs beside the sibling audit + libraries `protocol-drift-audit.ts` / `framework-ref-audit.ts`.* + - **B1** CMAP `REQUEST_CHANGES` rate (share of all verdicts) and **B2** review + rounds per plan phase (`max(iteration)` per `plan_phase`), parsed from + `codev/projects/*/status.yaml` → `history[]`. Sample: **the 17 SPIR projects + with non-empty `history`**. + - **Do not implement B2 as "rounds to unanimous approve."** Verified against + the corpus: **0 of 48 terminal plan phases end with 3× APPROVE** — porch + advances on builder rebuttal, not consensus, so such a counter never + resolves. Measured baselines to reproduce: **B1 = 51.9%** (n=160 verdicts), + **B2 mean = 1.12** (n=49 phases), **B4 mean = 3.06** (n=18 projects). + The script must reproduce these numbers on the current commit. + - **B3** scar-violation incidents, keyword-mined across **211** + `codev/reviews/*.md` and **139** `codev/state/*_thread.md`. Must emit + **matched excerpts, not just counts** — the mining is fuzzy (documentation + *about* a rule reads much like a violation of it) and a human adjudicates. + - **B4** review rounds per project (sum of B2 across its phases). + - **B5** consult cost/duration — **forward snapshot only, advisory, + non-deterministic**; `consult stats` is a rolling 30-day local DB with no + Feb–Jun history. **Excluded from T14's determinism assertion and from every + rollback trigger** — it cannot be reproduced from a commit. +- **New** `codev/resources/1252-behavior-baseline.md` — the committed numbers. +- **Do not implement gate-rejection counts.** Verified unavailable: gate + `status` only ever takes `approved | complete | in_progress | pending` across + all 201 projects, and `requested_at` is overwritten rather than appended, so a + rejected-then-approved gate is indistinguishable from a clean approval. Spec + Appendix D §2 records this; the script should not fake it. + +#### Success criteria + +- `auditProtocolDrift()` is invoked, not duplicated. +- Seeded-divergence fixture fails; clean tree passes. +- Word-count baseline committed. +- **Behavioural baseline committed** (M12a) — B1–B5 over the stated sample, + with B3 excerpts included for adjudication. +- **No phase altering served prompt content has run yet.** + +#### Test approach + +T5 (drift gate, incl. the bites-check), T1 (inventory reproduction), +T14 (baseline script runs clean and is deterministic on a fixed corpus). + +--- + +### Phase 2: Local-unique content audit (M11) + +**Dependencies**: Phase 1 +**Delivers**: M11 audit + escalations + +#### Objective + +Before anything is overwritten or deleted, determine what in the shadow tree is +**codev-specific functionality** rather than rot. This is the architect's D2 +safeguard and the phase that protects against silent capability loss. + +#### Implementation + +- **New** `codev/resources/1252-shadow-tree-audit.md` — one row per shadow copy, + all 76: + + | File | Divergence | Classification | Terminal state | Ruling | + |---|---|---|---|---| + +- **The table must be machine-parseable — T11 parses it** (Claude, plan review). + Fixed five-column pipe table, one row per file, with `Classification` drawn + from exactly `rot | local-unique` and `Terminal state` from exactly + `TS1 | TS2 | TS3 | TS4 | pending`. Free-form prose anywhere in the table makes + T11 unimplementable. Narrative commentary goes *below* the table, not inside + it. + +- Classification per D2: **rot** (local lags skeleton) vs **local-unique** + (content absent from the skeleton that plausibly encodes codev-specific + functionality). +- **Audit content, not just files.** A local-unique paragraph inside an + otherwise-rotted file is the loss this phase exists to prevent, and Phase 3 + would destroy it first. Every hunk in each of the 17 diffs is classified, not + just the file as a whole. +- The 59 `identical` copies are recorded as rot → **TS1** without further + analysis (nothing to lose). +- The 3 local-only entries (`release/`, + `maintain/templates/{audit-report.md,lessons-learned.md}`) are recorded and + **preserved** — they have no skeleton counterpart. +- **Ambiguous → local-unique → escalate.** Per the spec: a needless question is + cheap; a silently deleted behaviour is not. +- Escalate every local-unique finding to the architect via `afx send` with the + diff hunk and a short read on what it appears to provide. Record the ruling + and resulting terminal state (TS1–TS4) in the audit. + +#### Success criteria + +*(Amended at Phase 2, per Codex's iteration-1 finding — the original criteria +contradicted the spec's own sequencing. The spec allows escalations to remain +open into Phase 3, which "skips anything M11 escalated", and requires resolution +**before Phase 4's deletion** — M8 is "gated on M11: no file is deleted until … +any escalations are ruled on." The original "zero rows pending" at Phase 2 close +would have forced the TS3 escape hatch within minutes of escalating, bypassing +the architect discussion D2 exists to guarantee. The escape hatch is for +escalations that *cannot* be resolved, not for skipping the wait.)* + +- One row per shadow copy (77 — mechanical enumeration corrected the spec's + hand count of 76), each with a valid classification. +- Every `rot` row assigned a terminal state; zero rows *unclassified*. +- Every `local-unique` row **escalated** to the architect, with the escalation + recorded in the row (`ESCALATED` note). `pending` is permitted **only** for + such rows. +- **Resolution deadline is Phase 4, not Phase 2**: before any deletion + executes, every `pending` row must be resolved by architect ruling or — only + if a ruling genuinely cannot be obtained — by the TS3 escape hatch with a + filed follow-up issue. T11 enforces this mechanically (see below). + +#### Test approach + +T11 — asserts row count, complete classification, escalation notes on every +pending row, and that nothing local-unique was touched without a ruling. Two +completion guards: a phase-gated zero-pending assertion, plus an **automatic** +one — if any audited file has been deleted from `codev/`, zero pending rows may +remain anywhere. Deletion is the point of no return, so the guard arms itself +the moment Phase 4 starts; it cannot be forgotten the way a manual flag can. + +--- + +### Phase 3: Reconcile the 17 drifted files (M3) + +**Dependencies**: Phase 2 (**hard** — reconciling before auditing destroys the +evidence) +**Delivers**: M3 + +#### Objective + +Apply decision D1: the skeleton is authoritative. Bring the drifted shadow +copies back into agreement so the allowlist empties. + +#### Implementation + +- For each of the 16 drifted files under `codev/protocols/` and + `codev/roles/architect.md`: + - Rows classified **rot** in Phase 2 → take the skeleton version. + - Rows classified **local-unique** → apply the Phase 2 ruling (TS2 promote / + TS3 retain / TS4 drop). **Never silently overwrite.** +- Confirm the headline repair: `codev/protocols/spir/builder-prompt.md` regains + `### Multi-PR Mechanics`, `## Verify Phase`, and the + `"Entering verify phase."` notification string. +- Remove every `// pending reconciliation` entry from the Phase 1 allowlist. Any + residue must be an open M11 escalation citing its adjudication. + +#### Success criteria + +- `diff -rq codev/protocols codev-skeleton/protocols` reports zero differing + files (excluding TS3 retentions, which are allowlisted with justification). +- Allowlist contains no "pending reconciliation" entries. +- Phase 1's gate passes without exemptions beyond documented TS3 items. + +#### Test approach + +T2 (drift counts → 0), T3 (builder-prompt sections present), T5 (gate green). + +--- + +### Phase 4: Compatibility audit + shadow-tree removal + +**Dependencies**: Phase 3 +**Delivers**: M7, M8, M9, M10 + +#### Objective + +Complete the reference audit, then delete the shadow copies so the skeleton +becomes the single owner — the spec's Approach A, approved by D2. + +#### Implementation + +**Step 4a — complete M7** (must finish before any deletion): + +- Extend Appendix B's preliminary audit across **tests** (95 references) and any + non-TypeScript consumers. +- Classify each reference: resolver-routed (safe), comment/error-string (safe), + or direct-read (**must fix before deletion**). +- Appendix B found no direct-read consumer among the 26 non-test hits — + `consult/index.ts:175` uses `readCodevFile`, `porch/protocol.ts` uses + `resolveCodevFile`/`getSkeletonDir` — but the audit is only preliminary and + tests are unexamined. Any direct-read found is fixed to route through + `resolveCodevFile` first. + +**Step 4b — delete (M8)**: + +- Remove shadow copies under `codev/protocols/` and `codev/roles/`. +- **Preserve**: `codev/protocols/release/`, + `codev/protocols/maintain/templates/{audit-report.md,lessons-learned.md}`, and + any TS3 retention from Phase 2. +- `codev/protocols/protocol-schema.json` — verify it is a shadow of + `codev-skeleton/protocols/protocol-schema.json` and not separately referenced + by path before removing. + +**Step 4c — vestigial cleanup (M9)**: + +- Delete `copyProtocols` (`packages/codev/src/lib/scaffold.ts:480`) and + `copyRoles` (`:425`). +- **Test scope, exactly**: `scaffold.test.ts` has a `copyRoles` describe block + (~lines 156–195) which is removed with it. **`copyProtocols` has no test + cases** — it is referenced nowhere outside its own definition. The first draft + of this plan said "their `scaffold.test.ts` cases," implying both; corrected + after Codex checked it against the tree. +- Neither is called by `init`, `adopt`, or `update` — they are dead code that + would manufacture this problem for every adopter if rewired. + +**Step 4d — equivalence (M10)**: + +M10 has **two halves**, and the first draft of this plan only covered the first +(caught by Codex at plan review). Both ship here: + +- **New** `packages/codev/src/__tests__/shadow-removal-equivalence.test.ts`: + - **(i) Per-file resolution.** For every deleted path, `resolveCodevFile` + returns the skeleton counterpart with matching content. + - **(ii) Assembled-prompt byte-equivalence.** Assemble the builder spawn + prompt for each protocol (spir, aspir, bugfix, air, pir, …) **before** + deletion, snapshot it, then assert the post-deletion assembly is + **byte-identical** to that snapshot. +- Why (ii) is not redundant with (i): per-file resolution can be correct while + assembly still differs — ordering, interpolation of `{{project_id}}`, + or a template picked up from a different tier would all pass (i) and change + the prompt. The whole point of Phase 4 is that deletion is a no-op for what + agents actually receive, and only (ii) demonstrates that. +- Distinct from Phase 8's T13, which asserts *content presence* after + compression and dedup have deliberately changed the text. Here the assertion + is *nothing changed at all*. +- Snapshots are captured at the start of Phase 4 (pre-deletion tree) and + committed as fixtures. + +#### Success criteria + +- M7 audit committed; zero unfixed direct-read consumers. +- Shadow copies gone; all preserved entries intact and resolving. +- `copyProtocols`/`copyRoles` absent. +- `porch`, `consult`, and `codev doctor` all still resolve protocol files. + +#### Test approach + +T8 (local-only preservation), T9 (resolver equivalence), T10 (full regression — +`skeleton`, `protocol-drift-audit`, `protocol-prompt-audit`, +`framework-ref-audit`, `scaffold`). + +--- + +### Phase 5: Scar-rule registry with compressed wordings + +**Dependencies**: Phase 4 (see the Executive Summary ordering note — compressing +before deletion would edit files about to be deleted) +**Delivers**: M5, D3 + +#### Objective + +Register the eight ratified scar rules in compressed canonical form and make +deleting or rewording any of them fail the build — **before** Phase 7 touches a +single line of duplicated text. + +#### Implementation + +- **New** `codev/resources/scar-rules.yaml`: + + ```yaml + scar_rules: + - id: git-add-explicit + canonical: "Never `git add -A` / `.` / `--all` — stage files explicitly." + must_appear_on: [claude-md, agents-md, arch-critical, ...] + ``` + +- All **eight** rules from D3: the original six plus (7) never kill shellper + processes without the verified-orphan procedure, and (8) never restart Tower + without explicit human permission. +- **Compress each to one sentence, two at most** (D3). Today's + `### 🚨 ABSOLUTE PROHIBITION: NEVER USE git add -A 🚨` block in CLAUDE.md + collapses to a single line. +- **Meaning preservation is the risk here, not brevity.** Each compressed + wording is diffed against its longest existing variant and checked to retain: + the prohibition, its scope, and any named escape hatch (e.g. rule 2's "use + `--resume`, and ask when in doubt"). Compression that drops the escape hatch + turns guidance into a dead end. +- Replace all 9 existing `git add -A` variants — and the equivalents for the + other seven rules — with the byte-identical canonical string on every surface + in `must_appear_on`. +- **Phase 5 owns every scar-wording edit, on every surface, with no exceptions.** + That explicitly includes `CLAUDE.md` and `AGENTS.md`: they are in + `must_appear_on`, so they are rewritten *here*, and the byte-identical pair + invariant (N3) is maintained within this phase. Phase 8 does **not** re-apply + scar wordings — it only parity-checks N3 and lands the separate Phase 7 dedup + edits. Without this split, M5 would claim delivery before all its surfaces + were actually updated (Codex, plan review). +- **New** `packages/codev/src/__tests__/scar-rules.test.ts`: verbatim presence on + every required surface; **mutation checks** — deleting a rule fails, rewording + it fails. + +#### Success criteria + +- Eight rules registered, each one or two sentences. +- Every surface carries the canonical string byte-identically. +- Mutation tests demonstrably fail on deletion and on rewording. +- No scar rule lost or weakened (manual meaning-preservation review recorded). + +#### Test approach + +T6, plus the meaning-preservation diff recorded in the phase commit. + +--- + +### Phase 6: Ownership map + completeness enforcement + +**Dependencies**: Phase 4 (map a single tree, not a doubled one), Phase 5 +(scar rules must already be registered so the map can mark them `scar`) +**Delivers**: M1, M4 + +#### Objective + +Author the machine-readable ownership map and enforce both single-ownership +*and* the map's exhaustiveness — the latter being Codex's iteration-2 catch. + +#### Implementation + +- **New** `codev/resources/prompt-ownership.yaml` per Appendix A: `surfaces` + (id, path, load) and `instructions` (id, summary, owner, scar, + canonical_wording, must_appear_on, pattern, enforcement). +- **New** `codev/resources/prompt-ownership.md` — human-readable companion, + generated from or validated against the YAML. +- **Declare the inventory boundary** explicitly in the YAML: the exact file set + scanned. Anything outside is out of scope *by declaration*, not omission. +- **New** `scripts/extract-instruction-candidates.ts`: mechanically collects + normative statements (`MUST`, `NEVER`, `ALWAYS`, `DO NOT`, `don't`, …) inside + the boundary, each with a stable id. +- Every candidate gets exactly one disposition: `mapped`, `scar`, or + `out-of-scope` **with written justification**. +- **Required**: record why `codev/resources/` is excluded from the drift regime + (Q7 — `FRAMEWORK_DRIFT_DIRS` already omits `resources`; the map states the + reason so the next person doesn't read a correct default as an oversight). +- **New** `packages/codev/src/__tests__/prompt-ownership.test.ts`: + - **T7 / M4** — for each `enforcement: automated` class, the pattern matches + on exactly the declared owner. Assertions are **derived from the YAML**; + restating ownership in test code would itself violate the single-owner rule. + - **T12 / M1** — fails on any undispositioned candidate, and is itself + validated against a **seeded** normative line so it cannot pass vacuously on + an empty candidate set. + +#### Success criteria + +- Map covers the declared boundary with zero undispositioned candidates. +- T7 derives from the map file, not from literals. +- T12 fails on a seeded line and on a removed disposition. + +#### Test approach + +T7, T12. + +--- + +### Phase 7: Deduplication and measurement + +**Dependencies**: Phase 6 (the map says what may be reduced), Phase 5 (**hard** — +M5 green before anything is stripped) +**Delivers**: S1, N1 + +#### Objective + +Reduce non-scar duplicated instruction classes to their single owner plus +references, and report the measured win honestly. + +#### Implementation + +- For each `scar: false` class with duplicates: keep the owner's full statement; + replace other occurrences with a one-line reference. +- **Reference format** (Claude asked for an example): a single line naming the + owning surface and the rule, e.g. + `> Plans contain no time estimates — see \`spir/protocol.md\` § Plan.` + Prose reference, not a machine pointer: the consumer is a model reading the + prompt, and it must be able to act on the reference without resolving it. The + exact string per class is recorded in the ownership map's `references` field + so T7 can verify placement. +- **Scar rules are not touched** — C3, and Phase 5's tests would fail anyway. + Their contribution to N1 came from Phase 5's compression, which shortened them + without reducing their reach. +- Re-run `scripts/measure-prompt-surface.sh`; record before/after and the + achieved percentage. +- **Report the achieved figure whether or not it hits 20%.** N1 is a target, not + a gate. If the shortfall is structural — most always-on words being CLAUDE.md + prose that is already single-owned rather than duplicated rules — say so + plainly rather than stripping content to hit a number. + +#### Success criteria + +- No `scar: false` class appears outside its owner except as a reference. +- T13(a) confirms the assembled prompt still carries every rule an agent needs. +- Before/after measurement recorded. + +#### Test approach + +T4 (duplication probe re-run), T7, T13(a). + +--- + +### Phase 8: Governance sync + end-to-end verification + +**Dependencies**: Phase 7 +**Delivers**: C6 retirement, N2, N3, N4, T13(b) + +#### Objective + +Update governance docs to describe the new world, and verify the real user path +rather than trusting green tests. + +#### Implementation + +- **`codev/resources/arch-critical.md`** — the "mirror every framework change in + BOTH trees" fact (C6) is now wrong for `protocols/` and `roles/`. Rewrite that + bullet. **Respect the ≤10-fact / ≤35-line cap** (N4): if the replacement needs + more room, demote a weaker fact to `arch.md` per the displacement rule. Use + the `update-arch-docs` skill. +- **`codev/resources/arch.md`** — record the shadow-tree removal and the + single-owner regime. +- **`codev/resources/lessons-learned.md`** — the durable lesson: *a detector + that reports without failing the build is a detector nobody reads.* #1210 saw + this drift for months. +- **`CLAUDE.md` + `AGENTS.md`** — land Phase 7's dedup edits and **verify the + pair is byte-identical** (N3). Scar wordings are **not** touched here: Phase 5 + already rewrote them on both files. This phase parity-checks that work rather + than repeating it. +- **File the tiering follow-up issue** (D4) now that the ownership map exists — + the prerequisite that made it specifiable. +- **File the A/B eval follow-up issue** (M12c) — controlled same-task old-vs-new + prompt comparison with a held-out grader, which M12's observational design + cannot substitute for. Link it from the spec's Non-goals. +- **T13(b) — rescheduled to verify** (discovered constraint: spawns branch + from main HEAD; a pre-merge probe verifies the wrong tree). Pre-merge proxy: + the prompt-snapshot assertions. The architect runs the real probe at verify. + +#### Success criteria + +- Hot-tier caps respected; maps accurate. +- CLAUDE.md ≡ AGENTS.md byte-for-byte. +- Full suite green. +- **Manual spawn inspected and its outcome recorded in the review.** +- Tiering follow-up issue filed. + +#### Test approach + +T10 (regression), T13(a) automated + **T13(b) manual**, `hot-tier`, +`governance-sweep`. + +--- + +--- + +## Verify Phase (post-merge) — M12b + +SPIR's verify phase is optional and this plan originally left it undefined. +Directive D5 makes it load-bearing: it is where the behavioural claim is settled. + +**Trigger**: after the PR merges, the project enters `verify`. The builder stays +alive through it (`porch done 1252` signals readiness; the architect approves +`verify-approval`). + +**Window**: the next **N = 10** post-merge builder projects, of which **≥ 3 must +be SPIR**. The SPIR minimum exists because B1/B2 are only minable from SPIR +projects — `history` is empty for `pir`/`bugfix`/`air`. At recent rates +(~4 SPIR/month, ~33 projects/month overall) the SPIR minimum, not the total, is +the binding constraint on how long verify runs. + +**Procedure**: + +1. **T13(b) real-spawn inspection** *(rescheduled here by architect ruling — + `afx spawn` branches from main HEAD, so only a post-merge, + post-local-install probe serves the merged tree + freshly built skeleton)*: + the architect runs a disposable `afx spawn --task` probe from the main + root; confirm the assembled prompt carries the Verify Phase section and all + eight scar rules; record the prompt in the review. +2. Re-run the behavioural measurement over the verify-window projects. +3. Compare B1–B4 (+ B5 advisory snapshot) against + `codev/resources/1252-behavior-baseline.md`. +4. Adjudicate B3 excerpts by hand — the keyword mining produces false positives, + and the count alone is not a finding. +5. Record an explicit **no-regression judgment** in + `codev/reviews/1252-prompt-architecture-single-own.md`. + +**Rollback triggers** (spec Appendix D §4 — reproduced so the verify step is +self-contained): + +| Trigger | Threshold | Action | +|---|---|---| +| **Hard** — scar violation | **Any single** B3 incident traced to a missing/weakened rule | Revert the **Phase 5** compression commit (+ Phase 7 if the rule was a dedup target) | +| **Soft** — review friction | B1 rises **> 25% relative** to the 51.9% baseline (i.e. **above ~64.9%**), sustained | Revert **Phase 7** dedup commits; keep Phases 1–6 | +| **Advisory** | B2/B4/B5 movement with no B1/B3 movement | No revert; record and investigate. B2's range (1–2) is too narrow to trigger; B5 is non-deterministic | +| **Inconclusive** | < 10 projects or < 3 SPIR complete | **Do not declare success** — extend the window or record as inconclusive | + +**Rollback targets trims, never repairs.** Phases 1–4 restore correct content; +reverting them would reintroduce the drift bug. Only Phases 5 and 7 removed +text, so only they are candidates. + +**Honest limit**: with a 17-project baseline and a 10-project window, this +detects a large regression, not a subtle one. The strongest available conclusion +is *"no evidence of behavioural harm at this sample size."* Proving benefit +requires the A/B deferred under M12c. + +--- + +## Risks and Mitigations + +| Risk | Phase | Mitigation | +|---|---|---| +| Codev-specific functionality silently lost | 2, 4 | Phase 2 audits content *inside* drifted files; ambiguous → escalate; nothing local-unique touched without a ruling | +| Reconciliation destroys local-unique content before deletion is reached | 3 | Hard dependency Phase 2 → Phase 3; the spec's `M11 → M3 → M8` order | +| A scar rule dropped or weakened during compression or dedup | 5, 7 | M5 green before Phase 7; mutation tests; explicit meaning-preservation review incl. escape hatches | +| Ownership map under-lists, M4 passes vacuously | 6 | Declared boundary + mandatory disposition; T12 seeded-line validated | +| Deleting the shadow tree breaks a path-based reader | 4 | M7 completed across tests before any deletion; T9 per-file equivalence | +| Allowlist becomes a permanent exemption | 1, 3 | Justification per entry; empties in Phase 3; only open escalations may persist | +| Hot-tier cap breached while fixing C6 | 8 | `update-arch-docs` skill; demote-on-add displacement | +| Green tests, broken real spawn | 8 | T13(b) manual spawn — the exact failure that produced this project | +| Trims degrade behaviour while every structural test stays green | 1, verify | M12 baseline in Phase 1; verify comparison; hard rollback on a single B3 incident | +| Baseline taken after content changed — no clean "before" | 1 | Step 1b completes before Phase 3/5/7 touch served content | +| Verify declares "no regression" on too little data | verify | < 10 projects or < 3 SPIR ⇒ inconclusive, not success | + +--- + +## Rollback + +Each phase is one commit on `builder/spir-1252`. Phases 1–3 are additive or +reconciling and revert cleanly. + +**Phase 4 is the irreversible-feeling one** — but the deleted content is +byte-identical to `codev-skeleton/` (that is precisely what Phases 1–3 +established), so recovery is `git revert` and nothing is unique to the deleted +copies except TS3 retentions, which are preserved by construction. + +--- + +## Open Items for the Architect + +1. **Phase 2 escalations** will arrive mid-implementation via `afx send`. Each + needs a TS2/TS3/TS4 ruling. Unanswered ones convert to TS3 + follow-up issue + per the spec's escape hatch — flagging so that default is visible rather than + silent. +2. **Phase 5 compressed wordings** are the one place where a review by you is + worth more than a test: the tests prove the strings match everywhere, not + that the compressed sentence still carries the rule's force. I will include + the eight before/after pairs in the phase commit message. + +--- + +## Expert Consultation + +### Plan iteration 1 — 3-way review + +| Model | Verdict | Confidence | Issues | +|---|---|---|---| +| Gemini | **APPROVE** | HIGH | None | +| Codex | **REQUEST_CHANGES** | HIGH | 3 | +| Claude | **APPROVE** | HIGH | None blocking (3 minor) | + +All six points accepted, none disputed. + +**Codex — accepted in full:** + +1. *M10 not fully covered in Phase 4.* The spec requires resolver equivalence + **and** byte-identical assembled-prompt output; Phase 4 planned only the + former, and Phase 8's T13 checks presence rather than byte-identity. → + Step 4d now ships both halves, with snapshots captured pre-deletion and the + distinction from T13 stated. +2. *Phase 5 / Phase 8 ownership of CLAUDE.md/AGENTS.md is blurry.* → Phase 5 + now explicitly owns **every** scar-wording edit including both root files; + Phase 8 only parity-checks N3 and lands Phase 7's dedup. Otherwise M5 would + have claimed delivery before all its surfaces were updated. +3. *`scaffold.test.ts` has `copyRoles` coverage but no `copyProtocols` cases.* → + Corrected. (I had established this during the spec phase and then wrote the + plan as though both had tests.) + +**Claude — accepted in full:** + +4. *Phase 2's audit must be machine-parseable for T11.* → Fixed five-column + table with enumerated values for `Classification` and `Terminal state`; + narrative goes below the table. Free-form prose would make T11 + unimplementable. +5. *Phase 7's reference format unspecified.* → Example format given, recorded + per-class in the map's `references` field. +6. *`.mjs` breaks the TypeScript convention.* → `extract-instruction-candidates.ts`. + +**Gemini** raised no issues and specifically endorsed the Phase 5 placement +rationale and the `M11 → M3 → M8` safety ordering. + +Both Codex and Claude independently re-verified the plan's technical claims +against the tree; all held. + +--- + +## Change Log + +| Date | Change | Reason | Author | +|------|--------|--------|--------| +| 2026-07-27 | Initial plan | Spec approved at `spec-approval` | builder spir-1252 | +| 2026-07-27 | Plan with multi-agent review | 3-way iter-1: 6 points accepted | builder spir-1252 | +| 2026-07-27 | Behavioural measurement (D5) | Architect directive: M12 baseline + verify phase | builder spir-1252 | +| 2026-07-27 | Delta review fixes | B2 redefined (unanimity never occurs); B5/T14 determinism reconciled | builder spir-1252 | + +--- + +## Notes + +The plan deliberately front-loads *safety* over *savings*: four of eight phases +land before a single duplicated word is removed. That reflects the spec's +finding that drift, not token count, is the urgent problem — and the architect's +D2 condition that nothing codev-specific be lost on the way. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-rebuttals.md new file mode 100644 index 000000000..7eaee794a --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-rebuttals.md @@ -0,0 +1,57 @@ +# Phase 1 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | APPROVE | 0 | — | 0 | + +**Nothing disputed.** Both Codex findings were real and both are fixed in this +iteration's commit. + +## CX-A — hardcoded SPAWN_PROMPT_WORDS / PHASE_TASK_WORDS + +**Accepted — this would have corrupted the N1 result.** The two largest +always-on inputs were one-off measured constants (4891 / 1395). After Phase 7 +trims the protocol text, a rerun would still report the pre-trim numbers, so the +before/after delta would only reflect CLAUDE.md changes — precisely the +"reproducible before/after script" requirement M6 exists for. + +**Fixed**: both are now derived from resolved artifacts (tier-2 `codev/` first, +then skeleton, matching runtime resolution): + +- spawn proxy = `protocols/spir/builder-prompt.md` + `protocols/spir/protocol.md` + (the parts inlined into every spawn prompt) = 636 + 4087 = **4723** +- phase-task proxy = hot tier (736) + porch phase-prompt mean (400) = **1136** + +Per-project variable content (issue body ≈170 words, task-JSON boilerplate) is +*deliberately excluded*: it is not trimmable prompt surface, and including it +would let the delta be polluted by whichever issue spawned the measuring +builder. Sensitivity-verified: shrinking `protocol.md` in a temp copy moves +ALWAYS_ON 21,856 → 18,048. + +**Consequence**: the reproducible baseline is **21,856**, not the earlier +24,614 (which included the variable content). The spec's N1 note is updated; +N1 is evaluated against 21,856. The word baseline output is now also committed +(`codev/resources/1252-word-baseline.md`) rather than existing only as script +output. + +## CX-B — B5 absent from the committed baseline + +**Accepted.** The plan's success criteria said "B1–B5"; I implemented B1–B4 and +wrote "capture B5 separately" without actually capturing it. The spec's design +(B5 = forward snapshot, advisory, non-deterministic) was never the issue — the +missing part was the snapshot itself. + +**Fixed**: B5 forward snapshot appended to +`codev/resources/1252-behavior-baseline.md` — 30-day `consult stats`: 3,349 +calls, $1,478.01 total, per-model durations/success rates, capture-dated. The +section is explicitly marked appended-at-capture-time (the script deliberately +does not read the machine-local DB, preserving T14 determinism over B1–B4), and +no threshold keys off it. Its verify-phase use is directional context only — +e.g. a B1 rise with collapsing review durations points at degraded review +quality rather than degraded prompts. + +## Status + +Tests re-run green after both fixes (12 passed, 1 phase-gated skip). diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter2-context.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter2-context.md new file mode 100644 index 000000000..0ef9e174f --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter2-context.md @@ -0,0 +1,72 @@ +### Iteration 1 Reviews +- gemini: APPROVE — Phase 1 deliverables (shadow-drift CI gate, surface measurement script, and behavioral metrics baseline) are complete, robustly tested, and fully aligned with the spec and plan. +- codex: REQUEST_CHANGES — Phase 1 lands the drift gate and most of the baseline work, but two phase-required measurements are still incomplete/non-reproducible. +- claude: APPROVE — Phase 1 delivers M2 (drift gate), M6 (measurement script), and M12a (behavioral baseline) cleanly — all tests pass, numbers match the spec, and the baseline is correctly captured before any prompt content changes. + +### Builder Response to Iteration 1 +# Phase 1 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | APPROVE | 0 | — | 0 | + +**Nothing disputed.** Both Codex findings were real and both are fixed in this +iteration's commit. + +## CX-A — hardcoded SPAWN_PROMPT_WORDS / PHASE_TASK_WORDS + +**Accepted — this would have corrupted the N1 result.** The two largest +always-on inputs were one-off measured constants (4891 / 1395). After Phase 7 +trims the protocol text, a rerun would still report the pre-trim numbers, so the +before/after delta would only reflect CLAUDE.md changes — precisely the +"reproducible before/after script" requirement M6 exists for. + +**Fixed**: both are now derived from resolved artifacts (tier-2 `codev/` first, +then skeleton, matching runtime resolution): + +- spawn proxy = `protocols/spir/builder-prompt.md` + `protocols/spir/protocol.md` + (the parts inlined into every spawn prompt) = 636 + 4087 = **4723** +- phase-task proxy = hot tier (736) + porch phase-prompt mean (400) = **1136** + +Per-project variable content (issue body ≈170 words, task-JSON boilerplate) is +*deliberately excluded*: it is not trimmable prompt surface, and including it +would let the delta be polluted by whichever issue spawned the measuring +builder. Sensitivity-verified: shrinking `protocol.md` in a temp copy moves +ALWAYS_ON 21,856 → 18,048. + +**Consequence**: the reproducible baseline is **21,856**, not the earlier +24,614 (which included the variable content). The spec's N1 note is updated; +N1 is evaluated against 21,856. The word baseline output is now also committed +(`codev/resources/1252-word-baseline.md`) rather than existing only as script +output. + +## CX-B — B5 absent from the committed baseline + +**Accepted.** The plan's success criteria said "B1–B5"; I implemented B1–B4 and +wrote "capture B5 separately" without actually capturing it. The spec's design +(B5 = forward snapshot, advisory, non-deterministic) was never the issue — the +missing part was the snapshot itself. + +**Fixed**: B5 forward snapshot appended to +`codev/resources/1252-behavior-baseline.md` — 30-day `consult stats`: 3,349 +calls, $1,478.01 total, per-model durations/success rates, capture-dated. The +section is explicitly marked appended-at-capture-time (the script deliberately +does not read the machine-local DB, preserving T14 determinism over B1–B4), and +no threshold keys off it. Its verify-phase use is directional context only — +e.g. a B1 rise with collapsing review durations points at degraded review +quality rather than degraded prompts. + +## Status + +Tests re-run green after both fixes (12 passed, 1 phase-gated skip). + + +### IMPORTANT: Stateful Review Context +This is NOT the first review iteration. Previous reviewers raised concerns and the builder has responded. +Before re-raising a previous concern: +1. Check if the builder has already addressed it in code +2. If the builder disputes a concern with evidence, verify the claim against actual project files before insisting +3. Do not re-raise concerns that have been explained as false positives with valid justification +4. Check package.json and config files for version numbers before flagging missing configuration diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-rebuttals.md new file mode 100644 index 000000000..fff365fac --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-rebuttals.md @@ -0,0 +1,68 @@ +# Phase 2 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 (remedy differs) | 0 | +| Claude | APPROVE | 1 cosmetic | 1 | 0 | + +## Codex — both findings accepted; the remedy is not "resolve the escalations now" + +Codex is right that the phase, as written, contradicted itself: the plan's +Phase-2 criteria demanded "zero rows pending" while the audit leaves 4 pending +and T11 explicitly tolerates them. **The inconsistency is real. The bug is in +the plan text, not in the pending rows** — and the distinction matters enough +to spell out. + +The spec's sequencing is explicit that escalations outlive Phase 2: + +- M11: "Escalation is **blocking for that file only** — reconciliation and + deletion of the remaining files proceed." +- Phase 3 (M3): "reconcile per D1, **skipping anything M11 escalated**" — the + phase after this one is *designed around* open escalations. +- M8: "**Gated on M11**: no file is deleted until its local-unique audit is + complete **and any escalations are ruled on**" — the real deadline. + +The plan's "zero pending at Phase 2 close" bullet contradicted all three. Had I +satisfied it as written, the only available move within this phase would have +been the TS3 escape hatch — converting all 4 escalations to "keep local" +**within the hour of sending them**, before the architect had any realistic +chance to rule. The escape hatch exists for escalations that *cannot* be +resolved ("architect unavailable, decision genuinely deferred"), not for +skipping the wait. Using it here would have bypassed exactly the discussion D2 +guarantees — Waleed's words: *"if there are any unique things can we discuss +them to make sure we're not losing functionality specific to codev."* A phase +criterion cannot be allowed to strong-arm a human gate. + +**Changes made:** + +1. **Plan amended** (Phase 2 success criteria): one row per shadow copy, all + classified; every `local-unique` row escalated with the escalation recorded; + `pending` permitted only for escalated rows; **resolution deadline is + Phase 4, not Phase 2**. The amendment note explains why the original text + was wrong. +2. **T11 gains an automatic completion guard** — directly addressing Codex's + second point that a manual `ALL_ESCALATIONS_RESOLVED = false` flag lets the + phase pass while violating its criteria. The new guard needs no human to + remember it: **the moment any audited file is missing from `codev/` + (deletion has started), zero pending rows may remain anywhere.** Deletion is + the point of no return, so deletion itself arms the assertion. The manual + flag remains as a belt-and-braces early check, but the enforcement no longer + depends on it. +3. Spec count corrected in place: **77** shadow copies, not 76 (mechanical + enumeration caught `consult-types/integration-review.md`; every "76" in the + spec reads as 77, the audit artifact is authoritative). + +Current escalation state: sent to the architect this session via `afx send` +(max_iterations 8-vs-3; cwd packages/codev), acknowledged in the architect's +standing instruction that rulings will be routed as they arise and that +"unanswered → TS3 stands." Phases 3's rot-reconciliation does not touch the 4 +escalated files; Phase 4 cannot start until they resolve, and T11 now enforces +that mechanically. + +## Claude — cosmetic count accepted + +Header arithmetic said "74 protocols-tree files (63 .md + 11 .json)"; the true +breakdown is **73 (63 .md + 10 .json)** + 3 roles + 1 consult-types = 77. +Fixed. As Claude noted, the test verifies against reality rather than the +header, so this was prose-only. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter2-context.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter2-context.md new file mode 100644 index 000000000..f60296c37 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter2-context.md @@ -0,0 +1,83 @@ +### Iteration 1 Reviews +- gemini: APPROVE — Phase 2 deliverables (M11 shadow-tree audit and T11 process guard tests) are complete, spec-compliant, and well-tested. +- codex: REQUEST_CHANGES — The audit is well-structured and the coverage test is thoughtful, but phase_2 is not complete because local-unique escalations remain unresolved and the test suite explicitly skips enforcing that completion condition. +- claude: APPROVE — Phase 2 audit is thorough, well-evidenced, and correctly escalates the 4 genuinely functional divergences; test coverage is strong with good forward guards for later phases + +### Builder Response to Iteration 1 +# Phase 2 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 (remedy differs) | 0 | +| Claude | APPROVE | 1 cosmetic | 1 | 0 | + +## Codex — both findings accepted; the remedy is not "resolve the escalations now" + +Codex is right that the phase, as written, contradicted itself: the plan's +Phase-2 criteria demanded "zero rows pending" while the audit leaves 4 pending +and T11 explicitly tolerates them. **The inconsistency is real. The bug is in +the plan text, not in the pending rows** — and the distinction matters enough +to spell out. + +The spec's sequencing is explicit that escalations outlive Phase 2: + +- M11: "Escalation is **blocking for that file only** — reconciliation and + deletion of the remaining files proceed." +- Phase 3 (M3): "reconcile per D1, **skipping anything M11 escalated**" — the + phase after this one is *designed around* open escalations. +- M8: "**Gated on M11**: no file is deleted until its local-unique audit is + complete **and any escalations are ruled on**" — the real deadline. + +The plan's "zero pending at Phase 2 close" bullet contradicted all three. Had I +satisfied it as written, the only available move within this phase would have +been the TS3 escape hatch — converting all 4 escalations to "keep local" +**within the hour of sending them**, before the architect had any realistic +chance to rule. The escape hatch exists for escalations that *cannot* be +resolved ("architect unavailable, decision genuinely deferred"), not for +skipping the wait. Using it here would have bypassed exactly the discussion D2 +guarantees — Waleed's words: *"if there are any unique things can we discuss +them to make sure we're not losing functionality specific to codev."* A phase +criterion cannot be allowed to strong-arm a human gate. + +**Changes made:** + +1. **Plan amended** (Phase 2 success criteria): one row per shadow copy, all + classified; every `local-unique` row escalated with the escalation recorded; + `pending` permitted only for escalated rows; **resolution deadline is + Phase 4, not Phase 2**. The amendment note explains why the original text + was wrong. +2. **T11 gains an automatic completion guard** — directly addressing Codex's + second point that a manual `ALL_ESCALATIONS_RESOLVED = false` flag lets the + phase pass while violating its criteria. The new guard needs no human to + remember it: **the moment any audited file is missing from `codev/` + (deletion has started), zero pending rows may remain anywhere.** Deletion is + the point of no return, so deletion itself arms the assertion. The manual + flag remains as a belt-and-braces early check, but the enforcement no longer + depends on it. +3. Spec count corrected in place: **77** shadow copies, not 76 (mechanical + enumeration caught `consult-types/integration-review.md`; every "76" in the + spec reads as 77, the audit artifact is authoritative). + +Current escalation state: sent to the architect this session via `afx send` +(max_iterations 8-vs-3; cwd packages/codev), acknowledged in the architect's +standing instruction that rulings will be routed as they arise and that +"unanswered → TS3 stands." Phases 3's rot-reconciliation does not touch the 4 +escalated files; Phase 4 cannot start until they resolve, and T11 now enforces +that mechanically. + +## Claude — cosmetic count accepted + +Header arithmetic said "74 protocols-tree files (63 .md + 11 .json)"; the true +breakdown is **73 (63 .md + 10 .json)** + 3 roles + 1 consult-types = 77. +Fixed. As Claude noted, the test verifies against reality rather than the +header, so this was prose-only. + + +### IMPORTANT: Stateful Review Context +This is NOT the first review iteration. Previous reviewers raised concerns and the builder has responded. +Before re-raising a previous concern: +1. Check if the builder has already addressed it in code +2. If the builder disputes a concern with evidence, verify the claim against actual project files before insisting +3. Do not re-raise concerns that have been explained as false positives with valid justification +4. Check package.json and config files for version numbers before flagging missing configuration diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-rebuttals.md new file mode 100644 index 000000000..caa67d9c7 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-rebuttals.md @@ -0,0 +1,196 @@ +# Phase 4 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | APPROVE | 1 minor (overlaps Codex #3) | 1 | 0 | + +**Nothing disputed.** Codex's first finding deserves the plain admission: I +delivered less than my own plan promised — a plan line I myself wrote after +Codex caught exactly this gap at plan review. + +## CX-1 — assembled-prompt equivalence was inferred, not exercised + +The plan (amended at plan review, at Codex's insistence) says: *"Assemble the +builder spawn prompt for each protocol before deletion, snapshot it, then +assert the post-deletion assembly is byte-identical."* What I shipped instead +was an argument: resolved-content hashes match, `renderTemplate` is pure, +therefore prompts are equal. The argument happens to be sound — but it tests +the premises, not the conclusion, and it would miss exactly the failures M10 +exists to catch: `buildPromptFromTemplate` picking a different template path, +`resolveCodevIncludes` behaving differently against the post-deletion tree, or +any assembly-layer change between snapshot and check. + +**Fixed — the real path is now exercised.** The pre-deletion tree was +reconstructed from git (`git archive` of the deletion commit's parent), the +genuine `buildPromptFromTemplate` ran against it for all nine protocols with a +fixed `TemplateContext`, and the outputs are committed as +`fixtures/prompt-snapshots/.txt` (spir's is 30,593 bytes — the full +inlined protocol reference included). The test re-runs the same assembly +against the live tree and requires byte-identical output. + +## CX-2 — resolution tier was not asserted + +Correct: I checked *what* content resolves, not *where from*. A content match +served from some unexpected tier would have hidden a resolution bug behind a +green test. + +**Fixed**: the equivalence test now asserts +`path.resolve(resolved) === path.resolve(getSkeletonDir() + rel)` for every +deleted path — content AND tier. + +## CX-3 — bugfix-685's parity became file-vs-itself (Claude concurring, as "minor") + +Correct, and a fair consequence of my mechanical repoint: mapping both sides +of a mirror pair to the skeleton leaves a comparison of a file with itself — +a test that can never fail, which is worse than no test (it *looks* like +coverage). + +**Fixed**: bugfix-685's target list collapsed to a single skeleton list and the +parity test was **removed** with a comment explaining why (no second tree +exists; drift of these prompts is now impossible by construction, and the +grep-regression assertions retain all real value). The same treatment was +applied to `baked-decisions.test.ts`'s Baked-Decisions parity describe — not +flagged by Codex, but it had the identical defect, and leaving it would have +been fixing the reported instance rather than the reported class. Suite count +drops accordingly (3,746 from 3,767): vacuous tests deleted, not skipped. + +Noted for the review doc: Spec 746's parity comment explicitly described the +skeleton-vs-codev drift ("skeleton has Multi-PR Workflow / Verify Phase +sections that codev/ doesn't … PRE-EXISTING and not Phase 1's responsibility") +— the drift this project fixed was *observed and consciously stepped around* +months ago. Detection was never the problem. + +## Status + +Full suite green: 3,746 passed, 0 failures. + +--- + +# Iteration 2 addendum + +| Model | Verdict | Issues | +|---|---|---| +| Gemini | APPROVE | 0 | +| Codex | REQUEST_CHANGES | 2 | +| Claude | APPROVE | 0 | + +Both accepted; both are follow-through failures on my own earlier claims. + +## CX-1 — preserved `release/protocol.md` still `cat`s a deleted file + +Accepted. My M7 sweep covered `packages/*/src`, `scripts/`, workflows — and +never audited **codev/'s own preserved content**. The RELEASE protocol +(local-only, explicitly never shipped) told its reader to +`cat codev/protocols/maintain/protocol.md`, deleted in 4b. Fixed: repointed to +`codev-skeleton/protocols/maintain/protocol.md` with a one-line explanation — +legitimate here precisely because RELEASE is codev-local and the skeleton +source tree is guaranteed present in this repo. + +## CX-2 — bugfix-742's parity became file-vs-itself + +Accepted, and worth the sting: in iteration 1 I wrote that I fixed the vacuous +parity defect "as a class, not an instance" — and missed this instance. The +claim was stronger than the sweep behind it. Fixed the same way as 685: parity +describe removed with an explanatory comment, the substantive assertions +(BUGFIX templates must differ from SPIR's) retained against the skeleton, and +the corrupted `describe.each` table repaired. Suite: 3,730 passed, 0 failures. + +Also inventoried while fixing CX-1: `CLAUDE.md`/`AGENTS.md` carry ~10 prose +references to now-deleted `codev/protocols/...` paths (protocol listing, +release pointer). Those are *references, not fetches*, and both files are +already scheduled for Phase 5 (scar wordings) and Phase 7/8 (dedup + governance +sync) edits — repointing them lands there rather than expanding Phase 4's +commit. Recorded in the audit doc so it cannot be dropped. + +--- + +# Iteration 3 addendum + +| Model | Verdict | Issues | +|---|---|---| +| Gemini | APPROVE | 0 | +| Codex | REQUEST_CHANGES | 2 | +| Claude | APPROVE | 0 | + +Both accepted — with one remedy that differs from Codex's suggested mechanism, +explained below. + +## CX-1 — repointed tests validate `codev-skeleton/` (source), not what is served + +Codex is right about the gap: `resolveCodevFile()` serves the **embedded** +skeleton (`packages/codev/skeleton`, a build-time copy), so tests reading +`codev-skeleton/` could pass while a stale embedded copy serves agents old +content. That is this project's own drift thesis, reappearing at the +build-copy boundary — a copy relationship with no mechanical sync enforcement. + +**Remedy chosen: enforce the boundary once, globally, rather than rerouting +every test.** New `skeleton-embed-sync.test.ts` asserts every file in +`codev-skeleton/` is byte-identical to its embedded counterpart, bidirectionally +(no stale files, no missing files, no extras). With that guard green, a +source-tree read and a resolver read are the same bytes **by construction** — +and source-tree tests have a real advantage the resolver reads lack: they fail +at the commit surface, where the developer edits, *before* a build. The two +layers now split cleanly: content tests guard the source; the sync guard ties +source to served. + +This is the same single-owner pattern the project applies everywhere else: +don't chase N consumers into agreement — enforce the one copy boundary. + +## CX-2 — collapsed mirror structures left duplicate entries + +Accepted, third instance of the mechanical-repoint residue, and this round I +swept the **whole class with a grep for duplicate array entries** rather than +trusting the flagged list: deduped `bugfix-744` (3→2 entries), +`governance-sweep` (6→4), `protocol-prompt-audit` (2 walk roots→1), and +collapsed **three more vacuous pair loops inside `baked-decisions.test.ts`** +(PHASE-2 prompts, spec-review consult-types, docs sections — each was +`readRepoFile(pair.codev) === readRepoFile(pair.skeleton)` with both fields +naming the same file). Pairwise equality became single-owner presence +assertions (clause exists and extracts cleanly). + +Suite: 3,726 passed, 0 failures (count reflects vacuous tests deleted). + +--- + +# Iteration 4 addendum + +| Model | Verdict | Issues | +|---|---|---| +| Gemini | APPROVE | 0 | +| Codex | REQUEST_CHANGES (MEDIUM) | 2 | +| Claude | (pending at fix time) | — | + +Both accepted — and CX-1 is a genuine live catch, the best of the phase. + +## CX-1 — the spawn wrapper told builders to read a deleted file + +The wrapper sentence `"You are a Builder. Read codev/roles/builder.md …"` was +hardcoded at **four** call sites in `spawn.ts` and survived every audit sweep +because it lives in a template string in *production code*, not in a test or +doc. After Phase 4 it pointed at a deleted path — and it was already broken +for fresh installs, where `codev/roles/` never existed (#1011 bug class: the +role is never fetched by the builder at all; spawn injects it via the harness +system prompt and writes `.builder-role.md`). + +**Fixed with the project's own medicine**: the sentence now has a single owner +— `builderPreamble()` in `spawn-roles.ts` — used by all four call sites, and it +points at what is actually delivered ("your system prompt … a copy at +`.builder-role.md`"). Two new tests: the preamble fetches nothing by literal +framework path, and the full served prompt (preamble + assembled template) +for all nine protocols contains no `codev/roles/` reference. + +Note on `--no-role` spawns: the preamble mentions a role file that a no-role +spawn doesn't write. That is strictly better than before (a dangling fetch +instruction in *all* spawns), and no-role is an explicit operator opt-out. + +## CX-2 — the audit overstated the equivalence proof + +Accepted. The audit's "follows from renderTemplate purity" sentence described +the iter-1 inference, not the iter-2 implementation, and either way did not +cover the wrapper layer where CX-1's bug lived. Rewritten to state exactly what +is now proven: tier-asserted resolution, direct snapshot-equivalence of the +assembly for nine protocols, and the preamble/full-prompt guards. + +Suite: 3,728 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-context.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-context.md new file mode 100644 index 000000000..74bae2391 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-context.md @@ -0,0 +1,82 @@ +### Iteration 1 Reviews +- gemini: APPROVE — Phase 4 deliverables (M7, M8, M9, M10) are fully implemented and verified with strong test coverage. +- codex: REQUEST_CHANGES — Phase 4 completes the shadow-tree deletion work, but the required M10 equivalence coverage is only partially implemented. +- claude: APPROVE — Phase 4 cleanly delivers M7/M8/M9/M10 — 77 shadow copies deleted, local-only entries preserved, vestigial functions removed, equivalence proven by 15 passing tests plus 329 regression tests green. + +### Builder Response to Iteration 1 +# Phase 4 — rebuttal to iteration-1 implementation review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | APPROVE | 1 minor (overlaps Codex #3) | 1 | 0 | + +**Nothing disputed.** Codex's first finding deserves the plain admission: I +delivered less than my own plan promised — a plan line I myself wrote after +Codex caught exactly this gap at plan review. + +## CX-1 — assembled-prompt equivalence was inferred, not exercised + +The plan (amended at plan review, at Codex's insistence) says: *"Assemble the +builder spawn prompt for each protocol before deletion, snapshot it, then +assert the post-deletion assembly is byte-identical."* What I shipped instead +was an argument: resolved-content hashes match, `renderTemplate` is pure, +therefore prompts are equal. The argument happens to be sound — but it tests +the premises, not the conclusion, and it would miss exactly the failures M10 +exists to catch: `buildPromptFromTemplate` picking a different template path, +`resolveCodevIncludes` behaving differently against the post-deletion tree, or +any assembly-layer change between snapshot and check. + +**Fixed — the real path is now exercised.** The pre-deletion tree was +reconstructed from git (`git archive` of the deletion commit's parent), the +genuine `buildPromptFromTemplate` ran against it for all nine protocols with a +fixed `TemplateContext`, and the outputs are committed as +`fixtures/prompt-snapshots/.txt` (spir's is 30,593 bytes — the full +inlined protocol reference included). The test re-runs the same assembly +against the live tree and requires byte-identical output. + +## CX-2 — resolution tier was not asserted + +Correct: I checked *what* content resolves, not *where from*. A content match +served from some unexpected tier would have hidden a resolution bug behind a +green test. + +**Fixed**: the equivalence test now asserts +`path.resolve(resolved) === path.resolve(getSkeletonDir() + rel)` for every +deleted path — content AND tier. + +## CX-3 — bugfix-685's parity became file-vs-itself (Claude concurring, as "minor") + +Correct, and a fair consequence of my mechanical repoint: mapping both sides +of a mirror pair to the skeleton leaves a comparison of a file with itself — +a test that can never fail, which is worse than no test (it *looks* like +coverage). + +**Fixed**: bugfix-685's target list collapsed to a single skeleton list and the +parity test was **removed** with a comment explaining why (no second tree +exists; drift of these prompts is now impossible by construction, and the +grep-regression assertions retain all real value). The same treatment was +applied to `baked-decisions.test.ts`'s Baked-Decisions parity describe — not +flagged by Codex, but it had the identical defect, and leaving it would have +been fixing the reported instance rather than the reported class. Suite count +drops accordingly (3,746 from 3,767): vacuous tests deleted, not skipped. + +Noted for the review doc: Spec 746's parity comment explicitly described the +skeleton-vs-codev drift ("skeleton has Multi-PR Workflow / Verify Phase +sections that codev/ doesn't … PRE-EXISTING and not Phase 1's responsibility") +— the drift this project fixed was *observed and consciously stepped around* +months ago. Detection was never the problem. + +## Status + +Full suite green: 3,746 passed, 0 failures. + + +### IMPORTANT: Stateful Review Context +This is NOT the first review iteration. Previous reviewers raised concerns and the builder has responded. +Before re-raising a previous concern: +1. Check if the builder has already addressed it in code +2. If the builder disputes a concern with evidence, verify the claim against actual project files before insisting +3. Do not re-raise concerns that have been explained as false positives with valid justification +4. Check package.json and config files for version numbers before flagging missing configuration diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-rebuttals.md new file mode 100644 index 000000000..8cae2dbc6 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-rebuttals.md @@ -0,0 +1,55 @@ +# Phase 4 — rebuttal for porch iteration 2 (covers manual review rounds 2–5) + +Porch's iteration counter and my manually-run review rounds diverged (I ran the +consults directly per porch's task instructions, producing iter2–iter5 files +within porch's single iteration-2 window). This file consolidates the record; +the full running detail is in `1252-phase_4-iter1-rebuttals.md`'s addenda. + +## Round 2 (files `*-iter2-*`): Gemini APPROVE / Codex REQUEST_CHANGES ×2 / Claude APPROVE + +1. **Preserved `release/protocol.md` still `cat`'d a deleted file** — accepted; + repointed to `codev-skeleton/`, and the M7 sweep's blind spot (codev/'s own + preserved content) recorded. +2. **`bugfix-742` parity became file-vs-itself** — accepted; the vacuous-parity + class I claimed fixed in round 1 had a missed instance. De-vacuized. + +## Round 3 (files `*-iter3-*`): Gemini APPROVE / Codex REQUEST_CHANGES ×2 / Claude APPROVE + +1. **Repointed tests validate source, not the served embedded skeleton** — + accepted with a different mechanism than suggested: new + `skeleton-embed-sync.test.ts` enforces bidirectional byte-parity at the one + copy boundary (source ↔ embedded), making source reads and resolver reads + identical by construction while source tests keep failing at the commit + surface. Single-owner pattern applied to the build boundary. +2. **Duplicate collapsed-mirror entries** — accepted; swept as a class: + deduped 744 / governance-sweep / protocol-prompt-audit and collapsed three + more vacuous pair loops inside baked-decisions. + +## Round 4 (files `*-iter4-*`): Gemini APPROVE / Codex REQUEST_CHANGES ×2 / Claude APPROVE + +1. **The spawn wrapper told builders to `Read codev/roles/builder.md`** — the + live catch of the phase: a hardcoded sentence at four `spawn.ts` call sites, + pointing at a deleted path (and always broken in fresh installs; #1011 + class — the role is harness-injected, never fetched). Fixed with a + single-owner `builderPreamble()` + tests asserting the preamble and the + full served prompt fetch nothing by literal framework path. +2. **Audit overstated the equivalence proof** — accepted; claim rewritten to + state exactly what is proven. + +## Round 5 (files `*-iter5-*`): Gemini APPROVE / Codex **COMMENT** (non-blocking) / Claude APPROVE + +- Codex's remaining nit: the preamble said the role copy "is written" to + `.builder-role.md`, which is false for `--no-role` spawns. **Fixed**: "with + default role injection, a copy is also written…". No open issues remain. + +## Final state + +- All shadow copies deleted; skeleton is the single owner; local-only files + preserved; `copyRoles`/`copyProtocols` gone. +- Equivalence proven at three layers: resolution tier (path-asserted), + assembly (nine protocols, byte-identical to pre-deletion snapshots), and + wrapper (no literal-path fetches). +- Embedded ↔ source skeleton sync mechanically enforced. +- Full suite: 3,728 passed, 0 failures. + +Nothing was disputed in any round. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-rebuttals.md new file mode 100644 index 000000000..c50b9338e --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-rebuttals.md @@ -0,0 +1,14 @@ +# Phase 4 — rebuttal, porch iteration 3 + +(Reviews for this round were pre-run; fixes are already committed. Full detail +in `1252-phase_4-iter2-rebuttals.md`.) + +Codex's two findings — source-vs-embedded skeleton validation gap and duplicate +collapsed-mirror entries — were both accepted and fixed in commit `94ed1ecb`'s +predecessors: `skeleton-embed-sync.test.ts` enforces bidirectional byte-parity +at the build-copy boundary (making source reads and resolver reads identical by +construction), and the duplicate/vacuous structures were swept as a class +(744, governance-sweep, protocol-prompt-audit, three pair loops in +baked-decisions). Subsequent rounds 4–5 reviewed those fixes; round 5 closed +with Gemini APPROVE / Codex COMMENT (non-blocking, fixed) / Claude APPROVE. +Nothing disputed. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-rebuttals.md new file mode 100644 index 000000000..d14454662 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-rebuttals.md @@ -0,0 +1,43 @@ +# Phase 5 — rebuttal to iteration-1 review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | (verdict pending at fix time) | — | — | — | + +## CX-1 — `includes()` cannot enforce byte-identical replication + +**Accepted, and the attack shape is worth naming**: an appended qualifier — +*"…stage each file explicitly by path, unless convenient."* — contains the +canonical substring and passes `includes()` while gutting the rule. My benign +parentheticals (relay-convention note, porch-context exception) were the same +mechanical shape as that attack, so the enforcement couldn't distinguish them. + +**Fixed with line-exactness**: some line on the surface must *be* the canonical +wording, allowing only a list prefix (`- `, `4. `) and bold markers. All +contextual notes moved to their own adjacent lines (4 porch skill copies, +CLAUDE/AGENTS afx-from-root exception, maintain.md's inline sentence). + +One consequence, documented in the registry rather than hidden: +`arch-critical.md` carries the status.yaml sentence inside its combined porch +fact, and the hot tier's ≤10-fact cap forbids splitting it onto its own line — +so arch-critical is deliberately **not** listed under `no-hand-edit-status`. +Its wording remains policed by the stale-variant sweep and the hot tier's own +MAINTAIN regime (Spec 987). (R1's arch-critical line is already line-exact and +stays listed.) + +## CX-2 — `maintain/protocol.md` carried the canonical but was unregistered + +**Accepted** — I converged its wording in the sweep and then failed to register +the file, exactly the "enforcement misses a surface" gap M5 exists to close. +Registered. + +## CX-3 — `git clean -f` vs the ratified `-fd` + +**Accepted.** The spec's ratified list says `git clean -fd`; my canonical wrote +`-f`. Phase 5 freezes the form, so the frozen form must match the ratification +byte-for-byte. Fixed in the registry and both root docs. + +Suite: 3,734 passed, 0 failures (manifest re-pinned for the one intentional +line-split in maintain.md). diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-context.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-context.md new file mode 100644 index 000000000..d044e56a1 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-context.md @@ -0,0 +1,58 @@ +### Iteration 1 Reviews +- gemini: APPROVE — Phase 5 scar-rule registry and compressed wordings are complete, tested, and fully aligned with Spec 1252 and Plan 1252. +- codex: REQUEST_CHANGES — Phase 5 is close, but the scar-rule registry/test still misses required canonical enforcement and omits at least one live surface from registry coverage. +- claude: APPROVE — Scar-rule registry is well-structured with all 8 D3-ratified rules compressed, deployed byte-identically across all declared surfaces, and protected by a comprehensive 6-test suite — meaning preservation verified, old banner blocks cleaned. + +### Builder Response to Iteration 1 +# Phase 5 — rebuttal to iteration-1 review + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | (verdict pending at fix time) | — | — | — | + +## CX-1 — `includes()` cannot enforce byte-identical replication + +**Accepted, and the attack shape is worth naming**: an appended qualifier — +*"…stage each file explicitly by path, unless convenient."* — contains the +canonical substring and passes `includes()` while gutting the rule. My benign +parentheticals (relay-convention note, porch-context exception) were the same +mechanical shape as that attack, so the enforcement couldn't distinguish them. + +**Fixed with line-exactness**: some line on the surface must *be* the canonical +wording, allowing only a list prefix (`- `, `4. `) and bold markers. All +contextual notes moved to their own adjacent lines (4 porch skill copies, +CLAUDE/AGENTS afx-from-root exception, maintain.md's inline sentence). + +One consequence, documented in the registry rather than hidden: +`arch-critical.md` carries the status.yaml sentence inside its combined porch +fact, and the hot tier's ≤10-fact cap forbids splitting it onto its own line — +so arch-critical is deliberately **not** listed under `no-hand-edit-status`. +Its wording remains policed by the stale-variant sweep and the hot tier's own +MAINTAIN regime (Spec 987). (R1's arch-critical line is already line-exact and +stays listed.) + +## CX-2 — `maintain/protocol.md` carried the canonical but was unregistered + +**Accepted** — I converged its wording in the sweep and then failed to register +the file, exactly the "enforcement misses a surface" gap M5 exists to close. +Registered. + +## CX-3 — `git clean -f` vs the ratified `-fd` + +**Accepted.** The spec's ratified list says `git clean -fd`; my canonical wrote +`-f`. Phase 5 freezes the form, so the frozen form must match the ratification +byte-for-byte. Fixed in the registry and both root docs. + +Suite: 3,734 passed, 0 failures (manifest re-pinned for the one intentional +line-split in maintain.md). + + +### IMPORTANT: Stateful Review Context +This is NOT the first review iteration. Previous reviewers raised concerns and the builder has responded. +Before re-raising a previous concern: +1. Check if the builder has already addressed it in code +2. If the builder disputes a concern with evidence, verify the claim against actual project files before insisting +3. Do not re-raise concerns that have been explained as false positives with valid justification +4. Check package.json and config files for version numbers before flagging missing configuration diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-rebuttals.md new file mode 100644 index 000000000..2ebe2875e --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-rebuttals.md @@ -0,0 +1,30 @@ +# Phase 5 — rebuttal, iteration 2 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-A — architect.md contradicted its own scar rule on the same surface + +Accepted, and a genuine meaning-preservation catch: rule 4 (canonical +afx-from-root) sat directly above point 5's "All CLI tools (`afx`, `porch`, +`consult`, `codev`) … work from any directory." The tension predates this +project, but compression made it sharp. Fixed: point 5 now reads "`porch`, +`consult`, and `codev` are global commands that work from any directory +(`afx` is the exception — rule 4)." + +## CX-B — human-gates rule unconverged on eight builder-prompts + +Accepted. The old variant ("NEVER call `porch approve` without explicit human +approval — only run it after the architect says to") survived in all eight +skeleton builder-prompts, unregistered. My Phase-5 sweep grepped for +`auto-approve`/`only humans approve` phrasings and missed this one — the same +under-sweep failure mode as earlier phases, now on my own new rule. Converged +to the canonical + relay note on its own line, all eight files registered under +`human-gates`, and the old variant added to the stale-variant sweep so it can +never quietly return. + +Fixtures re-pinned as the explicit intentional-change act (manifest ×9, +snapshots ×9, baselines ×3). Full suite: 3,734 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-rebuttals.md new file mode 100644 index 000000000..7d58c37f8 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-rebuttals.md @@ -0,0 +1,26 @@ +# Phase 5 — rebuttal, iteration 3 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | APPROVE (iter-2, late) | 0 | — | 0 | + +## CX-1 — second "afx works from any directory" instance (architect.md:55) + +Accepted. Iter-2 fixed the instance at :247; this one at :55 said the same +thing in the CLI notes section and I did not sweep the whole file for the +contradiction class after fixing the flagged line. Fixed: the note now names +`consult`/`porch`/`codev` as work-from-anywhere and explicitly excepts `afx` +with a pointer to the scar rule. A repo-wide grep confirms no remaining +"afx works from any directory" claim. + +## CX-2 — the stale sweep couldn't catch that contradiction + +Accepted. Both contradiction phrasings added to the sweep, so any surface +re-asserting that `afx` works from anywhere fails T6 on registered surfaces. +The sweep remains a hardcoded list by design — it is a tripwire for known +regressions, not a semantic checker; genuinely novel contradictions remain +reviewer territory (as this round demonstrated the process working). + +Manifest re-pinned (×1). Full suite: 3,734 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter4-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter4-rebuttals.md new file mode 100644 index 000000000..a07032950 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter4-rebuttals.md @@ -0,0 +1,35 @@ +# Phase 5 — rebuttal, iteration 4 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | APPROVE | 0 | — | 0 | + +## CX-1/CX-2 — the "bypass checks" variant survived on 11 files; sweep blind to it + +Accepted. The flaky-test sections' "**DO NOT** edit `status.yaml` to bypass +checks" is the same prohibition in context clothing, and my convergence sweep +missed it because I grepped for the rule's phrasings, not the *act's* +phrasings. All 11 files converged to the canonical (the numbered-list prefix is +line-exact-compatible), the variant added to the stale sweep, and the newly +canonical-carrying files registered (spike builder-prompt — previously missing +from R5 entirely — plus porch/spir/aspir implement prompts). + +## CX-3 — arch-critical exclusion resolved by restructuring, not by defending the exception + +Accepted, with a better fix than either keeping or forcing the exception. The +hot tier's "Two trees … Mirror every framework change in BOTH" fact has been +**factually false since Phase 4** (there is no second tree to mirror for +protocols/roles). Rewriting it to the post-1252 truth — skeleton is the single +owner, drift fails CI — and folding the CLAUDE/AGENTS identity invariant into +it freed one slot under the ≤10-fact cap. The porch fact split, and the R5 +canonical now stands line-exact on its own fact line. arch-critical is +re-listed under `no-hand-edit-status`; the exclusion comment is gone. + +This pulls a sliver of Phase 8's C6 rewrite forward. Justified: Codex forced +the arch-critical structure question now, and the alternative was defending a +registry exception built on a stale fact. Caps verified: 10 facts, 33 lines. + +Fixtures re-pinned (manifest ×10, snapshots ×9, baselines ×3). +Full suite: 3,734 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-rebuttals.md new file mode 100644 index 000000000..d1a8b4058 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-rebuttals.md @@ -0,0 +1,54 @@ +# Phase 6 — rebuttal, iteration 1 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — extractor under-collected (case-sensitive pattern) + +Accepted, with Codex's exact example confirmed: lowercase "must stay compliant +with the protocol" was invisible to the extractor. Widened to case-insensitive +must/never/always/do-not/don't. Candidates rose 134 → **190**, surfacing four +new multi-file texts that the catch-all guard immediately flagged — including +three new instruction classes (`multi-pr-mechanics`, +`notify-architect-key-moments`, `soft-mode-protocol-compliance`; classes now +10) and one additional match route into `baked-decisions-handling`. The guard +doing its job on its first real widening is the machinery working as designed. + +## CX-2 — companion .md could drift silently from the YAML + +Accepted. The companion now carries a machine-readable parity marker +(``) asserted +against the LIVE extractor and map — plus an assertion that every class id +appears in the companion. Any boundary or map change now forces the human doc +to update or CI fails. + +## CX-3 — seeded-duplicate test didn't exercise the real guard + +Accepted — the test re-implemented the grouping locally instead of calling the +function under test. `checkCompleteness` was split into a thin loader plus +`computeCompleteness(map, candidates)`, and the seeded test now runs the REAL +function over a catch-all-only fixture map, asserting both seeds surface via +`multiFileViaCatchAll`. + +Counts: 190 = 37 mapped + 39 scar + 114 file-local; zero undispositioned; zero +multi-file via catch-all. Full suite: 3,745 passed, 0 failures. + +--- + +## Claude (COMMENT, arrived after the Codex fixes) — both points accepted + +1. **References data inaccuracies** — verified by grep before correcting + (reviewer claims are evidence, not ground truth — but both held): + `no-skip-3way-review` actually lives on spir/aspir/bugfix/experiment (my + list wrongly had pir/research); `no-skip-porch-checks` lives on 8 files, + not 9 — research lacks it. Both reference lists corrected against grep, + with the verification noted in the justifications so Phase 7 consumes + accurate data. +2. **Script-location deviation** — acknowledged and deliberate: the same + js-yaml/workspace-resolution constraint that moved the behavioural-metrics + logic into `src/lib/` (Phase 1, documented plan deviation) applies here; + the extractor is a tested library rather than a loose script. The plan's + Phase 6 text already anticipated this shape after the Phase 1 amendment. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-rebuttals.md new file mode 100644 index 000000000..136522474 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-rebuttals.md @@ -0,0 +1,32 @@ +# Phase 6 — rebuttal, iteration 2 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — T7's `references` exemption defeats single-owner enforcement + +Accepted, and it clarifies Phase 7's contract usefully: a well-formed +reference points at the owner **without reproducing the rule text**, so it +never trips the class pattern. Exempting `references` surfaces from the +pattern check therefore had it exactly backwards — a full restatement on a +referenced surface (the thing T7 exists to catch) would have passed. The +exemption is removed; automated non-scar classes now match on exactly the +owner. Consequence recorded for Phase 7: reference lines must be phrased so +they don't reproduce the pattern (or patterns chosen to match the full form +only) — the enforcement now makes that a hard requirement rather than a style +preference. + +## CX-2 — missing boundary/surface files skipped silently + +Accepted — a fail-fast violation on my part. A typo'd, renamed, or deleted +boundary file would have quietly shrunk the scan while T12 stayed green, +which is precisely the completeness guarantee M1 exists to give. Fixed twice +over: `extractCandidates` now throws loudly on any missing boundary file +(with a message naming the fix), and `validateMap(map, root)` verifies every +boundary and surface path exists. A new test seeds a nonexistent boundary +entry and asserts the loud failure. + +Full suite: 3,746 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-rebuttals.md new file mode 100644 index 000000000..2ee20383d --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-rebuttals.md @@ -0,0 +1,46 @@ +# Phase 7 — rebuttal, iteration 1 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 3 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — "core deliverable incomplete: classes still manual/duplicated" + +Accepted in substance — rather than litigating that S1 is a SHOULD, the +completion pass finished the extractable remainder: + +- **5 more partials**: `flaky-test-handling` (uniform across + spir/aspir/bugfix/experiment; the scar canonical stays authored inline in + every file — no scar dedup), `porch-workflow-fidelity` (×3), + `no-skip-3way-review` (single line, **nested** inside the strict partial and + included directly by bugfix/experiment), `baked-decisions` (spir/aspir + uniform), `pr-strategy` (spir/aspir). +- **All 10 classes now `enforcement: automated`.** Remaining non-owner copies + are *declared* `retained_restatements`, each justified in the YAML — and + they are genuine protocol variants, not deferred work: AIR documents flaky + skips in the PR body because it has no review file; air's baked clause is + Spec 746's own per-protocol wording; pp-implement's flaky list is phrased + for the phase context; spir-protocol-doc restates rules as reference prose. +- **Test suites moved with the dedups in the same commit**: bugfix-744 now + greps the partial; Spec 746's suite operates on SERVED text + (`readRepoFile` include-expands, mirroring production) with baselines + re-derived from expanded content. + +## CX-2 — companion drifted from the YAML + +Accepted. The class table is now **generated from the YAML** (owner + +enforcement + refs/retained columns), and the parity test grew teeth: each +class's companion row must name its current owner and enforcement, so prose +can no longer describe a stale state while the marker stays numerically green. + +## CX-3 — after-artifact lacked the delta + +Accepted. `1252-word-after-phase7.md` now carries the required per-component +before/after/delta table and the achieved percentage: **21,856 → 20,324 = +−7.0%** (served words; the proxy expands includes recursively so +dedup-by-partial cannot claim phantom savings), with the structural +decomposition of the shortfall against the 20% target. + +Full suite: 3,742 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-rebuttals.md new file mode 100644 index 000000000..85ca274de --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-rebuttals.md @@ -0,0 +1,48 @@ +# Phase 7 — rebuttal, iteration 2 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 | 2 fixed, 1 partially disputed | see below | +| Claude | APPROVE | 0 | — | 0 | + +## CX-1 — "include model is centralization, not deduplication" — PARTIALLY DISPUTED + +The frame is disputed; the concrete defect inside it was real and is fixed. + +**Disputed part**: prose references on served surfaces were analyzed and +rejected in the Phase-7 design for a hard reason — builder/phase prompts are +SERVED artifacts. A bugfix builder never sees spir's prompt: removing a rule +from its prompt and pointing elsewhere **deletes the instruction from that +agent's context**; nothing is deduplicated from any reader's perspective. +Cross-protocol repetition on served surfaces is per-agent single delivery. +The single-owner rule's three costs are all addressed by the include model: +drift (one authored source), ambiguity (one wording), and token cost — which +per served prompt is *unchanged by either approach for content the agent must +receive*. Claude's independent verdict this round reached the same +conclusion. The YAML's own header prose still described the old +reference plan, which legitimately fed this objection — **fixed**: it now +documents the include model and when `references` (cross-tier pointers) apply. + +## CX-2 — served prompt carries a rule twice — ACCEPTED, real bug + +The genuine catch: I converged two different lines in the same file +(`plan.md`'s "No time estimates" list item AND its "What NOT to Do" bullet) to +the same include — spir and aspir plan phase prompts served the rule **twice**, +which is exactly the +70 phase-task words in the measurement. Fixed: one +include per file. This is within-one-served-artifact duplication — the real +S1 failure mode on the agent-facing surface — as distinct from cross-artifact +repetition, which is delivery. + +## CX-3 — no end-to-end guard on assembled output — ACCEPTED + +New **served-surface dedup guard**: for every automated non-scar class, the +pattern may appear at most `served_max` times (default 1) in (a) each of the +nine ASSEMBLED spawn prompts via the real `buildPromptFromTemplate`, and (b) +each expanded phase prompt. The guard caught the CX-2 bug on its first run, +then surfaced a legitimate ceiling: every spawn prompt carries the baked +instruction section plus the spir protocol doc's *description* of the +convention (a declared retention inlined via `protocol_reference`) — encoded +as an explicit, commented `served_max: 3`; a fourth appearance fails. + +Full suite: 3,744 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-rebuttals.md new file mode 100644 index 000000000..fc8255248 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-rebuttals.md @@ -0,0 +1,35 @@ +# Phase 7 — rebuttal, iteration 3 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | (iter-1 re-run raced the fixes; current-round verdict pending) | — | — | — | + +## CX-1 — partials excluded from the inventory boundary + +Accepted — a completeness hole of exactly the shape M1 exists to close: the +phase moved canonical text into `codev-skeleton/partials/` and then didn't +scan them, so new normative text added to a partial would have bypassed +extraction entirely. All ten partials are now in `inventory_boundary`; their +lines route through the existing class dispositions (169 candidates, zero +undispositioned, zero multi-file-via-catch-all). + +## CX-2 — cap-only guard lets a vanished rule pass (n=0) + +Accepted — the worst failure mode (a broken `{{> ...}}` silently deleting a +rule from served prompts) was exactly the one not covered. The guard now +asserts **presence derived from the include graph**: for each automated class +owned by a partial, every protocol whose builder-prompt reaches that partial +(directly or one nested level) must serve the pattern in at least one mode +render. Both modes are rendered because conditional blocks +(`{{#if mode_soft}}`) legitimately gate content per mode — presence holds over +the union, the over-serve cap per render. A broken include now fails with a +message naming the suspicion. + +Note on the Claude column: the iteration-1 re-run completed after this round's +fixes were already committed and reviewed a mid-fix snapshot (its two issues — +served-guard multiplicity and a stale manifest — were the very things fixed in +iteration 2). The current-round Claude verdict is in flight against HEAD. + +Full suite: 3,744 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter4-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter4-rebuttals.md new file mode 100644 index 000000000..7ab2c171d --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter4-rebuttals.md @@ -0,0 +1,57 @@ +# Phase 7 — rebuttal, iteration 4 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 1 completed further, 1 firmly rebutted | see below | +| Claude | APPROVE (iter-3) | 0 | — | 0 | + +## CX-1 — "retained_restatements preserves full non-owner restatements" + +**Half completed further, half rebutted with evidence.** + +**Completed**: the flaky-handling variants Codex cited (air, maintain, pir, +spike, pp-implement) differed from the shared block in exactly ONE line — the +documentation target ("PR body" / "maintenance run file" / "findings" / +"review file"). That difference is incidental, not semantic, so it was +**harmonized** to protocol-neutral wording ("the artifact where your protocol +records outcomes (review file, PR body, findings, or maintenance-run file)") +and all nine protocol prompts plus the porch implement prompt now share the +single partial. **Zero retentions remain for `no-skip-porch-checks`.** + +**Rebutted — the remaining retentions are decisions, not debt**, and each is +individually defended: + +- `bp-air` baked clause + the two drafting-prompt clauses: **Spec 746 + deliberately authored per-context wordings** (builder vs specify vs + implement clauses differ in what they forbid — "override in spec/plan" vs + "substitute languages during implementation") and its test suite asserts + each wording per file. Collapsing them changes reviewed 746 behaviour and + is out of this spec's scope (Non-goal: "not rewriting protocol semantics"). +- `spir-protocol-doc` (no-time-estimates, baked description): an **on-demand + reference document describing conventions** is not a served restatement; the + spec's single-owner rule targets instruction surfaces, and the doc is the + anchor the instruction points AT. +- `bp-air`/`bp-bugfix` notification templates: **materially different + content** (issue-number message formats, no gate notifications — AIR/BUGFIX + have no gates). Sharing a partial would serve wrong instructions. + +The remaining-retention count after this round: **3 classes carry retentions, +all 746-coordination or reference-doc anchors.** The spec's own machinery +(M11/TS3) established that declared, justified retention is a legitimate +terminal state — the alternative reading, that S1 requires eliminating every +protocol-specific variant, would mandate semantic rewrites the spec forbids. + +## CX-2 — "T7 checks owner + anything allowlisted, weaker than the plan" + +Rebutted as stated, with the sharpening accepted: an allowlist that requires a +per-class justification, appears in a reviewed YAML, is documented in the +companion table, and shrinks (5 retention entries removed this round) is not +"anything allowlisted" — it is the M11/TS3 pattern applied at class level. +T7's job is preventing SILENT restatements; `retained_restatements` makes the +remaining ones loud, enumerated, and justified. The plan's one-line criterion +predates the discovery that some "duplicates" are protocol-variant content; +the YAML records that discovery instead of papering over it. + +Suite: 3,744 green. Candidates 164 (variants left boundary files for the +shared partial); zero undispositioned; zero multi-via-catch-all. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-rebuttals.md new file mode 100644 index 000000000..dc5d87ce9 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-rebuttals.md @@ -0,0 +1,35 @@ +# Phase 8 — rebuttal, iteration 1 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 3 (one class) | all | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1/2/3 — stale deleted-path references in arch.md deep sections + one CLAUDE.md line + +Accepted as one class: my Phase-8 sync rewrote the sections I knew about +(Dual Nature, Invariants) and missed arch.md's deep references (Quick Start +pointers, per-protocol section headers, the roles Location line, consultant +resolution order) plus CLAUDE.md's "Protocol details" quick-reference line. +Codex is also right that this made arch.md internally inconsistent — worse +than uniformly stale. + +Fixed by sweep, not by cited-line: every `codev/protocols|roles` reference in +arch.md and CLAUDE/AGENTS was enumerated and either repointed at +`codev-skeleton/` (the single owner), annotated as the resolver's now-empty +tier-2 slot, or left standing where it correctly *describes* the resolution +doctrine (CLAUDE.md's File Resolution section — those lines are more true +post-1252 than before). N3 byte-identity maintained. + +Suite: 3,744 green. + +--- + +## Claude (COMMENT, late) — accepted + +The Directory Structure tree in CLAUDE.md/AGENTS.md still drew the deleted +protocol subdirectories (spir/experiment/maintain under `codev/protocols/`). +Fixed: the tree now shows `codev/protocols/` as local-only (release/) with the +framework-resolution note. Same class as Codex's sweep — a diagram is a +reference too. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-rebuttals.md new file mode 100644 index 000000000..a6714ebb7 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-rebuttals.md @@ -0,0 +1,25 @@ +# Phase 8 — rebuttal, iteration 2 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 1 substantive + 1 sandbox note | 1 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — arch docs vs the worktree scar rule + +Accepted, with the underlying semantics worth stating: the two texts were in +*tension*, not true contradiction — `afx cleanup` is the sanctioned, +architect-driven retirement of a **finished** builder, while the scar rule +forbids `afx cleanup` + respawn as a way to bulldoze a **live** worktree. But +an always-on surface carrying "never delete manually (use afx cleanup)" next +to a scar rule reading "never destroy … `afx cleanup` + respawn" forces every +reader to reconstruct that distinction. Both lines now carry it explicitly +(arch-critical fact and arch.md's Worktree Integrity invariant): cleanup +retires finished builders; live ones are resumed, never bulldozed. Hot caps +verified after the edit: 10 facts, 33 lines. + +## CX-2 — reviewer sandbox couldn't run Vitest (EPERM) + +Noted for the record; not an implementation issue. Full suite on the branch: +3,744 passed, 0 failures. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-rebuttals.md new file mode 100644 index 000000000..c422ecd96 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-rebuttals.md @@ -0,0 +1,15 @@ +# Phase 8 — rebuttal, iteration 3 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 1 | 1 | 0 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — filed issues not durably linked from the spec + +Accepted — the issues were filed (#1276 tiering / #1277 A/B eval) but their +numbers lived only in the builder thread, while the plan explicitly requires +the spec's Non-goals to carry the pointers. Both Non-goals bullets now name +their issues. (The verify phase and the review doc will reference them as +well.) diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter4-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter4-rebuttals.md new file mode 100644 index 000000000..5bf520a7e --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter4-rebuttals.md @@ -0,0 +1,25 @@ +# Phase 8 — rebuttal, iteration 4 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 2 | 0 | +| Claude | APPROVE (iter-2, late) | 0 | — | 0 | + +## CX-1 — Important Notes still instructed fetch-by-path + +Accepted, and an ironic one: my Phase-8 repointing turned "check +codev/protocols/spir/protocol.md" into "check codev-skeleton/..." — fixing the +dangling path while preserving the *fetch instruction*, which is the #1011 bug +class the project itself polices. Rewritten to delivery language: protocol text +arrives inlined in every spawn prompt, templates arrive in porch phase tasks; +the skeleton path remains as an orientation reference only. + +## CX-2 — glossary's Skeleton entry said "copied to projects on init/adopt" + +Accepted — stale since #1012 and directly contradicting arch-critical fact #1 +after this project. Now describes the skeleton as the framework source tree, +embedded at build time, served as the resolver's tier-4 runtime fallback, with +init/adopt copying only root docs, skills, and tier starters. + +Suite: 3,744 green. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter1-rebuttals.md new file mode 100644 index 000000000..0afa0b419 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter1-rebuttals.md @@ -0,0 +1,162 @@ +# Plan 1252 — Rebuttal to iteration-1 plan review + +| Model | Verdict | Confidence | Issues | Accepted | Disputed | +|---|---|---|---|---|---| +| Gemini | **APPROVE** | HIGH | 0 | — | 0 | +| Codex | **REQUEST_CHANGES** | HIGH | 3 | 3 | 0 | +| Claude | **APPROVE** | HIGH | 0 blocking (3 minor) | 3 | 0 | + +**I dispute nothing.** Codex's first two are genuine under-deliveries against +criteria I wrote myself; the third is a factual error I should not have made. + +Notably, all three reviewers verified the plan's technical claims directly +against the tree, and Codex's third point is the only claim that failed — which +is a useful signal about where my errors cluster: not in analysis, but in +restating details I had verified *earlier* and then paraphrased from memory. + +--- + +## Codex (REQUEST_CHANGES) — all three accepted + +### CX-1 — "M10 is not fully covered in Phase 4" + +> *The spec requires post-deletion resolver equivalence **and** that the +> assembled spawn prompt is byte-identical to the skeleton-sourced expectation. +> Phase 4 currently plans only per-file `resolveCodevFile` equivalence; Phase 8's +> T13 checks prompt contents/presence, not byte-identical assembled output.* + +**Accepted — the sharpest of the three.** M10 as I wrote it in the spec has two +clauses, and the plan implemented one. Worse, the gap was disguised: Phase 8's +T13 *looks* like it covers assembled prompts, so a reader could reasonably +conclude M10 was satisfied across two phases when neither actually asserted +byte-identity. + +The distinction matters more than it first appears. **Per-file resolution can be +correct while assembly still differs** — template ordering, `{{project_id}}` +interpolation, or a fragment picked up from a different resolver tier would all +pass the per-file check and still change what a builder receives. The entire +claim of Phase 4 is that deletion is a *no-op for what agents actually see*, and +only byte-identity demonstrates that. + +**Changed** — Step 4d now ships both halves: + +- **(i)** per-file `resolveCodevFile` equivalence (as before); +- **(ii)** assembled-prompt byte-equivalence: snapshot each protocol's spawn + prompt on the pre-deletion tree, commit the snapshots as fixtures, assert + post-deletion assembly is byte-identical. + +I also stated why (ii) is not redundant with Phase 8's T13: **T13 asserts +content presence after compression and dedup have deliberately changed the +text; Step 4d(ii) asserts nothing changed at all.** Different phases, opposite +expectations — worth writing down so a later reader doesn't collapse them. + +### CX-2 — "Phase 5 vs Phase 8 ownership of CLAUDE.md/AGENTS.md is blurry" + +> *Phase 5 says canonical scar strings are replaced on every required surface, +> which should include CLAUDE.md/AGENTS.md if they are in `must_appear_on`; +> Phase 8 then says to apply Phase 5's compressed scar wordings there. Right now +> the phase boundaries imply M5 is delivered before all surfaces are actually +> updated.* + +**Accepted.** Both statements were in the plan and they contradict each other. +Read one way, Phase 5 finishes the job and Phase 8 redundantly repeats it; read +the other, Phase 5 skips the two most important surfaces and still claims M5. +The second reading is the dangerous one, because **M5's whole purpose is to be +green before Phase 7 starts stripping text** — if CLAUDE.md and AGENTS.md were +still un-rewritten at that point, the protection would have a hole exactly where +the most-read scar rules live. + +**Changed** — the boundary is now explicit in both places: + +- **Phase 5 owns every scar-wording edit, on every surface, no exceptions** — + including CLAUDE.md and AGENTS.md, with the N3 byte-identical pair invariant + maintained *within* Phase 5. +- **Phase 8 does not re-apply scar wordings.** It parity-checks N3 and lands the + separate Phase 7 dedup edits. + +### CX-3 — "`scaffold.test.ts` has `copyRoles` coverage and no `copyProtocols` cases" + +**Accepted — my error, and one I had already disproved.** During the spec phase I +grepped for callers and recorded in the iteration-1 spec rebuttal that +"`copyProtocols` has no references at all outside its definition." Then I wrote +the plan and paraphrased it as "plus their `scaffold.test.ts` cases," implying +both had coverage. + +Not consequential on its own — a builder would discover it in seconds — but it +is precisely the failure mode this project exists to fix, in miniature: a fact +verified once, restated from memory later, and drifting in the restatement. + +**Changed** — the plan now names the exact scope: the `copyRoles` describe block +(~`scaffold.test.ts:156–195`) is removed; `copyProtocols` has no test cases. + +--- + +## Claude (APPROVE) — three minor points, all accepted + +### CL-1 — Phase 2's audit document must be machine-parseable for T11 + +> *T11 validates row counts and classifications. The plan shows a markdown table +> but doesn't state it must be parseable. A builder who writes free-form prose +> would make T11 unfeasible.* + +**Accepted**, and worth more than "minor." I specified a test that parses a +document and then described the document loosely. A builder following the plan +literally could produce something T11 cannot read, and the natural fix under +deadline pressure would be to weaken T11 — quietly removing the guarantee that +no shadow copy was deleted unaudited, which is the single most important +safeguard in this plan. + +**Changed** — the table is now specified as a fixed five-column pipe table, one +row per file, with `Classification ∈ {rot, local-unique}` and +`Terminal state ∈ {TS1, TS2, TS3, TS4, pending}`. Narrative commentary goes +below the table, never inside it. + +### CL-2 — Phase 7's reference format unspecified + +**Accepted.** "Replace with a one-line reference" left the actual shape to the +implementer. + +**Changed** — an example is given, plus the reasoning behind the choice: a +**prose** reference (`> Plans contain no time estimates — see +\`spir/protocol.md\` § Plan.`) rather than a machine pointer, because the +consumer is a model reading the assembled prompt and it must be able to act on +the reference *without* resolving it. The per-class string is recorded in the +map's `references` field so T7 can verify placement. + +### CL-3 — `.mjs` breaks the TypeScript convention + +**Accepted.** → `scripts/extract-instruction-candidates.ts`. + +--- + +## Gemini (APPROVE) + +No issues raised. Two things worth recording because they were discretionary +calls of mine rather than spec requirements, and both survived outside scrutiny: + +- **Phase 5 placement** (scar compression *after* shadow-tree removal). Gemini + reviewed the rationale explicitly and confirmed it "satisfies all spec safety + invariants." +- **`M11 → M3 → M8`** ordering confirmed as respected. + +--- + +## Summary of changes + +| Change | Driver | +|---|---| +| Step 4d gains assembled-prompt byte-equivalence with pre-deletion snapshots | CX-1 | +| Stated why 4d(ii) differs from T13 (nothing-changed vs content-present) | CX-1 | +| Phase 5 owns all scar edits incl. CLAUDE.md/AGENTS.md; Phase 8 parity-checks only | CX-2 | +| Scaffold test scope corrected to `copyRoles` only | CX-3 | +| Phase 2 audit table specified as machine-parseable with enumerated values | CL-1 | +| Phase 7 reference format + rationale | CL-2 | +| `.ts` instead of `.mjs` | CL-3 | + +## Status + +Plan updated and committed. Proceeding to the `plan-approval` gate. + +Nothing in this round changed the phase structure, ordering, or scope — all six +points were about specifying existing phases more precisely. The eight phases, +their dependencies, and the B → A → C sequencing stand as approved at spec time. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter2-rebuttals.md new file mode 100644 index 000000000..0471d9cb3 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-plan-iter2-rebuttals.md @@ -0,0 +1,149 @@ +# Delta review rebuttal — behavioural-measurement amendment (D5 / M12) + +Scoped review of the D5 amendment only: spec M12 (a/b/c), Appendix D, D5, T14, +plan Step 1b, plan Verify Phase. + +| Model | Verdict | Confidence | Issues | Accepted | Disputed | +|---|---|---|---|---|---| +| Gemini | **APPROVE** | HIGH | 0 | — | 0 | +| Codex | **REQUEST_CHANGES** | HIGH | 2 | 2 | 0 | +| Claude | **APPROVE** | HIGH | 0 | — | 0 | + +**I dispute nothing.** Both of Codex's findings are genuine defects in material +I wrote, and one of them made a metric literally unmeasurable. + +**On the split verdict**: Gemini and Claude both verified the *data-availability* +claims (which were correct) and approved. Codex went further and checked whether +the *metric definitions* actually resolve against the data — which is where both +defects were. Two APPROVEs did not make the amendment sound, and the majority +was not the signal worth trusting here. + +--- + +## Codex (REQUEST_CHANGES) — both accepted + +### CX-1 — "B2 is not derivable as specified" + +> *B2 says "rounds to unanimous approve," yet in real SPIR data the terminal +> phase verdict is **never** 3× `APPROVE` (0/48 plan phases across the +> 17-project SPIR baseline).* + +**Accepted, and independently verified before acting on it.** I re-derived the +figure rather than taking the claim on trust: + +``` +terminal plan-phases with verdicts: 48 +unanimous APPROVE: 0 + + 20 (APPROVE, APPROVE, REQUEST_CHANGES) + 12 (APPROVE, REQUEST_CHANGES, REQUEST_CHANGES) + 7 (REQUEST_CHANGES, REQUEST_CHANGES, REQUEST_CHANGES) + 5 (APPROVE, COMMENT, REQUEST_CHANGES) + … +``` + +Codex is exactly right. **Porch advances a plan phase after the builder rebuts, +not on consensus** — so a "rounds to unanimity" counter would never resolve, and +B2 would have been a metric that silently never fired. Worse, it would have +*looked* fine: the script would run, emit a number, and that number would be +meaningless. + +This is a nice illustration of the difference between "the data exists" and "the +metric resolves." I verified the former carefully (Appendix D §1–2, which all +three reviewers confirmed) and then failed to check the latter for my own metric +definition. + +**Changed:** + +- **B2 redefined** as *review rounds per plan phase* = `max(iteration)` per + `plan_phase`. Directly derivable, and it measures the friction the metric was + reaching for. +- **Measured baselines added to Appendix D**, so the spec now publishes real + numbers rather than a promise to produce them: + + | Metric | Baseline | + |---|---| + | B1 `REQUEST_CHANGES` rate | **51.9%** (n=160; APPROVE 41.2%, COMMENT 6.9%) | + | B2 rounds per plan phase | mean **1.12**, median 1, max 2 (n=49) | + | B4 rounds per project | mean **3.06**, median 3 (n=18) | + +- **Weighting corrected as a consequence.** Computing the baselines exposed + something the original draft implied but the data does not support: **B2's + observed range is 1–2 with mean 1.12** — almost no variance, so it cannot + detect a subtle regression. B2 and B4 are now explicitly **advisory**, and + **B1 is named the load-bearing metric**. It was already the soft trigger's + basis; now it is labelled as such and the threshold is concrete: >25% relative + on 51.9% means **above ~64.9%**. + +The redefinition also made the empirical finding worth recording in its own +right — *phases advance on rebuttal, not unanimity* — since anyone later reading +the CMAP verdict data will otherwise expect unanimity and find none. + +### CX-2 — "B5/T14 must be reconciled" + +> *A rolling machine-local `consult stats` snapshot is not a committed-artifact +> metric and cannot satisfy T14's deterministic "same commit ⇒ same B1–B5 +> numbers" requirement.* + +**Accepted — a straightforward self-contradiction, both halves written by me in +the same amendment.** Appendix D §2 correctly labels B5 prospective-only and +machine-local; T14 then demanded determinism across B1–**B5**. Both cannot hold. + +**Changed:** + +- **T14's determinism assertion is scoped to B1–B4** (the committed-artifact + metrics). +- **B5 is explicitly excluded** from that assertion, labelled *advisory and + non-deterministic*, and confirmed to drive **no rollback trigger**. It was + already absent from the hard and soft trigger rows; it is now named in the + advisory row so the exclusion is deliberate rather than incidental. + +Worth stating why B5 is kept at all rather than dropped: cost and duration per +phase are genuinely useful context when interpreting a B1 movement, even though +they cannot support a causal claim. Keeping it labelled is better than losing +the signal — the failure mode was pretending it was reproducible. + +--- + +## Gemini (APPROVE) and Claude (APPROVE) + +Both verified the data-availability claims against the repo and confirmed no +usable source was missed: + +- Gate-rejection counts unminable — no `rejected` state; `requested_at` + overwritten on re-request. +- Consult token/cost prospective-only — logs gitignored at `.gitignore:59`; + `consult stats` backed by a local 30-day SQLite DB. +- `history[].reviews[].verdict` present for 17 SPIR projects only. + +Gemini specifically endorsed the **n = 1 hard trigger on B3**, reasoning that +scar rules exist *because* the catastrophic failure already occurred once, so a +single verified recurrence is sufficient grounds to revert compression. That +matches the intent and is worth recording, since a single-incident trigger looks +aggressive without that justification. + +Both also confirmed rollback targeting (trims revertible, repairs not), baseline +sequencing (Phase 1, before any content-altering phase), and that the +add/remove confound is *acknowledged rather than solved* — acceptable only +because the spec downgrades its claim to total-effect observation. + +--- + +## Summary of changes + +| Change | Driver | +|---|---| +| B2 redefined: rounds per plan phase, not rounds-to-unanimity | CX-1 | +| Empirical note: 0/48 terminal phases unanimous; phases advance on rebuttal | CX-1 | +| Measured baselines published in Appendix D (B1 51.9%, B2 1.12, B4 3.06) | CX-1 (+ builder) | +| B2/B4 demoted to advisory; B1 named load-bearing; soft threshold made concrete (~64.9%) | builder, from the measured data | +| T14 determinism scoped to B1–B4 | CX-2 | +| B5 labelled advisory/non-deterministic, excluded from triggers | CX-2 | +| Plan Step 1b updated with the reproduction targets | CX-1, CX-2 | + +## Status + +Amendment complete. Spec and plan updated and committed. + +Returning to the **`plan-approval`** gate for the architect to re-approve the +spec delta and the plan together, per the directive. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-review-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-review-iter1-rebuttals.md new file mode 100644 index 000000000..052e1d015 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-review-iter1-rebuttals.md @@ -0,0 +1,35 @@ +# PR review — rebuttal, iteration 1 + +| Model | Verdict | Issues | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 | — | 0 | +| Codex | REQUEST_CHANGES | 2 | 1 | 1 | +| Claude | (pending at fix time) | — | — | — | + +## CX-1 — spec/plan missing approval frontmatter — ACCEPTED + +Both artifacts passed their human gates (spec-approval 2026-07-27, +plan-approval 2026-07-28 jointly with the D5 delta) but still read +`Status: draft` with no frontmatter. Fixed: both now carry the repo's +standard `approved:` / `validated: [gemini, codex, claude]` frontmatter and +approved status lines naming their gates. + +## CX-2 — "54 commits do not match [Spec 1252] format" — DISPUTED (false positive by repo precedent) + +The non-conforming commits are **porch-generated state-transition commits** +(`chore(porch): 1252 `), written by the orchestrator itself when it +records gate requests/approvals and phase transitions in `status.yaml`. +Evidence that this is the repo's established convention — `main`'s own recent +history: + +``` +151ff076 chore(porch): bugfix-1264 pr gate-approved +b775f02f chore(porch): bugfix-1261 pr gate-approved +cf430e1b chore(porch): bugfix-1264 init bugfix +``` + +Every builder-authored commit on this branch follows +`[Spec 1252][Phase: …]` / `[Spec 1252] …`. Rewriting porch's commits would +require rebasing a pushed, in-review branch and would diverge from every +previously merged porch-driven project. The repo also merges with regular +merge commits (never squash), so the mixed history is the intended record. diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter1-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter1-rebuttals.md new file mode 100644 index 000000000..8d69f58a6 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter1-rebuttals.md @@ -0,0 +1,288 @@ +# Spec 1252 — Rebuttal to iteration-1 review feedback + +| Model | Verdict | Issues raised | Accepted | Disputed | +|---|---|---|---|---| +| Gemini | APPROVE | 0 (2 plan-phase suggestions) | 2 | 0 | +| Codex | REQUEST_CHANGES | 5 | 5 | 0 | +| Claude | COMMENT | 4 | 4 | 0 | + +**I dispute nothing.** All nine issues were valid. Two corrected factual errors +of mine, and one (Claude's #1) materially reduced the scope of the work. Every +change below is committed in `c58aff65`. + +Where I extended beyond what a reviewer asked, I say so explicitly, because +those additions are mine to defend rather than theirs. + +--- + +## Codex (REQUEST_CHANGES) — all five accepted + +### C-1 — "Critical scope-defining decisions unresolved (Q1, Q2)" + +> *A spec should not make its primary end state depend on unanswered critical +> questions.* + +**Accepted.** This was the right call and the most structurally important of +Codex's points. Iteration 1 recommended deletion as the headline path while +simultaneously admitting deletion required architect permission it did not +have — so the spec's end state was undefined until someone answered Q1. + +**Changed**: Success Criteria split into two blocks. + +- **Required (M1–M7)** — hold regardless of how Q1 and Q2 are answered. +- **Conditional (M8–M10)** — shadow-tree deletion, vestigial-scaffold cleanup, + and post-deletion equivalence, active only on an affirmative Q1. + +A "no" on Q1 now drops M8–M10 and still ships a complete, valuable result +(drift permanently gated + ownership map + deduplication). Q1 and Q2 remain +listed as Critical because they *are* architect decisions, but they no longer +gate the deliverable. Stated explicitly at the end of **Recommended +sequencing**. + +### C-2 — "M2 is ambiguous/test-hostile — two incompatible outcomes" + +**Accepted.** Iteration 1's M2 read "either the shadow trees are removed, or a +test fails on any divergence," which is untestable as written — a test cannot +assert a disjunction of two different world states. + +**Changed**: M2 is now exactly one thing — *drift cannot pass CI*. Deletion +moved wholesale to M8. M2 is satisfied by a gate that fails on any `differs` +finding outside a justified allowlist, whether or not deletion ever happens. + +### C-3 — "M4 is under-specified" + +> *"instruction class" and "machine-checkable" are not defined tightly enough +> for a builder to implement a reliable test.* + +**Accepted.** Fair — I used both terms without defining either. + +**Changed**: added **Appendix A**, which defines an instruction class ("a single +normative rule an agent is expected to follow, identified by a stable `id` and +detectable by `pattern`"; descriptive prose explicitly excluded) and gives the +concrete YAML schema for `codev/resources/prompt-ownership.yaml` with a worked +example. `enforcement` is now an explicit per-class field with two values: +`automated` (M4/T7 assert it) and `manual` (recorded for humans, not asserted, +and each use must be justified in the plan). M4 also now requires the test to +**derive** assertions from the map rather than restate them — otherwise the +enforcement mechanism would itself violate the single-owner rule. + +### C-4 — "Approach A feasibility is not yet bounded enough" + +> *Direct repo reads show many literal `codev/protocols/` / `codev/roles/` +> references across docs, tests, scaffolding, and spawn code.* + +**Accepted, and verified rather than assumed.** Codex's count is right: 26 +non-test and 95 test references in `packages/*/src`. + +**Changed**: Q5 promoted from a nice-to-know question to **M7**, a first-class +required deliverable (Codex's own option (b)), plus **Appendix B** recording the +preliminary audit. + +**One qualification, offered as evidence rather than disagreement.** Codex +inferred feasibility risk from reference *count*. Classifying the references +changes the conclusion: every production consumer routes through the resolver +and so falls through to the skeleton — + +- `consult/index.ts:175` → `readCodevFile(...)` +- `porch/protocol.ts` → `resolveCodevFile` / `getSkeletonDir` + +— and the remainder are doc comments, an error-message string +(`porch/protocol.ts:28`), and the vestigial writers in `scaffold.ts`. No +direct-read consumer exists. So deletion is **lower**-risk than iteration 1 +judged, not higher. I have still adopted Codex's remedy in full: M7 requires +the audit to be *completed* across tests and non-TypeScript consumers before +M8 executes. Appendix B is labelled preliminary for exactly that reason. + +**This investigation also produced the largest correction in the revision** — +see *Builder-originated corrections* below. + +### C-5 — "Model-capability tiering is too vague for implementation" + +> *The spec does not define the minimum supported selector, fallback behavior, +> or whether tiering is documentation-only versus runtime behavior.* + +**Accepted** — those are precisely the three unspecified axes. + +**Changed**: added **Appendix C**, fixing all three. + +- **Selector**: explicit `promptTier` key in `.codev/config.json`. Chosen over + model-string detection, which breaks on every new model id. +- **Fallback**: absent or unrecognized → `weak` (fuller scaffolding). Failing + toward *more* instruction is the safe direction: a strong model given extra + scaffolding wastes tokens; a weak model denied scaffolding produces wrong + work. +- **Scope**: documentation-only this iteration. The map records a `tier` per + surface; the selector and fallback are specified and tested; no runtime + prompt-assembly branching ships. Runtime tiering is a follow-up gated on Q4. +- Added: **scar rules are tier-invariant** — full text at every tier. Without + this, tiering would become a back door around C3. + +--- + +## Claude (COMMENT) — all four accepted + +### CL-1 — "`protocol-drift-audit` (#1210) not mentioned" *(Medium)* + +**Accepted. This is the most valuable finding of the review**, and it means +iteration 1 was about to have me build something that already exists. + +Verified directly: `packages/codev/src/lib/protocol-drift-audit.ts` (10,798 +bytes) exports `auditProtocolDrift()`, `hasFrameworkShadows()`, and +`FRAMEWORK_DRIFT_DIRS = ['protocols', 'consult-types', 'roles']`, classifying +each shadow copy `identical | differs`. `codev doctor` already calls it at +`doctor.ts:947`. A test suite exists at +`packages/codev/src/__tests__/protocol-drift-audit.test.ts`. + +Claude is also right that my wording was misleading. Iteration 1 said "no test +asserts that `codev/protocols/` matches `codev-skeleton/protocols/`." Drift *is* +detected and *is* reported; what is missing is that nothing **fails the build**. + +**Changed**: #1210 is now a named Dependency, listed first in the *Existing +enforcement machinery* table, and given its own subsection. The misleading claim +is corrected in place. M2 is rewritten from "write a parity test" to "wire the +existing audit into a CI gate with an adjudication allowlist" — a substantially +smaller and better-founded piece of work. T5 now also asserts the gate *bites* +(a seeded divergence must fail it), since a gate that reports without failing is +the exact condition that let this drift persist. + +I also sharpened the framing in **Notes**: our 17 drifted files were visible to +`codev doctor` all along and were ignored. The gap was never detection. + +### CL-2 — "'19 drifted files' appears to be 17" *(Low)* + +**Accepted — my error.** Recounted: + +``` +diff -rq codev/protocols codev-skeleton/protocols | grep -c '^Files' # 16 +diff -rq codev/roles codev-skeleton/roles | grep -c '^Files' # 1 +``` + +**17**, not 19. My 19 came from counting all `diff -rq` output lines, which +folded in three `Only in codev/...` entries — those are **local-only files, not +drift**. Claude identified the cause exactly. + +**Changed**: the figure is 17 throughout; **Terminology** now defines *drifted* +versus *local-only* as distinct categories, since Claude correctly notes the two +need different treatment under M8. The 16 drifted protocol files are enumerated +by name so the plan can work file-by-file, with the `.md` / `.json` split (11/5) +recorded. + +### CL-3 — "Local-only files in `codev/protocols/maintain/templates/` not called out" *(Low)* + +**Accepted.** A2 protected only `release/` and would have let +`audit-report.md` and `lessons-learned.md` be deleted. + +**Changed**: both files named in A2, in M8's preservation clause, and in the +Problem Statement. Added **T8**, a new test asserting all three local-only +entries still exist and still resolve after removal — closing the "missing test +scenario" Claude flagged separately. + +### CL-4 — "'63 markdown files' doesn't match 76 including `.json`" *(Low)* + +**Accepted.** Both numbers were right about different things; my label was +imprecise. Exact counts: + +| Scope | Count | +|---|---| +| `.md` in both `protocols/` trees | 63 | +| `.md` + `.json` in both `protocols/` trees | 73 | +| All shadow copies including `roles/` | **76** | + +Claude's 76 matches mine once `roles/` is included. + +**Changed**: all three stated explicitly; 45,183 words is now labelled as +markdown-only. + +### CL-5 — "'shadow tree' used in two senses" *(minor clarity)* + +**Accepted.** Added a **Terminology** section defining *skeleton*, *shadow +copy*, *shadow tree*, *drifted*, *local-only*, and *scar rule* once, with the +explicit note that "shadow tree" never refers to the skeleton. + +--- + +## Gemini (APPROVE) — both suggestions adopted + +- **G-1, machine-readable ownership map** — adopted. Q6 is resolved in favour of + YAML (**Appendix A**). Gemini and Codex converge here from opposite + directions: Gemini wants T7 to read the map directly; Codex wants the schema + pinned down. Both are satisfied by the same artifact. +- **G-2, grep audit before deletion** — adopted as **M7** + **Appendix B** + (same change as C-4). + +Gemini raised no key issues. I have not treated the APPROVE as license to skip +anything the other two raised. + +--- + +## Builder-originated corrections (not requested by any reviewer) + +Investigating C-4 turned up two things that changed the spec beyond what was +asked. Flagging them explicitly since no reviewer is accountable for them. + +### B-1 — Assumption A1 was speculative and is now evidence-backed + +Iteration 1's A1 asserted the shadow trees were "unintentional forks" on thin +evidence (a shared last-touch commit). + +Following the `scaffold.ts` references, I found `copyProtocols` (line 480) and +`copyRoles` (line 425), which copy the skeleton into `codev/`. My first reading +was alarming: if scaffolding creates the shadow tree, every adopter has this +problem. Then I grepped for callers — **neither function is called by `init`, +`adopt`, or `update`**; the only references are in `scaffold.test.ts`, and +`copyProtocols` has no references at all outside its definition. + +They are dead code. Two consequences: + +1. **Adopters have no shadow tree.** They resolve from the skeleton at tier 4, + exactly as `arch-critical.md` claims. Our shadow tree is a historical artifact + from when scaffolding did copy. This *strengthens* the deletion case: deleting + makes Codev match its own adopters. +2. **The dead functions are a live hazard** — rewiring them would manufacture + the problem for every project. Added **M9** to remove them alongside M8. + +This is the `lessons-critical.md` rule "*'Who calls this in production?' grep +before changing a long-lived API — vestigial code survives*" paying out +directly. + +### B-2 — A drift-audit allowlist is itself a risk + +Making M2 an allowlist-based gate creates a way to re-hide drift by appending to +the allowlist. Added to the risk table with the mitigation: entries require a +justification comment, the allowlist must be **empty** when M3 completes, and +any growth is visible in review diffs. + +--- + +## Summary of changes + +| Change | Driver | +|---|---| +| Success criteria split: required M1–M7 vs conditional M8–M10 | C-1 | +| M2 narrowed to a single testable outcome | C-2 | +| Appendix A — instruction-class definition + YAML schema | C-3, G-1, Q6 | +| M7 + Appendix B — compatibility audit | C-4, G-2, Q5 | +| Appendix C — tiering selector, fallback, scope; tier-invariant scar rules | C-5 | +| #1210 as dependency; M2 extends it; T5 asserts the gate bites | CL-1 | +| 17 drifted (not 19); drifted vs local-only separated; 16 files enumerated | CL-2 | +| Local-only files protected in A2/M8 + new T8 | CL-3 | +| Counts disambiguated: 63 / 73 / 76 | CL-4 | +| Terminology section | CL-5 | +| A1 rewritten with evidence; M9 added | B-1 | +| Allowlist-accretion risk | B-2 | + +Committed in `c58aff65`. + +## Still open for the architect + +Unchanged by this revision, and not the builder's to decide: + +- **Q1** — may the shadow copies be deleted (M8–M10)? Evidence supports yes; I + will not delete without explicit approval. +- **Q2** — for the 17 drifted files, which side wins? Default proposal: the + skeleton, with any file whose local copy carries content worth keeping + escalated rather than silently overwritten. +- **Q3** — is the scar-rule list complete? Ratification matters precisely + because the point of the list is that nothing on it is ever quietly dropped. +- **Q4** — is a config-key tiering selector right, and is documentation-only + tiering acceptable this iteration? diff --git a/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter2-rebuttals.md b/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter2-rebuttals.md new file mode 100644 index 000000000..333d644ee --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/1252-specify-iter2-rebuttals.md @@ -0,0 +1,197 @@ +# Spec 1252 — Rebuttal to iteration-2 review feedback + +Iteration-2 reviewed the spec as amended with architect decisions **D1–D4**. + +| Model | Verdict | Confidence | Issues | Accepted | Disputed | +|---|---|---|---|---|---| +| Gemini | **APPROVE** | HIGH | 0 (1 suggestion) | 1 | 0 | +| Codex | **REQUEST_CHANGES** | HIGH | 2 | 2 | 0 | +| Claude | **APPROVE** | HIGH | 0 blocking (3 minor) | 3 | 0 | + +**I dispute nothing.** Both of Codex's issues were real holes in criteria I +wrote, and one of them would have let the central deliverable pass its own tests +while being substantially incomplete. + +Round-over-round: iteration 1 drew 9 issues; iteration 2 drew 6, of which 2 were +blocking and 4 were presentational. The blocking pair are both *"your enforcement +mechanism has a hole,"* not *"your analysis is wrong"* — the empirical basis was +re-verified independently by both Codex and Claude and held up. + +--- + +## Codex (REQUEST_CHANGES) — both accepted + +### CX-1 — "Ownership-map completeness is not testably defined" + +> *M1 says the map gives every instruction class a single owner, but the spec +> does not define how the implementation proves the map is exhaustive rather +> than selectively listing a subset. M4 only validates entries that are already +> in the map.* + +**Accepted. This is the most valuable finding of the round**, and it exposes a +circularity I built into my own enforcement. + +M4/T7 iterate over the map's entries and check each has one owner. That is +trivially satisfiable: a map containing three instruction classes out of forty +passes cleanly. The tests would have been green, the artifact would have looked +rigorous, and the single-owner rule would have covered a fraction of the surface +with nothing anywhere signalling the gap. **The enforcement measured only what I +had already told it about** — precisely the failure mode this whole spec exists +to attack, reproduced inside the fix. + +**Changed** — M1 gains a completeness rule with four parts: + +- **Declared inventory boundary.** The map names the exact file set scanned for + candidates. Content outside it is out of scope *by declaration* rather than by + omission — the distinction that makes exhaustiveness checkable at all. +- **Mechanical candidate extraction** over that boundary, collecting normative + statements (`MUST`, `NEVER`, `ALWAYS`, `DO NOT`, `don't`, …), each with a + stable id. +- **Mandatory disposition**: every candidate is exactly one of `mapped`, `scar`, + or `out-of-scope` **with written justification**. There is no fourth state and + no silent omission. +- **T12** fails on any undispositioned candidate. Adopting Codex's own suggested + formulation nearly verbatim, since it was the right one. + +The durable benefit is that new normative text added anywhere inside the +boundary fails CI until dispositioned — so the map cannot rot as the prompt +surface grows, which is the same drift disease at the level of the fix. + +**One addition Codex did not ask for**: T12 must itself be validated against a +*seeded* normative line. A completeness test that runs against an empty +candidate set passes vacuously and looks identical to a healthy one. Having just +been caught by one vacuous-pass hole, adding another would be careless. + +### CX-2 — "The final state for escalated `local-unique` shadow files is under-specified" + +> *M11 correctly blocks overwrite/delete until architect review, but the spec +> does not clearly state whether this feature can still be considered complete +> if any shadow files remain after escalation. Define the permitted terminal +> states explicitly.* + +**Accepted.** I specified the escalation *trigger* and the *prohibition* +(nothing local-unique is destroyed pending a ruling) but never said what +happens afterwards. "Escalate to the architect" is a transition, not a +destination, and a criterion whose end state is undefined cannot be judged +complete or incomplete. + +**Changed** — M11 gains four explicit terminal states: + +| # | Terminal state | Applies to | Result | +|---|---|---|---| +| **TS1** | Reconciled to skeleton, then deleted | `rot` | Skeleton sole owner | +| **TS2** | Promoted — content moved *into* the skeleton, local copy deleted | `local-unique`, keep **and** share with adopters | Skeleton sole owner; functionality preserved for everyone | +| **TS3** | Retained as a deliberate documented local override | `local-unique`, keep **codev-only** | Stays in `codev/`, in the ownership map *and* the M2 allowlist | +| **TS4** | Dropped | `local-unique` judged obsolete | Deleted, ruling recorded | + +Plus three rules Codex's question implies: + +- **"Pending escalation" is explicitly NOT terminal.** Naming it as a + non-state is what makes the completion rule enforceable. +- **Completion rule**: all 76 shadow copies in TS1–TS4, **zero open + escalations**. So yes — every escalation resolves within this spec. +- **Escape hatch**: if a ruling genuinely cannot be obtained, the item converts + to **TS3** and a follow-up issue is filed. This is deliberate. Requiring + resolution with no escape would let one unanswered question block the whole + project indefinitely; TS3 is the conservative outcome (nothing is lost) and + guarantees a defined end state either way. + +I also flagged **TS2 as preferred** over TS3 for genuine codev-specific +functionality. TS3 knowingly re-creates a shadow copy — single, documented, +allowlisted, but still a shadow copy — and should stay exceptional, or the spec +quietly rebuilds the thing it removed. + +--- + +## Gemini (APPROVE) — suggestion adopted + +### G-1 — Adjudication allowlist lifecycle + +> *Ensuring the allowlist requires line-item justification comments and +> enforcing that it decays to empty after M3 completion (except for open M11 +> escalations) will prevent allowlist rot over time.* + +**Adopted.** I had logged allowlist accretion as a risk and written "empty at M3 +completion" as an *expectation*. Gemini is right that an expectation is not a +mechanism — the allowlist is the obvious way to re-hide drift, so its decay must +be enforced. + +**Changed** — M2 gains an explicit lifecycle: line-item justification comments +required; the test asserts the allowlist is **empty once M3 completes**; the +sole permitted residue is files with an open M11 escalation, each citing its +pending adjudication. An entry outliving its escalation fails the build. This +also ties M2 and M11 together, so an abandoned escalation cannot quietly become +a permanent exemption. + +Gemini also specifically endorsed the **M11 → M3 → M8** sequencing and the +scar-integrity chain (M5/T6 green before Approach C begins). Both were +builder-originated additions, so independent validation is worth recording. + +--- + +## Claude (APPROVE) — three minor points, all accepted + +### CL-1 — T11/T12 ordering non-sequential + +**Accepted.** I inserted T12 above T11 when adding the local-unique test. +Renumbered: **T11** local-unique audit, **T12** ownership-map completeness, +**T13** end-to-end. All cross-references corrected — the risk table (two rows) +and Approach C's mitigation line, which still pointed at T9 from an earlier +revision. + +### CL-2 — T11 should clarify automated-vs-manual expectation + +**Accepted**, and worth more than its "minor" label. + +**Changed** — now **T13**, split explicitly: + +- **(a) Automated, in CI**: assemble the spawn prompt in-process; assert the + verify-phase instructions and all eight compressed scar rules are present. +- **(b) Manual, once**: actually spawn a builder and read what it receives. + +The reason for keeping (b) despite (a): **part (a) can pass while the real spawn +path diverges** — an in-process assembly test and the live spawn can read +different files. That is exactly the failure that produced this project, where +the served builder prompt lost its Verify Phase section while everything else +looked fine. An ambiguous "inspect the prompt" instruction would likely have +collapsed into (a) alone. + +### CL-3 — Q7 should be required M1 coverage, not a trailing nice-to-know + +**Accepted.** Q7 asked whether `codev/resources/` joins the drift regime. The +answer is no — user-evolved files where divergence is legitimate, and +`FRAMEWORK_DRIFT_DIRS` already excludes `resources`. But Claude's point is that +an unrecorded correct default is indistinguishable from an oversight, and the +next person to touch `FRAMEWORK_DRIFT_DIRS` has nothing telling them the +exclusion is deliberate. + +**Changed** — Q7 moved out of nice-to-know and resolved into **M1**: recording +*why* `resources/` is excluded is now required map coverage, and M2's allowlist +must not accidentally cover those files. + +--- + +## Summary of changes + +| Change | Driver | +|---|---| +| M1 completeness rule — boundary, extraction, mandatory disposition | CX-1 | +| T12 ownership-map completeness, validated against a seeded line | CX-1 (+ builder) | +| M11 terminal states TS1–TS4; "pending" non-terminal; completion rule | CX-2 | +| M11 escape hatch — stalled escalation → TS3 + follow-up issue | CX-2 | +| M2 allowlist lifecycle enforced (justifications, decay, escalation-only residue) | G-1 | +| Tests renumbered T11/T12/T13; all cross-refs fixed | CL-1 | +| T13 split into automated (a) and manual (b), with rationale | CL-2 | +| Q7 resolved into required M1 coverage | CL-3 | +| Two risk rows: vacuous-map, stalled-escalation | CX-1, CX-2 | + +## Status + +No open questions remain. D1–D4 answered everything architect-owned; iteration-2 +feedback is fully absorbed. Returning to the `spec-approval` gate. + +The one judgement call worth the architect's eye is **M11's escape hatch**: I +chose "unresolved escalation → TS3 + follow-up issue" over "block until +answered." That trades a small amount of residual shadow tree for a guarantee +that the project cannot stall on an unanswered question. If you would rather it +hard-block, that is a one-line change. diff --git a/codev/projects/1252-prompt-architecture-single-own/status.yaml b/codev/projects/1252-prompt-architecture-single-own/status.yaml new file mode 100644 index 000000000..f5405e280 --- /dev/null +++ b/codev/projects/1252-prompt-architecture-single-own/status.yaml @@ -0,0 +1,312 @@ +id: '1252' +title: prompt-architecture-single-own +protocol: spir +phase: review +plan_phases: + - id: phase_1 + title: Drift gate + measurement baseline + status: complete + - id: phase_2 + title: Local-unique content audit (M11) + status: complete + - id: phase_3 + title: Reconcile the 17 drifted files (M3) + status: complete + - id: phase_4 + title: Compatibility audit + shadow-tree removal + status: complete + - id: phase_5 + title: Scar-rule registry with compressed wordings + status: complete + - id: phase_6 + title: Ownership map + completeness enforcement + status: complete + - id: phase_7 + title: Deduplication and measurement + status: complete + - id: phase_8 + title: Governance sync + end-to-end verification + status: complete +current_plan_phase: null +gates: + spec-approval: + status: approved + requested_at: '2026-07-27T07:35:18.389Z' + approved_at: '2026-07-27T12:54:53.738Z' + plan-approval: + status: approved + requested_at: '2026-07-27T13:07:15.544Z' + approved_at: '2026-07-27T19:31:40.566Z' + pr: + status: pending + requested_at: '2026-07-28T05:59:44.215Z' + verify-approval: + status: pending +iteration: 1 +build_complete: true +history: + - iteration: 1 + plan_phase: phase_1 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_1-iter1-claude.txt + - iteration: 1 + plan_phase: phase_2 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_2-iter1-claude.txt + - iteration: 1 + plan_phase: phase_4 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter1-claude.txt + - iteration: 2 + plan_phase: phase_4 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter2-claude.txt + - iteration: 3 + plan_phase: phase_4 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_4-iter3-claude.txt + - iteration: 1 + plan_phase: phase_5 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter1-claude.txt + - iteration: 2 + plan_phase: phase_5 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter2-claude.txt + - iteration: 3 + plan_phase: phase_5 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_5-iter3-claude.txt + - iteration: 1 + plan_phase: phase_6 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-codex.txt + - model: claude + verdict: COMMENT + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter1-claude.txt + - iteration: 2 + plan_phase: phase_6 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_6-iter2-claude.txt + - iteration: 1 + plan_phase: phase_7 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-codex.txt + - model: claude + verdict: COMMENT + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter1-claude.txt + - iteration: 2 + plan_phase: phase_7 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter2-claude.txt + - iteration: 3 + plan_phase: phase_7 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_7-iter3-claude.txt + - iteration: 1 + plan_phase: phase_8 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-codex.txt + - model: claude + verdict: COMMENT + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter1-claude.txt + - iteration: 2 + plan_phase: phase_8 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter2-claude.txt + - iteration: 3 + plan_phase: phase_8 + build_output: '' + reviews: + - model: gemini + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-gemini.txt + - model: codex + verdict: REQUEST_CHANGES + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-codex.txt + - model: claude + verdict: APPROVE + file: >- + /Users/mwk/Development/cluesmith/codev/.builders/spir-1252/codev/projects/1252-prompt-architecture-single-own/1252-phase_8-iter3-claude.txt +started_at: '2026-07-27T07:23:40.596Z' +updated_at: '2026-07-28T05:59:44.215Z' +force_advanced: + phase: phase_8 + iteration: 3 + max_iterations: 3 + rebuttal_file: 1252-phase_8-iter3-rebuttals.md + at: '2026-07-28T05:51:15.386Z' +pr_ready_for_human: true diff --git a/codev/protocols/air/builder-prompt.md b/codev/protocols/air/builder-prompt.md deleted file mode 100644 index f17ab40ad..000000000 --- a/codev/protocols/air/builder-prompt.md +++ /dev/null @@ -1,81 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are implementing {{input_description}}. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the AIR protocol yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Consultation is optional — use your judgement based on complexity -- You have flexibility in execution, but must stay compliant with the protocol -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -{{/if}} - -## Protocol -Follow the AIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## Baked Decisions - -If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. - -If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. - -{{#if issue}} -## Issue #{{issue.number}} -**Title**: {{issue.title}} - -**Description**: -{{issue.body}} - -## Your Mission -1. Read the issue requirements carefully -2. Implement the feature (< 300 LOC) -3. Write tests for the feature -4. Create PR with review in the PR body (NOT as a separate file) -5. Notify architect via `afx send architect "PR #N ready for review (implements #{{issue.number}})"` - -**IMPORTANT**: AIR produces NO spec, plan, or review files. The review goes in the PR body. - -If the feature is too complex (> 300 LOC or architectural changes), notify the Architect via: -```bash -afx send architect "Issue #{{issue.number}} is more complex than expected. [Reason]. Recommend escalating to ASPIR." -``` - -## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **PR ready**: `afx send architect "PR #N ready for review (implements #{{issue.number}})"` -- **PR merged**: `afx send architect "PR #N merged for issue #{{issue.number}}. Ready for cleanup."` -- **Blocked**: `afx send architect "Blocked on issue #{{issue.number}}: [reason]"` -{{/if}} - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in the PR body under a "Flaky Tests" section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the AIR protocol -2. Review the issue details -3. Implement the feature - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/air/consult-types/impl-review.md b/codev/protocols/air/consult-types/impl-review.md deleted file mode 100644 index b382faedc..000000000 --- a/codev/protocols/air/consult-types/impl-review.md +++ /dev/null @@ -1,64 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work for a small feature built under the AIR protocol. The builder implemented directly from a GitHub issue — there is no spec or plan document. Your job is to verify the implementation matches the issue requirements and follows good practices. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files - -## Baked Decisions - -If the issue body includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed. Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns about a baked decision (the architect decides whether to rescind it); reserve `REQUEST_CHANGES` for the case where the implementation **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions, do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Issue Adherence** - - Does the implementation fulfill the issue requirements? - - Are the described acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate? - - Do tests cover the main paths AND edge cases? - -4. **Scope** - - Is the change under 300 LOC? If not, should this be escalated to ASPIR? - - Does the implementation stay focused on the issue, or does it include unrelated changes? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Implementation looks good, ready for PR -- `REQUEST_CHANGES`: Issues that must be fixed -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Notes - -- AIR has no spec or plan — review against the GitHub issue -- Focus on "does this feature work correctly" not "is this architecturally perfect" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback diff --git a/codev/protocols/air/consult-types/pr-review.md b/codev/protocols/air/consult-types/pr-review.md deleted file mode 100644 index 0d7856f3a..000000000 --- a/codev/protocols/air/consult-types/pr-review.md +++ /dev/null @@ -1,68 +0,0 @@ -# PR Ready Review Prompt - -## Context -You are performing a review of a pull request created under the AIR protocol. The builder implemented a small feature directly from a GitHub issue — there are no spec, plan, or review files. The review is embedded in the PR body. - -## Baked Decisions - -If the issue body includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed. Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns about a baked decision (the architect decides whether to rescind it); reserve `REQUEST_CHANGES` for the case where the code **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions, do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Completeness** - - Are the issue requirements implemented? - - Is the PR body review section filled out (summary, key decisions, test plan)? - - Are commits properly formatted? - -2. **Test Status** - - Do all tests pass? - - Is test coverage adequate for the changes? - - Are there any skipped or flaky tests? - -3. **Code Cleanliness** - - Is there any debug code left in? - - Are there any TODO comments that should be resolved? - - Is the code properly formatted? - -4. **Scope** - - Is the change under 300 LOC? - - Does the implementation stay focused on the issue? - - Are there unrelated changes bundled in? - -5. **PR Quality** - - Does the PR link to the issue? - - Is the PR body review section informative? - - Is the branch up to date with its base (the integration branch the PR targets)? - -## Scope - -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption or "How to Test Locally" section). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Ready for architect review -- `REQUEST_CHANGES`: Issues to fix before review -- `COMMENT`: Minor items, can proceed but note feedback - -## Notes - -- AIR has no spec, plan, or review files — review the PR body and code diff -- Focus on "is this ready for someone else to review" not "is this perfect" -- Any issues found here are cheaper to fix than during integration review diff --git a/codev/protocols/air/prompts/implement.md b/codev/protocols/air/prompts/implement.md deleted file mode 100644 index 301641962..000000000 --- a/codev/protocols/air/prompts/implement.md +++ /dev/null @@ -1,95 +0,0 @@ -# IMPLEMENT Phase Prompt - -You are executing the **IMPLEMENT** phase of the AIR protocol. - -## Your Goal - -Read the GitHub issue, implement the feature, and add tests. Keep it focused and under 300 LOC. - -## Baked Decisions - -Check the issue body for a section named "Baked Decisions" (any heading level, case-insensitive). If present, treat each listed decision as fixed during implementation. Do not autonomously substitute alternate languages, frameworks, or dependencies. If you discover a serious problem with a baked decision, raise it via `afx send architect` rather than working around it. - -If two baked decisions contradict each other, do not pick one — pause, flag the contradiction via `afx send`, and wait for resolution before implementing. - -## Context - -- **Issue**: #{{issue.number}} — {{issue.title}} -- **Current State**: {{current_state}} - -## Process - -### 1. Read the Issue - -Read the full issue description. Identify: -- What is the desired behavior? -- What are the acceptance criteria? -- Are there examples or mockups? -- What files/modules are likely affected? - -### 2. Implement the Feature - -Apply a focused implementation: -- Implement what the issue describes — no more, no less -- Do NOT refactor surrounding code -- Do NOT add features beyond what's described in the issue -- Do NOT fix unrelated bugs you happen to notice (file separate issues) - -**Code Quality**: -- Self-documenting code (clear names, obvious structure) -- No commented-out code or debug prints -- Follow existing project conventions - -### 3. Add Tests - -Write tests that: -- Cover the main happy path -- Cover key edge cases -- Are deterministic (not flaky) - -Place tests following project conventions (`__tests__/`, `*.test.ts`, etc.). - -### 4. Verify the Build - -Run build and tests: - -```bash -npm run build # Must pass -npm test # Must pass -``` - -Fix any failures before proceeding. If build/test commands don't exist, check `package.json`. - -### 5. Commit - -Stage and commit your changes: -- Use explicit file paths (never `git add -A` or `git add .`) -- Commit message: `[Air #{{issue.number}}] feat: ` - -## Signals - -When implementation and tests are complete and passing: - -``` -PHASE_COMPLETE -``` - -If the feature is too complex for AIR (> 300 LOC or architectural): - -``` -TOO_COMPLEX -``` - -If you're blocked (missing context, unclear requirements, etc.): - -``` -BLOCKED:reason goes here -``` - -## Important Notes - -1. **Stay focused** — Implement what the issue describes, nothing else -2. **Tests are expected** — Add tests unless the change is purely declarative (e.g., config only) -3. **Build AND tests must pass** — Don't signal complete until both pass -4. **Stay under 300 LOC** — If the feature grows beyond this, signal `TOO_COMPLEX` -5. **No spec/plan artifacts** — AIR does not create files in `codev/specs/` or `codev/plans/` diff --git a/codev/protocols/air/prompts/pr.md b/codev/protocols/air/prompts/pr.md deleted file mode 100644 index 5e3439943..000000000 --- a/codev/protocols/air/prompts/pr.md +++ /dev/null @@ -1,110 +0,0 @@ -# PR Phase Prompt - -You are executing the **PR** phase of the AIR protocol. - -## Your Goal - -Create a pull request with the review embedded in the PR body, optionally run CMAP, and notify the architect. - -## Context - -- **Issue**: #{{issue.number}} — {{issue.title}} -- **Current State**: {{current_state}} - -## Process - -### 1. Create the Pull Request - -Create a PR that links to the issue. The PR body IS the review — include a summary, key decisions, and test plan. - -**PR body requirements**: The PR body MUST include `Closes #` (where `` is -the driving issue number) so GitHub auto-closes the issue on merge. If the PR -closes multiple issues (e.g. duplicates consolidated), include one `Closes #` -per issue. Without this, GitHub will not auto-close the issue. - -**Exception**: if this PR only partially addresses the issue, use `Refs #` -or `Part of #` instead of `Closes` — the issue stays open until a -follow-up PR closes it. - -**Note**: substitute the real issue number for `` — do not leave the -placeholder or any `{{...}}` template tag in the committed PR body. - -```bash -gh pr create --title "[Air #] feat: " --body "$(cat <<'EOF' -## Summary - -<1-2 sentence description of the feature> - -Closes # - -## What Changed - - - -## Key Decisions - - - -## Test Plan - -- [ ] Unit tests added -- [ ] Build passes -- [ ] All tests pass - -## Review Notes - - -EOF -)" -``` - -**IMPORTANT**: Do NOT create a review file in `codev/reviews/`. The PR body IS the review for AIR. - -### 2. Optional CMAP Review - -If the implementation is non-trivial, run 3-way consultation: - -```bash -consult -m gemini --protocol air --type pr & -consult -m codex --protocol air --type pr & -consult -m claude --protocol air --type pr & -``` - -All three should run in the background (`run_in_background: true`). - -**This is optional** — use your judgement. For simple features (config changes, small UI additions), you may skip consultation. For features touching core logic or multiple modules, run it. - -### 3. Address Feedback (if CMAP was run) - -If you ran CMAP: -- Wait for all consultations to complete -- Record each model's verdict -- Fix any issues identified -- Push updates to the PR branch - -### 4. Notify Architect - -Send notification with PR link: - -```bash -afx send architect "PR # ready for review (implements issue #{{issue.number}})" -``` - -If CMAP was run, include verdicts: -```bash -afx send architect "PR # ready for review (implements issue #{{issue.number}}). CMAP: gemini=, codex=, claude=" -``` - -## Signals - -When PR is created and ready for review: - -``` -PHASE_COMPLETE -``` - -If you're blocked: - -``` -BLOCKED:reason goes here -``` diff --git a/codev/protocols/air/protocol.json b/codev/protocols/air/protocol.json deleted file mode 100644 index 7fea5bec9..000000000 --- a/codev/protocols/air/protocol.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "air", - "version": "1.0.0", - "description": "AIR: Autonomous Implement & Review — lightweight protocol for small features from GitHub Issues", - "input": { - "type": "github-issue", - "required": false, - "default_for": ["--issue", "-i"] - }, - "hooks": { - "pre-spawn": { - "collision-check": true, - "comment-on-issue": "On it! Implementing this feature now." - } - }, - "phases": [ - { - "id": "implement", - "name": "Implement", - "description": "Implement the feature and add tests", - "type": "once", - "steps": [ - "read_issue", - "implement_feature", - "add_tests", - "verify_build", - "commit" - ], - "checks": { - "build": { - "command": "npm run build", - "cwd": "packages/codev", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "npm test -- --exclude='**/e2e/**'", - "cwd": "packages/codev", - "description": "Unit tests only - e2e tests run in PR phase", - "on_fail": "retry", - "max_retries": 2 - } - }, - "transition": { - "on_complete": "pr", - "on_too_complex": "escalate" - } - }, - { - "id": "pr", - "name": "Create PR", - "description": "Create pull request with review in PR body", - "type": "once", - "steps": [ - "create_pr", - "link_issue", - "optional_consultation", - "notify_architect" - ], - "consultation": { - "on": "review", - "models": ["gemini", "codex"], - "type": "impl", - "parallel": true, - "max_rounds": 1 - }, - "checks": { - "pr_exists": { - "command": "gh pr list --state all --head \"$(git branch --show-current)\" --json number --jq 'length' | grep -q '^[1-9]'", - "description": "PR must be created before signaling completion" - }, - "e2e_tests": { - "command": "npm run test:e2e 2>&1 || echo 'e2e tests skipped (not configured)'", - "cwd": "packages/codev", - "description": "Full e2e test suite", - "optional": true - } - }, - "gate": "pr", - "transition": { - "on_complete": null - } - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current phase is complete", - "transitions_to": "next_phase" - }, - "TOO_COMPLEX": { - "description": "Feature is too complex for AIR, escalate to ASPIR", - "transitions_to": "escalate" - }, - "BLOCKED": { - "description": "Signal implementation is blocked", - "requires": "reason" - } - }, - "defaults": { - "mode": "strict", - "consultation": { - "enabled": true, - "models": ["gemini", "codex"], - "parallel": true - }, - "checks": { - "build": "npm run build", - "test": "npm test" - } - } -} diff --git a/codev/protocols/aspir/builder-prompt.md b/codev/protocols/aspir/builder-prompt.md deleted file mode 100644 index 07d02b701..000000000 --- a/codev/protocols/aspir/builder-prompt.md +++ /dev/null @@ -1,96 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are implementing {{input_description}}. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the protocol document yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval -{{/if}} - -## Protocol -Follow the ASPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## Baked Decisions - -If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. - -If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. - -{{#if spec}} -## Spec -Read the specification at: `{{spec.path}}` -{{/if}} - -{{#if plan}} -## Plan -Follow the implementation plan at: `{{plan.path}}` -{{/if}} - -{{#if issue}} -## Issue #{{issue.number}} -**Title**: {{issue.title}} - -**Description**: -{{issue.body}} -{{/if}} - -{{#if task}} -## Task -{{task_text}} -{{/if}} - -## PR Strategy - -**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. - -By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. - -### Architect-requested PRs - -The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. - -## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` -- **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} complete. PR merged. Ready for cleanup."` -- **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the protocol document thoroughly -2. Review the spec and plan (if available) -3. Begin implementation following the protocol phases - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/aspir/consult-types/impl-review.md b/codev/protocols/aspir/consult-types/impl-review.md deleted file mode 100644 index de01b8d00..000000000 --- a/codev/protocols/aspir/consult-types/impl-review.md +++ /dev/null @@ -1,72 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work during the Implement phase. A builder has completed a plan phase and needs feedback before proceeding. Your job is to verify the implementation matches the spec and plan. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Spec Adherence** - - Does the implementation fulfill the spec requirements for this phase? - - Are acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate for this phase? - - Do tests cover the main paths AND edge cases? - -4. **Plan Alignment** - - Does the implementation follow the plan? - - Are there plan items skipped or partially completed? - -5. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - If spec says "async" or "non-blocking", is it actually async? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Phase is complete, builder can proceed -- `REQUEST_CHANGES`: Issues that must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scoping (Multi-Phase Plans) - -When the implementation plan has multiple phases (e.g., scaffolding, landing, media_rtl): -- **ONLY review work belonging to the current plan phase** -- The query will specify which phase you are reviewing -- Do NOT request changes for functionality scheduled in later phases -- Do NOT flag missing features that are out of scope for this phase -- If unsure whether something belongs to this phase, check the plan file - -## Notes - -- This is a phase-level review, not the final PR review -- Focus on "does this phase work" not "is the whole feature done" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to continue diff --git a/codev/protocols/aspir/consult-types/phase-review.md b/codev/protocols/aspir/consult-types/phase-review.md deleted file mode 100644 index de01b8d00..000000000 --- a/codev/protocols/aspir/consult-types/phase-review.md +++ /dev/null @@ -1,72 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work during the Implement phase. A builder has completed a plan phase and needs feedback before proceeding. Your job is to verify the implementation matches the spec and plan. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Spec Adherence** - - Does the implementation fulfill the spec requirements for this phase? - - Are acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate for this phase? - - Do tests cover the main paths AND edge cases? - -4. **Plan Alignment** - - Does the implementation follow the plan? - - Are there plan items skipped or partially completed? - -5. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - If spec says "async" or "non-blocking", is it actually async? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Phase is complete, builder can proceed -- `REQUEST_CHANGES`: Issues that must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scoping (Multi-Phase Plans) - -When the implementation plan has multiple phases (e.g., scaffolding, landing, media_rtl): -- **ONLY review work belonging to the current plan phase** -- The query will specify which phase you are reviewing -- Do NOT request changes for functionality scheduled in later phases -- Do NOT flag missing features that are out of scope for this phase -- If unsure whether something belongs to this phase, check the plan file - -## Notes - -- This is a phase-level review, not the final PR review -- Focus on "does this phase work" not "is the whole feature done" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to continue diff --git a/codev/protocols/aspir/consult-types/plan-review.md b/codev/protocols/aspir/consult-types/plan-review.md deleted file mode 100644 index 485ff3183..000000000 --- a/codev/protocols/aspir/consult-types/plan-review.md +++ /dev/null @@ -1,65 +0,0 @@ -# Plan Review Prompt - -## Context -You are reviewing an implementation plan during the Plan phase. The spec has been approved - now you must evaluate whether the plan adequately describes HOW to implement it. - -## Baked Decisions - -If the issue body or the approved spec's Constraints section includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed (this extends the existing "don't re-litigate spec decisions" rule with explicit baked-decision language). Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns; reserve `REQUEST_CHANGES` for the case where the plan **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions, do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Spec Coverage** - - Does the plan address all requirements in the spec? - - Are there spec requirements not covered by any phase? - - Are there phases that go beyond the spec scope? - -2. **Phase Breakdown** - - Are phases appropriately sized (not too large or too small)? - - Is the sequence logical (dependencies respected)? - - Can each phase be completed and committed independently? - -3. **Technical Approach** - - Is the implementation approach sound? - - Are the right files/modules being modified? - - Are there obvious better approaches being missed? - -4. **Testability** - - Does each phase have clear test criteria? - - Will the Defend step (writing tests) be feasible? - - Are edge cases from the spec addressable? - -5. **Risk Assessment** - - Are there potential blockers not addressed? - - Are dependencies on other systems identified? - - Is the plan realistic given constraints? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Plan is ready for human review -- `REQUEST_CHANGES`: Significant issues with approach or coverage -- `COMMENT`: Minor suggestions, plan is workable but could improve - -## Notes - -- The spec has already been approved - don't re-litigate spec decisions -- Focus on the quality of the plan as a guide for builders -- Consider: Would a builder be able to follow this plan successfully? -- If referencing existing code, verify file paths seem accurate diff --git a/codev/protocols/aspir/consult-types/pr-review.md b/codev/protocols/aspir/consult-types/pr-review.md deleted file mode 100644 index 837cdea33..000000000 --- a/codev/protocols/aspir/consult-types/pr-review.md +++ /dev/null @@ -1,76 +0,0 @@ -# PR Ready Review Prompt - -## Context -You are performing a final self-check during the Review phase. The builder has completed all implementation phases and is about to create a PR. This is the last check before the work goes to the architect for integration review. - -## Focus Areas - -1. **Completeness** - - Are all spec requirements implemented? - - Are all plan phases complete? - - Is the review document written (`codev/reviews/XXXX-name.md`)? - - Are all commits properly formatted (`[Spec XXXX][Phase]`)? - -2. **Test Status** - - Do all tests pass? - - Is test coverage adequate for the changes? - - Are there any skipped or flaky tests? - -3. **Code Cleanliness** - - Is there any debug code left in? - - Are there any TODO comments that should be resolved? - - Are there any `// REVIEW:` comments that weren't addressed? - - Is the code properly formatted? - -4. **Documentation** - - Are inline comments clear where needed? - - Is the review document comprehensive? - - Are any new APIs documented? - -5. **PR Readiness** - - Is the branch up to date with its base (the integration branch the PR targets)? - - Are commits atomic and well-described? - - Is the change diff reasonable in size? - -## Scope - -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption or "How to Test Locally" section). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... - -PR_SUMMARY: | - ## Summary - [2-3 sentences describing what this PR does] - - ## Key Changes - - [Change 1] - - [Change 2] - - ## Test Plan - - [How to test] -``` - -**Verdict meanings:** -- `APPROVE`: Ready to create PR -- `REQUEST_CHANGES`: Issues to fix before PR creation -- `COMMENT`: Minor items, can create PR but note feedback - -## Notes - -- This is the builder's final self-review before hand-off -- The PR_SUMMARY in your output can be used as the PR description -- Focus on "is this ready for someone else to review" not "is this perfect" -- Any issues found here are cheaper to fix than during integration review diff --git a/codev/protocols/aspir/consult-types/spec-review.md b/codev/protocols/aspir/consult-types/spec-review.md deleted file mode 100644 index b537e7cc6..000000000 --- a/codev/protocols/aspir/consult-types/spec-review.md +++ /dev/null @@ -1,61 +0,0 @@ -# Specification Review Prompt - -## Context -You are reviewing a feature specification during the Specify phase. Your role is to ensure the spec is complete, correct, and feasible before it moves to human approval. - -## Baked Decisions - -If the issue body or the spec's Constraints section includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed. Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns about a baked decision (the architect decides whether to rescind it); reserve `REQUEST_CHANGES` for the case where the spec **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions (e.g., two different language choices), do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Completeness** - - Are all requirements clearly stated? - - Are success criteria defined? - - Are edge cases considered? - - Is scope well-bounded (not too broad or vague)? - -2. **Correctness** - - Do requirements make sense technically? - - Are there contradictions? - - Is the problem statement accurate? - -3. **Feasibility** - - Can this be implemented with available tools/constraints? - - Are there obvious technical blockers? - - Is the scope realistic for a single spec? - -4. **Clarity** - - Would a builder understand what to build? - - Are acceptance criteria testable? - - Is terminology consistent? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Spec is ready for human review -- `REQUEST_CHANGES`: Significant issues must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but consider feedback - -## Notes - -- You are NOT reviewing code - you are reviewing the specification document -- Focus on WHAT is being built, not HOW it will be implemented (that's for plan review) -- Be constructive - identify issues AND suggest solutions -- If the spec references other specs, note if context seems missing diff --git a/codev/protocols/aspir/prompts/implement.md b/codev/protocols/aspir/prompts/implement.md deleted file mode 100644 index bacc8502e..000000000 --- a/codev/protocols/aspir/prompts/implement.md +++ /dev/null @@ -1,215 +0,0 @@ -# IMPLEMENT Phase Prompt - -You are executing the **IMPLEMENT** phase of the SPIR protocol. - -## Your Goal - -Write clean, well-structured code AND tests that implement the current plan phase. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Plan Phase**: {{plan_phase_id}} - {{plan_phase_title}} - -## ⚠️ SCOPE RESTRICTION — READ THIS FIRST - -**You are implementing ONLY the current plan phase: {{plan_phase_id}} ({{plan_phase_title}}).** - -- **DO NOT** implement other phases. Other phases will be handled in subsequent porch iterations. -- **DO NOT** read the full plan file and implement everything you see. -- The plan phase details are included below under "Current Plan Phase Details". That is your ONLY scope. -- If you need to reference the spec for requirements, read `codev/specs/{{project_id}}-*.md` but ONLY implement what the current phase requires. - -## What Happens After You Finish - -When you signal `PHASE_COMPLETE`, porch will: -1. Run 3-way consultation (Gemini, Codex, Claude) on your implementation -2. Check that tests exist and pass -3. If reviewers request changes, you'll be respawned with their feedback -4. Once approved, porch commits and moves to the next plan phase - -## Spec Compliance (CRITICAL) - -**The spec is the source of truth. Code that doesn't match the spec is wrong, even if it "works".** - -### Trust Hierarchy - -``` -SPEC (source of truth) - ↓ -PLAN (implementation guide derived from spec) - ↓ -EXISTING CODE (NOT TRUSTED - must be validated against spec) -``` - -**Never trust existing code over the spec.** Previous implementations may have drifted. - -### Pre-Implementation Sanity Check (PISC) - -**Before writing ANY code:** - -1. ✅ "Have I read the spec in the last 30 minutes?" -2. ✅ "If the spec has a 'Traps to Avoid' section, have I read it?" -3. ✅ "Does my approach match the spec's Technical Implementation section?" -4. ✅ "If the spec has code examples, am I following them?" -5. ✅ "Does the existing code I'm building on actually match the spec?" - -**If ANY answer is "no" or "unsure" → STOP and re-read the spec.** - -### Avoiding "Fixing Mode" - -A dangerous pattern: You start looking at symptoms in code, making incremental fixes, copying existing patterns - without going back to the spec. This leads to: -- Cargo-culting patterns that may be wrong -- Building on broken foundations -- Implementing something different from the spec - -**When you catch yourself "fixing" code:** -1. STOP -2. Ask: "What does the spec say about this?" -3. Re-read the spec's Traps to Avoid section -4. Verify existing code matches the spec before building on it - -## Prerequisites - -Before implementing, verify: -1. Previous phase (if any) is committed to git -2. You've read the plan phase you're implementing -3. You understand the success criteria for this phase -4. Dependencies from earlier phases are available - -## Process - -### 1. Review the Plan Phase - -Read the current phase in the plan: -- What is the objective? -- What files need to be created/modified? -- What are the success criteria? -- What dependencies exist? - -### 2. Set Up - -- Verify you're on the correct branch -- Check that previous phase is committed: `git log --oneline -5` -- Ensure build passes before starting: `npm run build` (or equivalent) - -### 3. Implement the Code - -Write the code following these principles: - -**Code Quality Standards**: -- Self-documenting code (clear names, obvious structure) -- No commented-out code -- No debug prints in final code -- Explicit error handling -- Follow project style guide - -**Implementation Approach**: -- Work on one file at a time -- Make small, incremental changes -- Document complex logic with comments - -### 4. Write Tests - -**Tests are required.** For each piece of functionality you implement: - -- Write unit tests for core logic -- Write integration tests if the phase involves multiple components -- Test error cases and edge conditions -- Ensure tests are deterministic (no flaky tests) - -**Test file locations** (follow project conventions): -- `tests/` or `__tests__/` directories -- `*.test.ts` or `*.spec.ts` naming - -### 5. Verify Everything Works - -Run both build and tests: - -```bash -npm run build # Must pass -npm test # Must pass -``` - -**Important**: Don't assume these commands exist. Check `package.json` first. - -Fix any errors before signaling completion. - -### 6. Self-Review - -Before signaling completion: -- Read through all code changes -- Read through all test changes -- Verify code matches the spec requirements -- Ensure no accidental debug code -- Check test coverage is adequate - -## Output - -When complete, you should have: -- Modified/created source files as specified in the plan phase -- Tests covering the new functionality -- All build checks passing -- All tests passing - -## Signals - -When implementation AND tests are complete and passing: - -``` -PHASE_COMPLETE -``` - -If you encounter a blocker: - -``` -BLOCKED:reason goes here -``` - -If you need spec/plan clarification: - -``` - -Your specific questions here - -``` - -## Important Notes - -1. **Follow the plan** - Implement what's specified, not more -2. **Don't over-engineer** - Simplest solution that works -3. **Don't skip error handling** - But don't go overboard either -4. **Keep changes focused** - Only touch files in this phase -5. **Build AND tests must pass** - Don't signal complete until both pass -6. **Write tests** - Every implementation phase needs tests - -## What NOT to Do - -- Don't modify files outside this phase's scope -- Don't add features not in the spec -- Don't leave TODO comments for later (fix now or note as blocker) -- Don't skip writing tests -- Don't use `git add .` or `git add -A` when you commit (security risk) - -## Handling Problems - -**If the plan is unclear**: -Signal `AWAITING_INPUT` with your specific question. - -**If you discover the spec is wrong**: -Signal `BLOCKED` and explain the issue. The Architect may need to update the spec. - -**If a dependency is missing**: -Signal `BLOCKED` with details about what's missing. - -**If build or tests fail and you can't fix it**: -Signal `BLOCKED` with the error message. - -**If you encounter pre-existing flaky tests** (tests that fail intermittently but are unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use workarounds to avoid the failure -3. **DO** mark the flaky test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: intermittent timeout, skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section so the team can follow up -5. Commit the skip and continue with your work diff --git a/codev/protocols/aspir/prompts/plan.md b/codev/protocols/aspir/prompts/plan.md deleted file mode 100644 index 2c12250dd..000000000 --- a/codev/protocols/aspir/prompts/plan.md +++ /dev/null @@ -1,118 +0,0 @@ -# PLAN Phase Prompt - -You are executing the **PLAN** phase of the SPIR protocol. - -## Your Goal - -Transform the approved specification into an executable implementation plan with clear phases. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` -- **Plan File**: `codev/plans/{{artifact_name}}.md` - -## Prerequisites - -Before planning, verify: -1. The specification exists and has been approved -2. You've read and understood the entire spec -3. Success criteria are clear and measurable - -## Process - -### 1. Analyze the Specification - -Read the spec thoroughly. Identify: -- All functional requirements -- Non-functional requirements -- Dependencies and constraints -- Success criteria to validate against - -### 2. Identify Implementation Phases - -Break the work into logical phases. Each phase should be: -- **Self-contained** - A complete unit of functionality -- **Independently testable** - Can be verified on its own -- **Valuable** - Delivers observable progress -- **Committable** - Can be a single atomic commit - -Good phase examples: -- "Database Schema" - Creates all tables/migrations -- "Core API Endpoints" - Implements main REST routes -- "Authentication Flow" - Handles login/logout/session - -Bad phase examples: -- "Setup" - Too vague -- "Part 1" - Not descriptive -- "Everything" - Not broken down - -### 3. Define Each Phase - -For each phase, document: -- **Objective** - Single clear goal -- **Files to modify/create** - Specific paths -- **Dependencies** - Which phases must complete first -- **Success criteria** - How to know it's done -- **Test approach** - What tests will verify it - -### 4. Order Phases by Dependencies - -Arrange phases so dependencies are satisfied: -``` -Phase 1: Database Schema (no dependencies) -Phase 2: Data Models (depends on Phase 1) -Phase 3: API Endpoints (depends on Phase 2) -Phase 4: Frontend Integration (depends on Phase 3) -``` - -### 5. Finalize - -After completing the plan draft, signal completion. Porch will run 3-way consultation (Gemini, Codex, Claude) automatically via the verify step. If reviewers request changes, you'll be respawned with their feedback. - -## Output - -Create the plan file at `codev/plans/{{artifact_name}}.md`, following the template below: - -{{> protocols/spir/templates/plan.md}} - -## Signals - -Emit appropriate signals based on your progress: - -- After completing the plan draft: - ``` - PLAN_DRAFTED - ``` - -## Commit Cadence - -Make commits at these milestones: -1. `[Spec {{project_id}}] Initial implementation plan` -2. `[Spec {{project_id}}] Plan with multi-agent review` -3. `[Spec {{project_id}}] Plan with user feedback` -4. `[Spec {{project_id}}] Final approved plan` - -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: -```bash -git add codev/plans/{{artifact_name}}.md -``` - -## Important Notes - -1. **No time estimates** - Don't include hours/days/weeks -3. **Be specific about files** - Exact paths, not "the config file" -4. **Keep phases small** - 1-3 files per phase is ideal -5. **Document dependencies clearly** - Prevents blocked work - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't write code (that's for Implement phase) -- Don't estimate time (meaningless in AI development) -- Don't create phases that can't be independently tested -- Don't skip dependency analysis -- Don't make phases too large (if >5 files, split it) -- Don't use `git add .` or `git add -A` (security risk) diff --git a/codev/protocols/aspir/prompts/review.md b/codev/protocols/aspir/prompts/review.md deleted file mode 100644 index 22af9aec4..000000000 --- a/codev/protocols/aspir/prompts/review.md +++ /dev/null @@ -1,278 +0,0 @@ -# REVIEW Phase Prompt - -You are executing the **REVIEW** phase of the SPIR protocol. - -## Your Goal - -Perform a comprehensive review, document lessons learned, and prepare for PR submission. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` -- **Plan File**: `codev/plans/{{artifact_name}}.md` -- **Review File**: `codev/reviews/{{artifact_name}}.md` - -## Prerequisites - -Before review, verify: -1. All implementation phases are committed -2. All tests are passing -3. Build is passing -4. Spec compliance verified for all phases - -Verify commits: `git log --oneline | grep "[Spec {{project_id}}]"` - -## Process - -### 1. Comprehensive Review - -Review the entire implementation: - -**Code Quality**: -- Is the code readable and maintainable? -- Are there any code smells? -- Is error handling consistent? -- Are there any security concerns? - -**Architecture**: -- Does the implementation fit well with existing code? -- Are there any architectural concerns? -- Is the design scalable if needed? - -**Documentation**: -- Is code adequately commented where needed? -- Are public APIs documented? -- Is README updated if needed? - -### 2. Spec Comparison - -Compare final implementation to original specification: - -- What was delivered vs what was specified? -- Any deviations? Document why. -- All success criteria met? - -### 3. Create Review Document - -Create `codev/reviews/{{artifact_name}}.md`: - -```markdown -# Review: {{title}} - -## Summary -Brief description of what was implemented. - -## Spec Compliance -- [x] Requirement 1: Implemented as specified -- [x] Requirement 2: Implemented with deviation (see below) -- [x] Requirement 3: Implemented as specified - -## Deviations from Plan -- **Phase X**: [What changed and why] - -## Lessons Learned - -### What Went Well -- [Positive observation 1] -- [Positive observation 2] - -### Challenges Encountered -- [Challenge 1]: [How it was resolved] -- [Challenge 2]: [How it was resolved] - -### What Would Be Done Differently -- [Insight 1] -- [Insight 2] - -### Methodology Improvements -- [Suggested improvement to SPIR protocol] -- [Suggested improvement to tooling] - -## Technical Debt -- [Any shortcuts taken that should be addressed later] - -## Consultation Feedback - -[See instructions below] - -## Flaky Tests -- [Any pre-existing tests that were skipped as flaky during this project] -- [Include test name, file path, and observed failure mode] -- [If none: "No flaky tests encountered"] - -## Follow-up Items -- [Any items identified for future work] -``` - -### 3b. Include Consultation Feedback - -**IMPORTANT**: The review document MUST include a `## Consultation Feedback` section that summarizes all consultation concerns raised during every phase of the project and how the builder responded. - -Read the consultation output files from the project directory (`codev/projects/{project-id}-*/`). For each phase that had consultation, create a subsection organized by phase, round, and model: - -```markdown -## Consultation Feedback - -### Specify Phase (Round 1) - -#### Gemini -- **Concern**: [Summary of the concern] - - **Addressed**: [What was changed to resolve it] - -#### Codex -- **Concern**: [Summary] - - **Rebutted**: [Why the current approach is correct] - -#### Claude -- No concerns raised (APPROVE) - -### Plan Phase (Round 1) -... -``` - -**Response types** — each concern gets exactly one: -- **Addressed**: Builder made a change to resolve the concern -- **Rebutted**: Builder explains why the concern doesn't apply -- **N/A**: Concern is out of scope, already handled elsewhere, or moot - -**Edge cases**: -- If all reviewers approved with no concerns: "No concerns raised — all consultations approved" -- For COMMENT verdicts: include their feedback (non-blocking but useful context) -- For CONSULT_ERROR (model failure): note "Consultation failed for [model]" -- If a phase had multiple rounds, give each round its own subsection - -### 4. Update Architecture and Lessons Learned Documentation - -**MANDATORY**: The review document MUST include `## Architecture Updates` and `## Lessons Learned Updates` sections. Porch will block advancement if these are missing. - -Each governance doc has **two tiers** (Spec 987) — **route** each new fact/lesson to the right tier; do **not** just append to the cold archive: -- **HOT** — `codev/resources/arch-critical.md` / `lessons-critical.md`: tiny, **hard-capped**, **always injected** into every prompt and into CLAUDE.md/AGENTS.md. The behavior-changer. -- **COLD** — `codev/resources/arch.md` / `lessons-learned.md`: full, on-demand reference. - -**Architecture Updates**: -1. Read `arch-critical.md` (hot) and skim `arch.md` (cold). -2. If this project produced a system-shape fact, route it: - - **Behavior-changing + cross-cutting** (an invariant/decision a future builder must know up front) → add to **`arch-critical.md`**. Respect the cap: if the hot file is full, **demote** a weaker entry into `arch.md` to make room. If you add/rename a top-level `arch.md` section, keep the hot file's cold-doc map accurate. - - **Reference detail** (subsystem mechanism, file location, one-off) → add to **`arch.md`** (cold). -3. Describe what you routed where in the `## Architecture Updates` section. If nothing qualifies: write "No architecture updates needed" with a brief reason. - -**Lessons Learned Updates**: -1. Read `lessons-critical.md` (hot) and skim `lessons-learned.md` (cold). -2. If this project produced a durable lesson, route it: - - **Behavior-changing + cross-cutting** (a rule that should change how the next project is built) → add to **`lessons-critical.md`**, respecting the cap (demote a weaker entry into `lessons-learned.md` if full). - - **Spec-narrow recipe / reference tip** → add to **`lessons-learned.md`** (cold). Spec-narrow recipes belong in the cold archive, never the always-on hot file. -3. Describe what you routed where in the `## Lessons Learned Updates` section. If nothing qualifies: write "No lessons learned updates needed" with a brief reason. - -**Never** grow a hot file past its cap by appending — route to cold or displace. The cap is what keeps the hot tier cheap enough to always inject. - -### 4b. Update Other Documentation - -If needed, also update: -- README.md (new features, changed behavior) -- API documentation - -### 5. Final Verification - -Before PR: -- [ ] All tests pass (use project-specific test command) -- [ ] Build passes (use project-specific build command) -- [ ] Lint passes (if configured) -- [ ] No uncommitted changes: `git status` -- [ ] Review document complete - -### 6. Create Pull Request - -**IMPORTANT: Create the PR BEFORE signaling completion.** The PR must exist so that -porch consultation reviews the actual PR, and the architect can review a real PR -when the pr gate fires. - -**PR body requirements**: The PR body MUST include `Closes #` (for feature issues) -or `Fixes #` (for bug issues) for the driving GitHub issue. If the PR closes -multiple issues (e.g. duplicates consolidated), include one keyword per issue. -Without this, GitHub will not auto-close the issue on merge. - -**Exception**: if this PR only partially addresses the issue (e.g. one phase of a -multi-PR effort), DO NOT use `Closes`/`Fixes` — reference the issue with `Refs #` -or `Part of #` instead. The issue stays open until the follow-up PR closes it. - -```bash -gh pr create --title "[Spec {{project_id}}] {{title}}" --body "$(cat <<'EOF' -## Summary -[Brief description of the implementation] - -Closes # - -## Changes -- [Change 1] -- [Change 2] - -## Testing -- All unit tests passing -- Integration tests added for [X] -- Manual testing completed for [Y] - -## Spec -Link: codev/specs/{{artifact_name}}.md - -## Review -Link: codev/reviews/{{artifact_name}}.md -EOF -)" -``` - -### 7. Signal Completion - -After the PR is created, signal completion. Porch will run 3-way consultation -(Gemini, Codex, Claude) automatically via the verify step. If reviewers request -changes, you'll be respawned with their feedback. - -## Output - -- Review document at `codev/reviews/{{artifact_name}}.md` -- Updated documentation (if needed) -- Pull request created and ready for review - -## Signals - -- After review document is complete: - ``` - REVIEW_COMPLETE - ``` - -- After PR is created — signal completion so porch runs consultation: - ``` - PR_READY - ``` - -## Important Notes - -1. **Be honest in lessons learned** - Future you will thank present you -3. **Document deviations** - They're not failures, they're learnings -4. **Update methodology** - If you found a better way, document it -5. **Don't skip the checklist** - It catches last-minute issues -6. **Clean PR description** - Makes review easier - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't skip lessons learned ("nothing to report") -- Don't merge your own PR (Architect handles integration) -- Don't leave uncommitted changes -- Don't forget to update documentation -- Don't rush this phase - it's valuable for learning -- Don't use `git add .` or `git add -A` (security risk) - -## Review Prompts for Reflection - -Ask yourself: -- What surprised me during implementation? -- Where did I spend the most time? Was it avoidable? -- What would have helped me go faster? -- Did the spec adequately describe what was needed? -- Did the plan phases make sense in hindsight? -- What tests caught issues? What tests were unnecessary? - -Capture these reflections in the lessons learned section. diff --git a/codev/protocols/aspir/prompts/specify.md b/codev/protocols/aspir/prompts/specify.md deleted file mode 100644 index 3716f7969..000000000 --- a/codev/protocols/aspir/prompts/specify.md +++ /dev/null @@ -1,145 +0,0 @@ -# SPECIFY Phase Prompt - -You are executing the **SPECIFY** phase of the SPIR protocol. - -## Your Goal - -Create a comprehensive specification document that thoroughly explores the problem space and proposed solution. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` - -## Process - -### 0. Check for Existing Spec (ALWAYS DO THIS FIRST) - -**Before asking ANY questions**, check if a spec already exists: - -```bash -ls codev/specs/{{project_id}}-*.md -``` - -**If a spec file exists:** -1. READ IT COMPLETELY - the answers to your questions are already there -2. The spec author has already made the key decisions -3. DO NOT ask clarifying questions - proceed directly to consultation -4. Your job is to REVIEW and IMPROVE the existing spec, not rewrite it from scratch - -**If no spec exists:** Proceed to Step 1 below. - -### 0.5 Baked Decisions - -Before exploring solution approaches, check the issue body for a section named "Baked Decisions" (any heading level, case-insensitive). If present, copy its content verbatim into the spec's Constraints section and treat each item as fixed. Do not autonomously relitigate the architect's choices in your Solution Exploration. If you discover a serious problem with a baked decision, raise it via `afx send architect` rather than overriding it in the spec. - -If two baked decisions contradict each other (e.g., two different language choices), do not pick one — pause, flag the contradiction via `afx send`, and wait for resolution before drafting. - -### 1. Clarifying Questions (ONLY IF NO SPEC EXISTS) - -Before writing anything, ask clarifying questions to understand: -- What problem is being solved? -- Who are the stakeholders? -- What are the constraints? -- What's in scope vs out of scope? -- What does success look like? - -If this is your first iteration AND no spec exists, ask these questions now and wait for answers. - -**CRITICAL**: Do NOT ask questions if a spec already exists. The spec IS the answer. - -**On subsequent iterations**: If questions were already answered, acknowledge the answers and proceed to the next step. - -### 2. Problem Analysis - -Once you have answers, document: -- The problem being solved (clearly articulated) -- Current state vs desired state -- Stakeholders and their needs -- Assumptions and constraints - -### 3. Solution Exploration - -Generate multiple solution approaches. For each: -- Technical design overview -- Trade-offs (pros/cons) -- Complexity assessment -- Risk assessment - -### 4. Open Questions - -List uncertainties categorized as: -- **Critical** - blocks progress -- **Important** - affects design -- **Nice-to-know** - optimization - -### 5. Success Criteria - -Define measurable acceptance criteria: -- Functional requirements (MUST, SHOULD, COULD) -- Non-functional requirements (performance, security) -- Test scenarios - -### 6. Finalize - -After completing the spec draft, signal completion. Porch will run 3-way consultation (Gemini, Codex, Claude) automatically via the verify step. If reviewers request changes, you'll be respawned with their feedback. - -## Output - -Create or update the specification file at `codev/specs/{{artifact_name}}.md`. - -**IMPORTANT**: Keep spec/plan/review filenames in sync: -- Spec: `codev/specs/{{artifact_name}}.md` -- Plan: `codev/plans/{{artifact_name}}.md` -- Review: `codev/reviews/{{artifact_name}}.md` - -## Signals - -Emit appropriate signals based on your progress: - -- When waiting for clarifying question answers, **include your questions in the signal**: - ``` - - Please answer these questions: - 1. What should the primary use case be - internal tooling or customer-facing? - 2. What are the key constraints we should consider? - 3. Who are the main stakeholders? - - ``` - - The content inside the signal tag is displayed prominently to the user. - -- After completing the initial spec draft: - ``` - SPEC_DRAFTED - ``` - - -## Commit Cadence - -Make commits at these milestones: -1. `[Spec {{project_id}}] Initial specification draft` -2. `[Spec {{project_id}}] Specification with multi-agent review` -3. `[Spec {{project_id}}] Specification with user feedback` -4. `[Spec {{project_id}}] Final approved specification` - -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: -```bash -git add codev/specs/{{artifact_name}}.md -``` - -## Important Notes - -1. **Be thorough** - A good spec prevents implementation problems -3. **Be specific** - Vague specs lead to wrong implementations -4. **Include examples** - Concrete examples clarify intent - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) -- Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) diff --git a/codev/protocols/aspir/protocol.json b/codev/protocols/aspir/protocol.json deleted file mode 100644 index ed0dd7edc..000000000 --- a/codev/protocols/aspir/protocol.json +++ /dev/null @@ -1,169 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "aspir", - "version": "1.0.0", - "description": "ASPIR: Autonomous SPIR — Specify → Plan → Implement → Review without human approval gates", - "input": { - "type": "spec", - "required": false, - "default_for": ["--project", "-p"] - }, - "phases": [ - { - "id": "specify", - "name": "Specify", - "description": "Write specification with 3-way review", - "type": "build_verify", - "build": { - "prompt": "specify.md", - "artifact": "codev/specs/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "spec", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "next": "plan" - }, - { - "id": "plan", - "name": "Plan", - "description": "Write implementation plan with 3-way review", - "type": "build_verify", - "build": { - "prompt": "plan.md", - "artifact": "codev/plans/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "plan", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "plan_exists": "test -f codev/plans/${PROJECT_TITLE}.md", - "has_phases_json": "grep -qE '\"phases\"\\s*:' codev/plans/${PROJECT_TITLE}.md", - "min_two_phases": "grep -o '\"id\": *\"[^\"]*\"' codev/plans/${PROJECT_TITLE}.md | wc -l | awk '$1 >= 2 {exit 0} {exit 1}'" - }, - "next": "implement" - }, - { - "id": "implement", - "name": "Implement", - "description": "Implement code with 3-way review per plan phase", - "type": "per_plan_phase", - "build": { - "prompt": "implement.md", - "artifact": "src/**/*.{ts,tsx,js,jsx}" - }, - "verify": { - "type": "impl", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "build": { - "command": "npm run build", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "npm test -- --exclude='**/e2e/**'", - "description": "Unit tests only - e2e tests run in review phase", - "on_fail": "retry", - "max_retries": 2 - } - }, - "transition": { - "on_complete": "implement", - "on_all_phases_complete": "review" - } - }, - { - "id": "review", - "name": "Review", - "description": "Final review and PR with 3-way review", - "type": "build_verify", - "build": { - "prompt": "review.md", - "artifact": "codev/reviews/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "pr", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "pr_exists": { - "command": "gh pr list --state all --head \"$(git branch --show-current)\" --json number --jq 'length' | grep -q '^[1-9]'", - "description": "PR must be created before signaling completion" - }, - "review_has_arch_updates": { - "command": "grep -q '## Architecture Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Architecture Updates' section (what changed in arch.md, or why no changes needed)" - }, - "review_has_lessons_updates": { - "command": "grep -q '## Lessons Learned Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Lessons Learned Updates' section (what changed in lessons-learned.md, or why no changes needed)" - }, - "e2e_tests": { - "command": "npm run test:e2e 2>&1 || echo 'e2e tests skipped (not configured)'", - "description": "Full e2e test suite - only runs in review phase", - "optional": true - } - }, - "gate": "pr", - "next": "verify" - }, - { - "id": "verify", - "name": "Verify", - "description": "Post-merge environmental verification (optional — skip with porch verify --skip)", - "type": "once", - "gate": "verify-approval", - "next": null - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current build phase is complete", - "transitions_to": "verify" - }, - "BLOCKED": { - "description": "Signal implementation is blocked", - "requires": "reason" - } - }, - "phase_completion": { - "build_succeeds": "npm run build 2>&1", - "tests_pass": "npm test 2>&1", - "commit_has_code": "git log -1 --name-only --pretty=format: | grep -qE '\\.(ts|tsx|js|jsx|py|go|rs)$'" - }, - "defaults": { - "mode": "strict", - "max_iterations": 8, - "verify": { - "models": ["gemini", "codex", "claude"], - "parallel": true - } - } -} diff --git a/codev/protocols/aspir/protocol.md b/codev/protocols/aspir/protocol.md deleted file mode 100644 index 18a423a30..000000000 --- a/codev/protocols/aspir/protocol.md +++ /dev/null @@ -1,98 +0,0 @@ -# ASPIR Protocol - -> **ASPIR** = **A**utonomous **S**pecify → **P**lan → **I**mplement → **R**eview -> -> Identical to SPIR but without human approval gates on spec and plan phases. -> Each phase has one build-verify cycle with 3-way consultation. - -## What is ASPIR? - -ASPIR is an autonomous variant of the SPIR protocol. It follows the exact same phases (Specify → Plan → Implement → Review) with the same 3-way consultations, checks, and PR flow — but removes the `spec-approval` and `plan-approval` human gates. - -This means the builder proceeds automatically from Specify → Plan → Implement without waiting for human approval at each gate. The `pr` gate in the Review phase is preserved — a human still reviews all code before merge. - -### Differences from SPIR - -| Aspect | SPIR | ASPIR | -|--------|------|-------| -| Spec gate (`spec-approval`) | Human must approve | Auto-approved | -| Plan gate (`plan-approval`) | Human must approve | Auto-approved | -| PR gate (`pr`) | Human must approve | Human must approve | -| Phases | Specify → Plan → Implement → Review | Same | -| 3-way consultations | Yes, every phase | Same | -| Checks (build, tests, PR) | Yes | Same | -| Prompts / templates | Full set | Same (copied from SPIR) | - -### When to Use ASPIR - -Use ASPIR instead of SPIR when: - -- The work is **trusted and low-risk** — internal tooling, protocol additions, well-understood features -- The architect has **pre-written and approved** the spec before spawning -- The scope is **self-contained** with low blast radius -- You want **full SPIR discipline** (consultations, phased implementation, review) without waiting at gates - -### When NOT to Use ASPIR - -Use SPIR instead when: - -- The feature involves **novel architecture** or unclear requirements -- The spec needs **iterative human feedback** during drafting -- The work is **high-risk** — security-sensitive, user-facing, or broadly impactful -- You want to **review and adjust** the plan before implementation starts - -## Baked Decisions (Optional) - -When filing an issue for ASPIR, you can pin architectural decisions you don't want the builder or CMAP reviewers to re-litigate. Include a `## Baked Decisions` section (any heading level is fine) anywhere in the issue body. Useful categories: language, framework, deployment shape, key dependencies, decisions deferred to a later spec. The builder will copy the section verbatim into the spec's Constraints and treat each item as fixed; CMAP reviewers will not propose alternatives unless the spec itself fails to honor a stated decision. Leave the section out for issues where you want the builder to explore freely — absence is the no-op default. You can amend or rescind a baked decision at any time by updating the issue and respawning, or by sending the builder a direct instruction via `afx send`. - -## Protocol Phases - -ASPIR follows the same four phases as SPIR. For full phase documentation, see the [SPIR protocol](../spir/protocol.md). - -### S - Specify -Write specification with 3-way review (Gemini, Codex, Claude). **No human gate** — proceeds directly to Plan after verification. - -### P - Plan -Write implementation plan with 3-way review. **No human gate** — proceeds directly to Implement after verification and checks pass. - -### I - Implement -Execute each plan phase with build-verify cycle. Same as SPIR — no gate between phases (SPIR also has no gate here). - -### R - Review -Final review, PR preparation, and 3-way review. **PR gate preserved** — builder stops and waits for human approval before merge. - -## Usage - -```bash -# Spawn a builder using ASPIR -afx spawn 42 --protocol aspir - -# The builder runs autonomously through Specify → Plan → Implement -# and stops only at the PR gate in the Review phase -``` - -## File Structure - -``` -codev/protocols/aspir/ -├── protocol.json # Protocol definition (SPIR minus gates) -├── protocol.md # This file -├── builder-prompt.md # Builder instructions (same as SPIR) -├── prompts/ -│ ├── specify.md # Specify phase prompt (same as SPIR) -│ ├── plan.md # Plan phase prompt (same as SPIR) -│ ├── implement.md # Implement phase prompt (same as SPIR) -│ └── review.md # Review phase prompt (same as SPIR) -├── consult-types/ -│ ├── spec-review.md # Spec consultation guide (same as SPIR) -│ ├── plan-review.md # Plan consultation guide (same as SPIR) -│ ├── impl-review.md # Impl consultation guide (same as SPIR) -│ ├── phase-review.md # Phase consultation guide (same as SPIR) -│ └── pr-review.md # PR consultation guide (same as SPIR) -└── templates/ - ├── spec.md # Spec template (same as SPIR) - ├── plan.md # Plan template (same as SPIR) - └── review.md # Review template (same as SPIR) -``` - -All files except `protocol.json` and `protocol.md` are identical to their SPIR counterparts. diff --git a/codev/protocols/aspir/templates/plan.md b/codev/protocols/aspir/templates/plan.md deleted file mode 100644 index 831199848..000000000 --- a/codev/protocols/aspir/templates/plan.md +++ /dev/null @@ -1,204 +0,0 @@ -# Plan: [Title] - -## Metadata -- **ID**: plan-[YYYY-MM-DD]-[short-name] -- **Status**: draft -- **Specification**: [Link to codev/specs/spec-file.md] -- **Created**: [YYYY-MM-DD] - -## Executive Summary -[Brief overview of the implementation approach chosen and why. Reference the specification's selected approach.] - -## Success Metrics -[Copy from specification and add implementation-specific metrics] -- [ ] All specification criteria met -- [ ] Test coverage >90% -- [ ] Performance benchmarks achieved -- [ ] Zero critical security issues -- [ ] Documentation complete - -## Phases (Machine Readable) - - - -```json -{ - "phases": [ - {"id": "phase_1", "title": "Phase 1 Title Here"}, - {"id": "phase_2", "title": "Phase 2 Title Here"}, - {"id": "phase_3", "title": "Phase 3 Title Here"} - ] -} -``` - -## Phase Breakdown - -### Phase 1: [Descriptive Name] -**Dependencies**: None - -#### Objectives -- [Clear, single objective for this phase] -- [What value does this phase deliver?] - -#### Deliverables -- [ ] [Specific deliverable 1] -- [ ] [Specific deliverable 2] -- [ ] [Tests for this phase] -- [ ] [Documentation updates] - -#### Implementation Details -[Specific technical approach for this phase. Include: -- Key files/modules to create or modify -- Architectural decisions -- API contracts -- Data models] - -#### Acceptance Criteria -- [ ] [Testable criterion 1] -- [ ] [Testable criterion 2] -- [ ] All tests pass -- [ ] Code review completed - -#### Test Plan -- **Unit Tests**: [What to test] -- **Integration Tests**: [What to test] -- **Manual Testing**: [Scenarios to verify] - -#### Rollback Strategy -[How to revert this phase if issues arise] - -#### Risks -- **Risk**: [Specific risk for this phase] - - **Mitigation**: [How to address] - ---- - -### Phase 2: [Descriptive Name] -**Dependencies**: Phase 1 - -[Repeat structure for each phase] - ---- - -### Phase 3: [Descriptive Name] -**Dependencies**: Phase 2 - -[Continue for all phases] - -## Dependency Map -``` -Phase 1 ──→ Phase 2 ──→ Phase 3 - ↓ - Phase 4 (optional) -``` - -## Resource Requirements -### Development Resources -- **Engineers**: [Expertise needed] -- **Environment**: [Dev/staging requirements] - -### Infrastructure -- [Database changes] -- [New services] -- [Configuration updates] -- [Monitoring additions] - -## Integration Points -### External Systems -- **System**: [Name] - - **Integration Type**: [API/Database/Message Queue] - - **Phase**: [Which phase needs this] - - **Fallback**: [What if unavailable] - -### Internal Systems -[Repeat structure] - -## Risk Analysis -### Technical Risks -| Risk | Probability | Impact | Mitigation | Owner | -|------|------------|--------|------------|-------| -| [Risk 1] | L/M/H | L/M/H | [Strategy] | [Name] | - -### Schedule Risks -| Risk | Probability | Impact | Mitigation | Owner | -|------|------------|--------|------------|-------| -| [Risk 1] | L/M/H | L/M/H | [Strategy] | [Name] | - -## Validation Checkpoints -1. **After Phase 1**: [What to validate] -2. **After Phase 2**: [What to validate] -3. **Before Production**: [Final checks] - -## Monitoring and Observability -### Metrics to Track -- [Metric 1: Description and threshold] -- [Metric 2: Description and threshold] - -### Logging Requirements -- [What to log and at what level] -- [Retention requirements] - -### Alerting -- [Alert condition and severity] -- [Who to notify] - -## Documentation Updates Required -- [ ] API documentation -- [ ] Architecture diagrams -- [ ] Runbooks -- [ ] User guides -- [ ] Configuration guides - -## Post-Implementation Tasks -- [ ] Performance validation -- [ ] Security audit -- [ ] Load testing -- [ ] User acceptance testing -- [ ] Monitoring validation - -## Expert Review -**Date**: [YYYY-MM-DD] -**Model**: [Model consulted] -**Key Feedback**: -- [Feasibility assessment] -- [Missing considerations] -- [Risk identification] -- [Alternative suggestions] - -**Plan Adjustments**: -- [How the plan was modified based on feedback] - -## Approval -- [ ] Technical Lead Review -- [ ] Engineering Manager Approval -- [ ] Resource Allocation Confirmed -- [ ] Expert AI Consultation Complete - -## Change Log -| Date | Change | Reason | Author | -|------|--------|--------|--------| -| [Date] | [What changed] | [Why] | [Who] | - -## Notes -[Additional context, assumptions, or considerations] - ---- - -## Amendment History - -This section tracks all TICK amendments to this plan. TICKs modify both the spec and plan together as an atomic unit. - - - - \ No newline at end of file diff --git a/codev/protocols/aspir/templates/review.md b/codev/protocols/aspir/templates/review.md deleted file mode 100644 index af72f0e62..000000000 --- a/codev/protocols/aspir/templates/review.md +++ /dev/null @@ -1,120 +0,0 @@ -# Review: [Feature/Project Name] - -## Summary - -[1-3 sentences: what was built, how many phases, net outcome.] - -## Spec Compliance - -- [x] AC1: [Description] (Phase N) -- [x] AC2: [Description] (Phase N) -- [ ] ACn: [Not met — reason] - -## Deviations from Plan - -- **Phase N**: [What changed and why] - -## Key Metrics - -- **Commits**: [N] on the branch -- **Tests**: [N] passing ([N] existing + [N] new) -- **Files created**: [list] -- **Files deleted**: [list] -- **Net LOC impact**: [+/-N lines] - -## Timelog - -All times [timezone], [date range]. - -| Time | Event | -|------|-------| -| HH:MM | First commit: [description] | -| HH:MM | [Phase/milestone] | -| — | **GATE: [gate-name]** (human approval required) | -| HH:MM | Implementation begins | -| HH:MM | Phase N complete after N iterations | -| HH:MM | **GATE: pr** | - -### Autonomous Operation - -| Period | Duration | Activity | -|--------|----------|----------| -| Spec + Plan | ~Nm | [Summary] | -| Human gate wait | ~Nh Nm | Idle — waiting for approval | -| Implementation → PR | ~Nh Nm | N phases, N consultation rounds | - -**Total wall clock** (first commit to pr): **Xh Ym** -**Total autonomous work time** (excluding gate waits): **~Xh Ym** -**Context window resets**: [N] (resumed automatically / required manual restart) - -## Consultation Iteration Summary - -[N] consultation files produced ([N] rounds x [N] models). [N] APPROVE, [N] REQUEST_CHANGES, [N] COMMENT. - -| Phase | Iters | Who Blocked | What They Caught | -|-------|-------|-------------|------------------| -| Specify | N | [Model] | [Brief description] | -| Plan | N | [Model] | [Brief description] | -| Phase 1 | N | [Model] | [Brief description] | -| Phase N | N | [Model] | [Brief description] | -| Review | N | [Model] | [Brief description] | - -**Most frequent blocker**: [Model] — blocked in N of N rounds, focused on: [pattern]. - -### Avoidable Iterations - -Iterations that could have been prevented with better builder behavior: - -1. **[Pattern]**: [Specific thing the builder should have done without needing reviewer feedback. E.g., "Run exhaustive grep before claiming all instances fixed."] - -2. **[Pattern]**: [Another avoidable iteration pattern.] - -## Consultation Feedback - -[For each phase that had consultation, summarize every reviewer's concerns and how the builder responded. Use **Addressed** (fixed), **Rebutted** (disagreed with reasoning), or **N/A** (out of scope/moot) for each concern. If all reviewers approved with no concerns: "No concerns raised — all consultations approved."] - -### [Phase] Phase (Round N) - -#### Gemini -- **Concern**: [Summary of concern] - - **Addressed**: [What was changed] - -#### Codex -- **Concern**: [Summary of concern] - - **Rebutted**: [Why current approach is correct] - -#### Claude -- No concerns raised (APPROVE) - -## Lessons Learned - -### What Went Well -- [Specific positive observation — what worked and why] - -### Challenges Encountered -- **[Challenge]**: [How it was resolved. How many iterations it cost.] - -### What Would Be Done Differently -- [Actionable improvement for future builders] - -## Architecture Updates - -[What you routed where — HOT `codev/resources/arch-critical.md` (tiny, capped, always-injected) vs COLD `codev/resources/arch.md` (reference) — or why no changes were needed.] - -- Routed: [hot | cold] — [fact/section] — [what was added/changed; note any demotion if the hot file was full] -- Or: "No architecture updates needed — [brief reason]" - -## Lessons Learned Updates - -[What you routed where — HOT `codev/resources/lessons-critical.md` (capped) vs COLD `codev/resources/lessons-learned.md` (reference) — or why no changes were needed.] - -- Routed: [hot | cold] — [category] — [lesson summary] -- Or: "No lessons learned updates needed — [brief reason]" - -## Technical Debt - -- [Any shortcuts taken or inconsistencies introduced] - -## Follow-up Items - -- [Items identified for future work, outside this spec's scope] diff --git a/codev/protocols/aspir/templates/spec.md b/codev/protocols/aspir/templates/spec.md deleted file mode 100644 index 03c17315d..000000000 --- a/codev/protocols/aspir/templates/spec.md +++ /dev/null @@ -1,182 +0,0 @@ -# Specification: [Title] - - - -## Metadata -- **ID**: spec-[YYYY-MM-DD]-[short-name] -- **Status**: draft -- **Created**: [YYYY-MM-DD] - -## Clarifying Questions Asked - -[List the questions you asked to understand the problem better and the responses received. This shows the discovery process.] - -## Problem Statement -[Clearly articulate the problem being solved. Include context about why this is important, who is affected, and what the current pain points are.] - -## Current State -[Describe how things work today. What are the limitations? What workarounds exist? Include specific examples.] - -## Desired State -[Describe the ideal solution. How should things work after implementation? What specific improvements will users see?] - -## Stakeholders -- **Primary Users**: [Who will directly use this feature?] -- **Secondary Users**: [Who else is affected?] -- **Technical Team**: [Who will implement and maintain this?] -- **Business Owners**: [Who has decision authority?] - -## Success Criteria -- [ ] [Specific, measurable criterion 1] -- [ ] [Specific, measurable criterion 2] -- [ ] [Specific, measurable criterion 3] -- [ ] All tests pass with >90% coverage -- [ ] Performance benchmarks met (specify below) -- [ ] Documentation updated - -## Constraints -### Technical Constraints -- [Existing system limitations] -- [Technology stack requirements] -- [Integration points] - -### Business Constraints -- [Timeline requirements] -- [Budget considerations] -- [Compliance requirements] - -## Assumptions -- [List assumptions being made] -- [Include dependencies on other work] -- [Note any prerequisites] - -## Solution Approaches - -### Approach 1: [Name] -**Description**: [Brief overview of this approach] - -**Pros**: -- [Advantage 1] -- [Advantage 2] - -**Cons**: -- [Disadvantage 1] -- [Disadvantage 2] - -**Estimated Complexity**: [Low/Medium/High] -**Risk Level**: [Low/Medium/High] - -### Approach 2: [Name] -[Repeat structure for additional approaches] - -[Add as many approaches as appropriate for the problem] - -## Open Questions - -### Critical (Blocks Progress) -- [ ] [Question that must be answered before proceeding] - -### Important (Affects Design) -- [ ] [Question that influences technical decisions] - -### Nice-to-Know (Optimization) -- [ ] [Question that could improve the solution] - -## Performance Requirements -- **Response Time**: [e.g., <200ms p95] -- **Throughput**: [e.g., 1000 requests/second] -- **Resource Usage**: [e.g., <500MB memory] -- **Availability**: [e.g., 99.9% uptime] - -## Security Considerations -- [Authentication requirements] -- [Authorization model] -- [Data privacy concerns] -- [Audit requirements] - -## Test Scenarios -### Functional Tests -1. [Scenario 1: Happy path] -2. [Scenario 2: Edge case] -3. [Scenario 3: Error condition] - -### Non-Functional Tests -1. [Performance test scenario] -2. [Security test scenario] -3. [Load test scenario] - -## Dependencies -- **External Services**: [List any external APIs or services] -- **Internal Systems**: [List internal dependencies] -- **Libraries/Frameworks**: [List required libraries] - -## References -- [Link to relevant documentation in codev/ref/] -- [Link to related specifications] -- [Link to architectural diagrams] -- [Link to research materials] - -## Risks and Mitigation -| Risk | Probability | Impact | Mitigation Strategy | -|------|------------|--------|-------------------| -| [Risk 1] | Low/Med/High | Low/Med/High | [How to address] | -| [Risk 2] | Low/Med/High | Low/Med/High | [How to address] | - -## Expert Consultation - -**Date**: [YYYY-MM-DD] -**Models Consulted**: [e.g., GPT-5 and Gemini Pro] -**Sections Updated**: -- [Section name]: [Brief description of change based on consultation] -- [Section name]: [Brief description of change based on consultation] - -Note: All consultation feedback has been incorporated directly into the relevant sections above. - -## Approval -- [ ] Technical Lead Review -- [ ] Product Owner Review -- [ ] Stakeholder Sign-off -- [ ] Expert AI Consultation Complete - -## Notes -[Any additional context or considerations not covered above] - ---- - -## Amendments - -This section tracks all TICK amendments to this specification. TICKs are lightweight changes that refine an existing spec rather than creating a new one. - - - - \ No newline at end of file diff --git a/codev/protocols/bugfix/builder-prompt.md b/codev/protocols/bugfix/builder-prompt.md deleted file mode 100644 index bb950cfe4..000000000 --- a/codev/protocols/bugfix/builder-prompt.md +++ /dev/null @@ -1,75 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are implementing {{input_description}}. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the BUGFIX protocol yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -{{/if}} - -## Protocol -Follow the BUGFIX protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -{{#if issue}} -## Issue #{{issue.number}} -**Title**: {{issue.title}} - -**Description**: -{{issue.body}} - -## Your Mission -1. Reproduce the bug -2. Identify root cause -3. Implement fix (< 300 LOC) -4. Add regression test -5. Create PR with "Fixes #{{issue.number}}" in body -6. Notify architect via `afx send architect "PR #N ready for review (fixes #{{issue.number}})"` - -If the fix is too complex (> 300 LOC or architectural changes), notify the Architect via: -```bash -afx send architect "Issue #{{issue.number}} is more complex than expected. [Reason]. Recommend escalating to SPIR/TICK." -``` - -## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **PR ready**: `afx send architect "PR #N ready for review (fixes #{{issue.number}})"` -- **PR merged**: `afx send architect "PR #N merged for issue #{{issue.number}}. Ready for cleanup."` -- **Blocked**: `afx send architect "Blocked on issue #{{issue.number}}: [reason]"` -{{/if}} - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the BUGFIX protocol -2. Review the issue details -3. Reproduce the bug before fixing - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/bugfix/consult-types/impl-review.md b/codev/protocols/bugfix/consult-types/impl-review.md deleted file mode 100644 index 90d6a2d9e..000000000 --- a/codev/protocols/bugfix/consult-types/impl-review.md +++ /dev/null @@ -1,79 +0,0 @@ -# Implementation Review Prompt (BUGFIX) - -## Context -You are reviewing in-progress fix work for a **BUGFIX protocol** project. A builder has investigated a GitHub Issue, identified a root cause, and is implementing the fix + regression test. Your job is to verify the fix matches the issue's symptom and meets BUGFIX standards. - -**BUGFIX is not SPIR.** There is **no spec, no plan, and no review document**. The GitHub Issue is the spec. The PR body will be the review. Do **not** request changes for missing `codev/specs/`, `codev/plans/`, or `codev/reviews/` artifacts. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions. -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs. -3. **Do not assume** your training data reflects the version in use — verify against project files. -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed. - -## Focus Areas - -1. **Issue Adherence** - - Does the implementation actually resolve the symptom described in the GitHub Issue? - - Is the root cause fix targeted, or is it a workaround that masks the symptom? - -2. **Regression Test** - - Is there a regression test that exercises the exact scenario from the issue? - - Without the fix applied, would this test fail? (The whole point.) - - Is the test deterministic? - - If no test was added, has the builder justified why (e.g., docs-only change with no testable behavior)? - -3. **Scope Discipline** - - Is the change focused on the root cause only — no unrelated refactors, no drive-by fixes? - - Is the net diff staying under ~300 LOC? If it has grown larger, should this escalate to SPIR/TICK? - -4. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues introduced by the fix? - - Are error cases handled appropriately for the path that was changed? - - No debug code, stray `console.log`, or commented-out code. - -5. **Test Status** - - Existing tests still pass. - - Build still passes. - - No new flaky tests introduced. - -## Out of Scope (Do NOT request changes for) - -The following are **not** part of the BUGFIX protocol and must **not** be cited as REQUEST_CHANGES reasons: - -- Missing `codev/specs/-*.md`, `codev/plans/-*.md`, or `codev/reviews/-*.md` — BUGFIX produces none of these. The GitHub Issue is the spec; the PR body is the review. -- Commit format `[Spec NNNN][Phase]` — BUGFIX uses `Fix #N: ...` or `[Bugfix #N] ...`. This is the protocol-mandated format, **not** a bug. -- `status.yaml` fields such as `build_complete: false` — porch manages `status.yaml`; the builder is **forbidden** from editing it manually. Treat porch state as informational, not a fixable issue. -- "Plan Alignment" or "Spec Adherence" — there is no plan and no spec to align with. -- Phase-scoping concerns — BUGFIX is single-phase by design. There are no plan phases to scope against. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Fix and regression test are in good shape; builder can proceed to PR creation. -- `REQUEST_CHANGES`: Real BUGFIX-relevant issues (fix doesn't resolve the symptom, missing regression test without justification, scope creep, broken existing tests, etc.). -- `COMMENT`: Minor suggestions; builder can proceed but should consider the feedback. - -## Notes - -- This is an implementation-level review, not the final PR review. -- Focus on "does this fix actually resolve the issue, and is it protected by a regression test" — not on artifacts from other protocols. -- If referencing line numbers, use `file:line` format. -- The builder needs actionable, protocol-correct feedback to continue. diff --git a/codev/protocols/bugfix/consult-types/pr-review.md b/codev/protocols/bugfix/consult-types/pr-review.md deleted file mode 100644 index efdb7a176..000000000 --- a/codev/protocols/bugfix/consult-types/pr-review.md +++ /dev/null @@ -1,98 +0,0 @@ -# PR Ready Review Prompt (BUGFIX) - -## Context -You are performing a final self-check during the PR phase of the **BUGFIX protocol**. The builder has investigated a GitHub Issue, implemented a focused fix, and added a regression test. They are about to create — or have just created — a PR for the architect's integration review. - -**BUGFIX is not SPIR.** Do **not** review against the SPIR three-document trinity. The artifacts of a BUGFIX project are: -- The originating **GitHub Issue** (serves as the spec) -- The **code fix** (minimal, focused on root cause) -- A **regression test** that fails without the fix and passes with it -- The **PR body** (Summary, Root Cause, Fix, Test Plan) - -There is **no `codev/specs/`, `codev/plans/`, or `codev/reviews/` file** for a BUGFIX, and there should not be one. The commit format is `Fix #NNNN: ` (or `[Bugfix #NNNN] ...`), **not** `[Spec NNNN][Phase]`. - -## Focus Areas - -1. **Issue Resolution** - - Does the fix actually resolve the symptom described in the issue? - - Does the PR body include `Fixes #` so the issue auto-closes on merge? - - Does the PR description cover: Summary, Root Cause, Fix, Test Plan? - -2. **Regression Test** - - Is there a regression test that targets the exact scenario from the issue? - - Would the test fail without the fix? (If reviewers can't tell, ask the builder to demonstrate.) - - Is the test deterministic (not flaky)? - - If the fix is documentation-only or otherwise truly untestable, has the builder explicitly justified the absence of a test? - -3. **Scope Discipline** - - Is the change focused on the root cause? No unrelated refactors, no drive-by fixes for other bugs. - - Is the net diff under ~300 LOC (additions + deletions, excluding generated/lockfiles)? - - If the scope grew beyond a bugfix, should the builder have escalated to SPIR/TICK instead? - -4. **Code Cleanliness** - - No debug code, `console.log`, or commented-out blocks left behind. - - No stray TODOs introduced by this fix. - - Code follows existing project conventions. - -5. **Test Status** - - All existing tests pass. - - Build passes. - - No new flaky tests introduced. - -6. **PR Hygiene** - - Commits use the BUGFIX format: `Fix #: ...` or `[Bugfix #] ...` (**not** `[Spec NNNN][Phase]`). - - Branch is up to date with its base (or close enough for clean merge). - - PR is linked to the issue. - -## Out of Scope (Do NOT request changes for) - -The following are **not** part of the BUGFIX protocol and must **not** be cited as REQUEST_CHANGES reasons: - -- Missing `codev/specs/-*.md` — BUGFIX has no spec; the GitHub Issue is the spec. -- Missing `codev/plans/-*.md` — BUGFIX has no plan. -- Missing `codev/reviews/-*.md` — BUGFIX has no review document; review lives in the PR body. -- Commit format `[Spec NNNN][Phase]` — BUGFIX intentionally uses `Fix #N:` / `[Bugfix #N]`. -- `status.yaml` fields like `build_complete: false` — porch manages `status.yaml`; the builder is **forbidden** from editing it directly. Treat porch state as informational, not a fixable issue. -- Phase-scoping concerns — BUGFIX is a single-phase protocol; there are no plan phases to scope against. -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... - -PR_SUMMARY: | - ## Summary - Fixes #. [1-2 sentences on what was fixed.] - - ## Root Cause - [Brief explanation of what caused the bug] - - ## Fix - [Brief explanation of the fix] - - ## Test Plan - - [Regression test description] - - [Manual verification, if applicable] -``` - -**Verdict meanings:** -- `APPROVE`: Bug is resolved, regression test is in place, PR is ready for architect review. -- `REQUEST_CHANGES`: Real BUGFIX-relevant issues to fix (missing regression test, fix doesn't resolve the symptom, scope creep, etc.). -- `COMMENT`: Minor items, can proceed but note feedback. - -## Notes - -- This is the builder's final self-review before hand-off to the architect. -- The `PR_SUMMARY` block can be used directly as the PR description. -- Focus on "is this bug actually fixed and protected by a test" — not on artifacts from other protocols. diff --git a/codev/protocols/bugfix/prompts/fix.md b/codev/protocols/bugfix/prompts/fix.md deleted file mode 100644 index afecc3343..000000000 --- a/codev/protocols/bugfix/prompts/fix.md +++ /dev/null @@ -1,77 +0,0 @@ -# FIX Phase Prompt - -You are executing the **FIX** phase of the BUGFIX protocol. - -## Your Goal - -Implement the bug fix and add a regression test. Keep it minimal and focused. - -## Context - -- **Issue**: #{{issue.number}} — {{issue.title}} -- **Current State**: {{current_state}} - -## Process - -### 1. Implement the Fix - -Apply the minimum change needed to resolve the bug: -- Fix the root cause identified in the INVESTIGATE phase -- Do NOT refactor surrounding code -- Do NOT add features beyond what's needed -- Do NOT fix other bugs you happen to notice (file separate issues) - -**Code Quality**: -- Self-documenting code (clear names, obvious structure) -- No commented-out code or debug prints -- Follow existing project conventions - -### 2. Add a Regression Test - -**A regression test is MANDATORY.** Every bugfix MUST include a test unless you provide explicit justification for why a test is impossible (e.g., pure CSS-only change with no testable behavior). If you skip the test, you MUST explain why in your commit message and PR description. - -Write a test that: -- Fails without the fix (demonstrates the bug) -- Passes with the fix (demonstrates the fix works) -- Covers the specific scenario from the issue -- Is deterministic (not flaky) - -Place tests following project conventions (`__tests__/`, `*.test.ts`, etc.). - -### 3. Verify the Fix - -Run build and tests: - -```bash -npm run build # Must pass -npm test # Must pass -``` - -Fix any failures before proceeding. If build/test commands don't exist, check `package.json`. - -### 4. Commit - -Stage and commit your changes: -- Use explicit file paths (never `git add -A` or `git add .`) -- Commit message: `Fix #{{issue.number}}: ` - -## Signals - -When fix and tests are complete and passing: - -``` -PHASE_COMPLETE -``` - -If you encounter a blocker: - -``` -BLOCKED:reason goes here -``` - -## Important Notes - -1. **Minimal changes only** — Fix the bug, nothing else -2. **Regression test is MANDATORY** — No fix without a test. If truly untestable, justify in writing. -3. **Build AND tests must pass** — Don't signal complete until both pass -4. **Stay under 300 LOC** — If the fix grows beyond this, signal `TOO_COMPLEX` diff --git a/codev/protocols/bugfix/prompts/investigate.md b/codev/protocols/bugfix/prompts/investigate.md deleted file mode 100644 index ffa54385e..000000000 --- a/codev/protocols/bugfix/prompts/investigate.md +++ /dev/null @@ -1,77 +0,0 @@ -# INVESTIGATE Phase Prompt - -You are executing the **INVESTIGATE** phase of the BUGFIX protocol. - -## Your Goal - -Understand the bug, reproduce it, identify the root cause, and assess whether it's fixable within BUGFIX scope (< 300 LOC). - -## Context - -- **Issue**: #{{issue.number}} — {{issue.title}} -- **Current State**: {{current_state}} - -## Process - -### 1. Read the Issue - -Read the full issue description. Identify: -- What is the expected behavior? -- What is the actual behavior? -- Are there reproduction steps? -- Are there error messages or screenshots? - -### 2. Reproduce the Bug - -Before fixing anything, confirm the bug exists: -- Follow the reproduction steps from the issue -- If no steps are given, infer them from the description -- Document the exact reproduction steps you used -- If you **cannot** reproduce, signal `BLOCKED` with details - -### 3. Identify Root Cause - -Trace the bug to its source: -- Read the relevant code paths -- Use grep/search to find related code -- Identify the exact file(s) and line(s) causing the issue -- Understand **why** the bug occurs, not just **where** - -### 4. Assess Complexity - -Determine if this is BUGFIX-appropriate: -- **< 300 LOC change**: Proceed with BUGFIX -- **> 300 LOC or architectural**: Signal `TOO_COMPLEX` to escalate - -Consider: -- How many files need to change? -- Does it require new abstractions or refactoring? -- Are there cascading effects? - -## Output - -By the end of this phase, you should know: -1. The exact root cause -2. Which files need to change -3. The approximate size of the fix -4. Whether it's BUGFIX-appropriate - -## Signals - -When investigation is complete: - -``` -PHASE_COMPLETE -``` - -If the bug is too complex for BUGFIX: - -``` -TOO_COMPLEX -``` - -If you're blocked (can't reproduce, missing context, etc.): - -``` -BLOCKED:reason goes here -``` diff --git a/codev/protocols/bugfix/prompts/pr.md b/codev/protocols/bugfix/prompts/pr.md deleted file mode 100644 index d70d8dfdf..000000000 --- a/codev/protocols/bugfix/prompts/pr.md +++ /dev/null @@ -1,110 +0,0 @@ -# PR Phase Prompt - -You are executing the **PR** phase of the BUGFIX protocol. - -## Your Goal - -Create a pull request, run CMAP review, and address feedback. - -## Context - -- **Issue**: #{{issue.number}} — {{issue.title}} -- **Current State**: {{current_state}} - -## Process - -### 1. Create the Pull Request - -Create a PR that links to the issue. - -**PR body requirements**: The PR body MUST include `Fixes #` (where `` is -the driving issue number) so GitHub auto-closes the issue on merge. If the PR -fixes multiple issues (e.g. duplicates consolidated), include one `Fixes #` -per issue. Without this, GitHub will not auto-close the issue. - -**Exception**: if this PR only partially addresses the issue, use `Refs #` -or `Part of #` instead of `Fixes` — the issue stays open until a -follow-up PR closes it. - -**Note**: substitute the real issue number for `` — do not leave the -placeholder or any `{{...}}` template tag in the committed PR body. - -```bash -gh pr create --title "Fix #: " --body "$(cat <<'EOF' -## Summary - -<1-2 sentence description of the bug and fix> - -Fixes # - -## Root Cause - - - -## Fix - - - -## Test Plan - -- [ ] Regression test added -- [ ] Build passes -- [ ] All tests pass -EOF -)" -``` - -### 2. Run CMAP Review - -Run 3-way parallel consultation on the PR: - -```bash -consult -m gemini --protocol bugfix --type pr & -consult -m codex --protocol bugfix --type pr & -consult -m claude --protocol bugfix --type pr & -``` - -All three should run in the background (`run_in_background: true`). - -### 3. Wait for Results and Address Feedback - -**DO NOT proceed to step 4 until ALL THREE consultations have returned results.** - -Wait for each background consultation to complete, then read the results: -- Use `TaskOutput` (with `block: true`) to retrieve each consultation result -- Record each model's verdict (APPROVE or REQUEST_CHANGES) -- Fix any issues identified by reviewers -- Push updates to the PR branch -- Re-run CMAP if substantial changes were made - -You must have three concrete verdicts (e.g., "gemini: APPROVE, codex: APPROVE, claude: APPROVE") before continuing. - -### 4. Notify Architect - -**DO NOT send this notification until you have all three CMAP verdicts from step 3.** - -Send a **single** notification that includes the PR link and each model's verdict: - -```bash -afx send architect "PR # ready for review (fixes issue #{{issue.number}}). CMAP: gemini=, codex=, claude=" -``` - -Then run `porch done ` to auto-request the `pr` gate. The PR surfaces -in Needs Attention from this point; **STOP and wait** for the architect to call -`porch approve pr`. After gate approval, porch will emit a merge task -(via the next `porch next` call) — follow it to merge the PR and advance to -`verified`. - -## Signals - -When PR is created and reviews are complete: - -``` -PHASE_COMPLETE -``` - -If you're blocked: - -``` -BLOCKED:reason goes here -``` diff --git a/codev/protocols/bugfix/protocol.json b/codev/protocols/bugfix/protocol.json deleted file mode 100644 index cac575cbd..000000000 --- a/codev/protocols/bugfix/protocol.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "bugfix", - "version": "1.2.0", - "description": "Lightweight protocol for minor bugfixes using GitHub Issues", - "input": { - "type": "github-issue", - "required": false, - "default_for": ["--issue", "-i"] - }, - "hooks": { - "pre-spawn": { - "collision-check": true, - "comment-on-issue": "On it! Working on a fix now." - } - }, - "phases": [ - { - "id": "investigate", - "name": "Investigate", - "description": "Understand the bug and its root cause", - "type": "once", - "steps": [ - "read_issue", - "reproduce_bug", - "identify_root_cause", - "assess_complexity" - ], - "transition": { - "on_complete": "fix", - "on_too_complex": "escalate" - } - }, - { - "id": "fix", - "name": "Fix", - "description": "Implement the bug fix", - "type": "once", - "steps": [ - "implement_fix", - "add_tests", - "verify_fix", - "commit" - ], - "checks": { - "regression_test": { - "description": "A regression test MUST be added unless explicitly justified. No fix without a test.", - "required": true, - "skip_requires_justification": true - }, - "build": { - "command": "npm run build", - "cwd": "packages/codev", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "npm test", - "cwd": "packages/codev", - "on_fail": "retry", - "max_retries": 2 - } - }, - "transition": { - "on_complete": "pr" - } - }, - { - "id": "pr", - "name": "Create PR", - "description": "Create pull request for the fix", - "type": "once", - "steps": [ - "create_pr", - "link_issue", - "request_review" - ], - "consultation": { - "on": "review", - "models": ["gemini", "codex"], - "type": "impl", - "parallel": true, - "max_rounds": 1 - }, - "gate": "pr", - "transition": { - "on_complete": null - } - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current phase is complete", - "transitions_to": "next_phase" - }, - "TOO_COMPLEX": { - "description": "Bug is too complex for BUGFIX, escalate to SPIR", - "transitions_to": "escalate" - }, - "BLOCKED": { - "description": "Signal fix is blocked", - "requires": "reason" - } - }, - "defaults": { - "mode": "strict", - "consultation": { - "enabled": true, - "models": ["gemini", "codex"], - "parallel": true - }, - "checks": { - "build": "npm run build", - "test": "npm test" - } - } -} diff --git a/codev/protocols/experiment/builder-prompt.md b/codev/protocols/experiment/builder-prompt.md deleted file mode 100644 index 31c5581e5..000000000 --- a/codev/protocols/experiment/builder-prompt.md +++ /dev/null @@ -1,82 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are executing a disciplined experiment. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the EXPERIMENT protocol yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Document your findings thoroughly -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -{{/if}} - -## Protocol -Follow the EXPERIMENT protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## EXPERIMENT Overview -The EXPERIMENT protocol ensures disciplined experimentation: - -1. **Hypothesis Phase**: Define what you're testing and success criteria -2. **Design Phase**: Plan the experiment approach -3. **Execute Phase**: Run the experiment and gather data -4. **Analyze Phase**: Evaluate results and draw conclusions - -{{#if task}} -## Experiment Focus -{{task_text}} -{{/if}} - -## Key Principles -- Start with a clear, falsifiable hypothesis -- Define success/failure criteria upfront -- Keep scope minimal for quick iteration -- Document findings regardless of outcome -- Separate experiment artifacts from production code - -## If You Open a PR - -Most experiments are committed to a branch without a PR, but if you do open one -to integrate findings and the experiment was triggered by a GitHub issue: - -**PR body requirements**: The PR body MUST include `Closes #` (for feature -issues) or `Fixes #` (for bug issues) for the driving issue so GitHub -auto-closes it on merge. If the PR closes multiple issues, include one keyword -per issue. - -**Exception**: if this PR only partially addresses the issue (e.g. experiment -validates an approach but production implementation is deferred), use -`Refs #` or `Part of #` instead — the issue stays open until a follow-up -PR closes it. - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the EXPERIMENT protocol document -2. Define your hypothesis clearly -3. Follow the phases in order - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/experiment/protocol.json b/codev/protocols/experiment/protocol.json deleted file mode 100644 index ed04446ec..000000000 --- a/codev/protocols/experiment/protocol.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "experiment", - "version": "1.0.0", - "description": "Disciplined experimentation with hypothesis testing", - "input": { - "type": "none", - "required": false, - "default_for": [] - }, - "hooks": { - "pre-spawn": {} - }, - "phases": [ - { - "id": "hypothesis", - "name": "Hypothesis", - "description": "Define the hypothesis and success criteria", - "type": "once", - "steps": [ - "define_hypothesis", - "define_success_criteria", - "define_scope", - "create_experiment_doc" - ], - "transition": { - "on_complete": "design" - } - }, - { - "id": "design", - "name": "Design", - "description": "Design the experiment approach", - "type": "once", - "steps": [ - "choose_approach", - "identify_dependencies", - "plan_implementation", - "define_measurements" - ], - "transition": { - "on_complete": "execute" - } - }, - { - "id": "execute", - "name": "Execute", - "description": "Run the experiment", - "type": "once", - "steps": [ - "implement_prototype", - "gather_data", - "document_findings" - ], - "transition": { - "on_complete": "analyze" - } - }, - { - "id": "analyze", - "name": "Analyze", - "description": "Analyze results and draw conclusions", - "type": "once", - "steps": [ - "analyze_data", - "evaluate_hypothesis", - "document_conclusions", - "recommend_next_steps" - ], - "gate": { - "name": "experiment-complete", - "description": "Experiment complete", - "requires": ["conclusions_documented"], - "next": null - } - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current phase is complete", - "transitions_to": "next_phase" - }, - "BLOCKED": { - "description": "Signal experiment is blocked", - "requires": "reason" - }, - "HYPOTHESIS_REJECTED": { - "description": "Signal hypothesis was disproven", - "transitions_to": "analyze" - } - }, - "defaults": { - "mode": "soft", - "consultation": { - "enabled": false, - "models": [], - "parallel": false - }, - "checks": {} - } -} diff --git a/codev/protocols/experiment/templates/notes.md b/codev/protocols/experiment/templates/notes.md deleted file mode 100644 index 18e1c63f6..000000000 --- a/codev/protocols/experiment/templates/notes.md +++ /dev/null @@ -1,97 +0,0 @@ -# Experiment ####: Name - -**Status**: In Progress | Complete | Disproved | Aborted - -**Date**: YYYY-MM-DD - -## Goal - -What are you trying to learn or test? Be specific about: -- The question you're answering -- The hypothesis you're testing -- Success criteria (how will you know if it worked?) - -## Effort - -**Approximate time spent**: [e.g., "4 hours"] - -*(Optional: Break down into setup, coding, analysis if helpful)* - -## Approach - -Brief description of the approach being tested: -- Key technique or method -- Why this approach was chosen -- Any alternatives considered - -## Environment & Reproduction - -**How to run**: -```bash -# Command to reproduce results -python experiment.py --input data/input/sample.json -``` - -**Dependencies** (if different from main project): -- List any additional packages required -- Or reference: `pip install -r requirements.txt` - -**Environment notes**: -- Python version, key library versions if relevant -- Any seeds or configuration needed for reproducibility - -## Code - -List your experiment files: -- [`experiment.py`](experiment.py) - Brief description -- [Other files as needed] - -## Results - -### Summary - -One-paragraph summary of key findings. - -### Key Findings - -1. **Finding one**: Description and significance -2. **Finding two**: Description and significance -3. **Finding three**: Description and significance - -### Metrics - -| Metric | Value | Notes | -|--------|-------|-------| -| Metric 1 | Value | Context | -| Metric 2 | Value | Context | - -### Output Files - -- `data/output/results.csv` - Raw results data -- `data/output/chart.png` - Visualization of findings - -## What Worked - -- List things that went well -- Approaches that proved effective -- Useful discoveries - -## What Didn't Work - -- Failed approaches (and why) -- Dead ends encountered -- Surprising obstacles - -## Next Steps - -Based on these findings: - -1. **Immediate**: What should happen right after this experiment? -2. **Follow-up experiments**: What new questions emerged? -3. **Production path**: If validated, what's needed for production? (SPIR spec?) - -## References - -- Links to relevant documentation -- Related experiments -- External resources consulted diff --git a/codev/protocols/maintain/builder-prompt.md b/codev/protocols/maintain/builder-prompt.md deleted file mode 100644 index 6a2deda0d..000000000 --- a/codev/protocols/maintain/builder-prompt.md +++ /dev/null @@ -1,62 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are executing the MAINTAIN protocol to clean up and synchronize the codebase. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the MAINTAIN protocol yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Work through each step methodically -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -{{/if}} - -## Protocol -Follow the MAINTAIN protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## MAINTAIN Overview - -Two phases: -1. **Maintain**: Single pass — audit findings, clean dead code, sync docs, verify build -2. **Review**: Create PR with 3-way consultation - -## Key Rules -- Use soft deletion (move to `codev/maintain/.trash/`) -- Verify build passes after each removal (`cd packages/codev && pnpm build && pnpm test`) -- Update documentation to match current architecture -- Don't remove anything actively used -- One removal at a time — commit after each -- Document every deletion with justification -- Never use `git add -A` or `git add .` - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your maintenance run file -5. Commit the skip and continue with your work - -## Getting Started -1. Read the MAINTAIN protocol document -2. Run `porch next` to get your first task -3. Work through audit → clean → sync → verify in a single pass -4. Document everything in the maintenance run file - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/maintain/consult-types/impl-review.md b/codev/protocols/maintain/consult-types/impl-review.md deleted file mode 100644 index de01b8d00..000000000 --- a/codev/protocols/maintain/consult-types/impl-review.md +++ /dev/null @@ -1,72 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work during the Implement phase. A builder has completed a plan phase and needs feedback before proceeding. Your job is to verify the implementation matches the spec and plan. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Spec Adherence** - - Does the implementation fulfill the spec requirements for this phase? - - Are acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate for this phase? - - Do tests cover the main paths AND edge cases? - -4. **Plan Alignment** - - Does the implementation follow the plan? - - Are there plan items skipped or partially completed? - -5. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - If spec says "async" or "non-blocking", is it actually async? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Phase is complete, builder can proceed -- `REQUEST_CHANGES`: Issues that must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scoping (Multi-Phase Plans) - -When the implementation plan has multiple phases (e.g., scaffolding, landing, media_rtl): -- **ONLY review work belonging to the current plan phase** -- The query will specify which phase you are reviewing -- Do NOT request changes for functionality scheduled in later phases -- Do NOT flag missing features that are out of scope for this phase -- If unsure whether something belongs to this phase, check the plan file - -## Notes - -- This is a phase-level review, not the final PR review -- Focus on "does this phase work" not "is the whole feature done" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to continue diff --git a/codev/protocols/maintain/consult-types/pr-review.md b/codev/protocols/maintain/consult-types/pr-review.md deleted file mode 100644 index 837cdea33..000000000 --- a/codev/protocols/maintain/consult-types/pr-review.md +++ /dev/null @@ -1,76 +0,0 @@ -# PR Ready Review Prompt - -## Context -You are performing a final self-check during the Review phase. The builder has completed all implementation phases and is about to create a PR. This is the last check before the work goes to the architect for integration review. - -## Focus Areas - -1. **Completeness** - - Are all spec requirements implemented? - - Are all plan phases complete? - - Is the review document written (`codev/reviews/XXXX-name.md`)? - - Are all commits properly formatted (`[Spec XXXX][Phase]`)? - -2. **Test Status** - - Do all tests pass? - - Is test coverage adequate for the changes? - - Are there any skipped or flaky tests? - -3. **Code Cleanliness** - - Is there any debug code left in? - - Are there any TODO comments that should be resolved? - - Are there any `// REVIEW:` comments that weren't addressed? - - Is the code properly formatted? - -4. **Documentation** - - Are inline comments clear where needed? - - Is the review document comprehensive? - - Are any new APIs documented? - -5. **PR Readiness** - - Is the branch up to date with its base (the integration branch the PR targets)? - - Are commits atomic and well-described? - - Is the change diff reasonable in size? - -## Scope - -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption or "How to Test Locally" section). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... - -PR_SUMMARY: | - ## Summary - [2-3 sentences describing what this PR does] - - ## Key Changes - - [Change 1] - - [Change 2] - - ## Test Plan - - [How to test] -``` - -**Verdict meanings:** -- `APPROVE`: Ready to create PR -- `REQUEST_CHANGES`: Issues to fix before PR creation -- `COMMENT`: Minor items, can create PR but note feedback - -## Notes - -- This is the builder's final self-review before hand-off -- The PR_SUMMARY in your output can be used as the PR description -- Focus on "is this ready for someone else to review" not "is this perfect" -- Any issues found here are cheaper to fix than during integration review diff --git a/codev/protocols/maintain/prompts/maintain.md b/codev/protocols/maintain/prompts/maintain.md deleted file mode 100644 index 3c83f404d..000000000 --- a/codev/protocols/maintain/prompts/maintain.md +++ /dev/null @@ -1,89 +0,0 @@ -# MAINTAIN Phase Prompt - -You are executing the **maintain** phase — a single pass covering audit, cleanup, and doc sync. - -## Context - -- **Current State**: {{current_state}} - -## Step 1: Determine Scope - -```bash -ls codev/maintain/ -``` - -Find the last run number and its base commit. Then see what changed: - -```bash -git log --oneline ..HEAD -``` - -Create your maintenance run file: `codev/maintain/NNNN.md` (next number in sequence). - -## Step 2: Audit - -Identify dead code, unused dependencies, and stale documentation. Don't fix yet — catalog first. - -```bash -# Dead exports -npx ts-prune 2>/dev/null || echo "ts-prune not available" - -# Unused dependencies -npx depcheck 2>/dev/null || echo "depcheck not available" - -# Stale arch.md references -grep -oE '[a-zA-Z]+/[a-zA-Z/]+\.[a-z]+' codev/resources/arch.md | sort -u | while read f; do - [ -e "$f" ] || echo "Missing: $f" -done -``` - -Record all findings in the maintenance run file. - -## Step 3: Clean - -For each audit finding: -1. Verify it's truly unused (grep the codebase) -2. Remove with `git rm` (tracked) or move to `codev/maintain/.trash/$(date +%Y-%m-%d)/` (untracked) -3. Build and test: `cd packages/codev && pnpm build && pnpm test` -4. Commit: `git add && git commit -m "[Maintain] Remove unused X"` - -One removal at a time. Verify after each. Never use `git add -A`. - -## Step 4: Sync Documentation - -**arch.md / arch-critical.md** (Spec 987 two-tier): Read both, compare with actual codebase. Route behavior-changing invariants to the HOT `arch-critical.md` (respect its cap + keep its cold-doc map accurate); reference detail to the COLD `arch.md` (directory structure, component descriptions, key files, removals). Explain HOW things work, not just WHAT. - -**lessons-learned.md / lessons-critical.md** (two-tier): Scan `codev/reviews/` for new reviews since the base commit. **Route** each lesson — behavior-changing + cross-cutting → HOT `lessons-critical.md` (cap + displacement); reference recipe → COLD `lessons-learned.md`. Audit the hot caps + maps via the `update-arch-docs` skill. - -**CLAUDE.md / AGENTS.md**: `diff CLAUDE.md AGENTS.md` — they must be identical. Update the stale one. - -**Pruning**: Remove obsolete content. Document every deletion with justification (OBSOLETE, DUPLICATIVE, MOVED, VERBOSE). When in doubt, keep. - -Commit documentation changes: -```bash -git add codev/resources/arch.md codev/resources/arch-critical.md -git add codev/resources/lessons-learned.md codev/resources/lessons-critical.md -git commit -m "[Maintain] Update governance docs (hot + cold tiers)" -``` - -## Step 5: Final Checks - -```bash -cd packages/codev && pnpm build && pnpm test -``` - -Both must pass. Update the maintenance run file with a summary of everything done. - -## Signals - -When all work is complete and build/tests pass: - -``` -PHASE_COMPLETE -``` - -If blocked: - -``` -BLOCKED:reason -``` diff --git a/codev/protocols/maintain/prompts/review.md b/codev/protocols/maintain/prompts/review.md deleted file mode 100644 index c61e05fd5..000000000 --- a/codev/protocols/maintain/prompts/review.md +++ /dev/null @@ -1,84 +0,0 @@ -# REVIEW Phase Prompt - -You are executing the **review** phase of the MAINTAIN protocol. - -## Context - -- **Current State**: {{current_state}} - -## Process - -### 1. Final Validation - -```bash -cd packages/codev && pnpm build && pnpm test -``` - -Both must pass. If either fails, fix before proceeding. - -### 2. Verify Documentation Links - -```bash -grep -oE '[a-zA-Z]+/[a-zA-Z/]+\.[a-z]+' codev/resources/arch.md | sort -u | while read f; do - [ -e "$f" ] || echo "Missing: $f" -done -``` - -### 3. Finalize Maintenance Run File - -Update `codev/maintain/NNNN.md` with: -- PR number (once created) -- Final summary of what was done -- Deferred items (if any) - -### 4. Create PR - -**PR body requirements**: If this maintenance run was triggered by a GitHub issue -(e.g. "track down dead X", "clean up Y module"), the PR body MUST include -`Closes #` for that issue so GitHub auto-closes it on merge. If multiple -issues are addressed in one run, include one `Closes #` per issue. - -**Exception**: if this PR only partially addresses a tracking issue (e.g. more -cleanup passes are planned), use `Refs #` or `Part of #` instead. - -If the run was not tied to any issue, the `Closes` line can be omitted. - -```bash -git push origin HEAD - -gh pr create --title "[Maintain] Codebase maintenance run NNNN" --body "$(cat <<'PREOF' -## Summary - -<2-3 bullet points of what was done> - -Closes # - -## Changes - -- Dead code removed: X items -- Dependencies cleaned: Y packages -- Documentation updated: arch.md / arch-critical.md, lessons-learned.md / lessons-critical.md (hot + cold tiers; hot caps + cold-doc maps policed) -- Tests: all passing - -## Test plan - -- [x] Build passes -- [x] All tests pass -- [x] Documentation links resolve -PREOF -)" -``` - -## Signals - -When PR is created: - -``` -PHASE_COMPLETE -``` - -If blocked: - -``` -BLOCKED:reason -``` diff --git a/codev/protocols/maintain/protocol.json b/codev/protocols/maintain/protocol.json deleted file mode 100644 index 3dadcd91c..000000000 --- a/codev/protocols/maintain/protocol.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "maintain", - "alias": "maint", - "version": "3.0.0", - "description": "Codebase maintenance — single-pass hygiene, doc sync, and cleanup with PR review", - "input": { - "type": "protocol", - "required": false, - "default_for": ["--protocol maintain"] - }, - "phases": [ - { - "id": "maintain", - "name": "Maintain", - "description": "Single-pass: audit, clean dead code, sync docs, verify build", - "type": "build_verify", - "build": { - "prompt": "maintain.md", - "artifact": "codev/maintain/*.md" - }, - "verify": { - "type": "impl", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 5, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "build": { - "command": "pnpm build", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "pnpm test", - "on_fail": "retry", - "max_retries": 2 - } - }, - "next": "review" - }, - { - "id": "review", - "name": "Review", - "description": "Final validation, PR creation, 3-way review", - "type": "build_verify", - "build": { - "prompt": "review.md", - "artifact": "codev/maintain/*.md" - }, - "verify": { - "type": "pr", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 3, - "on_complete": { - "commit": true, - "push": true - }, - "gate": "maintain-complete", - "next": null - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current phase is complete", - "transitions_to": "review" - }, - "BLOCKED": { - "description": "Signal maintenance is blocked", - "requires": "reason" - } - }, - "defaults": { - "mode": "strict", - "max_iterations": 5, - "verify": { - "models": ["gemini", "codex", "claude"], - "parallel": true - } - } -} diff --git a/codev/protocols/maintain/templates/maintenance-run.md b/codev/protocols/maintain/templates/maintenance-run.md deleted file mode 100644 index 189c478be..000000000 --- a/codev/protocols/maintain/templates/maintenance-run.md +++ /dev/null @@ -1,33 +0,0 @@ -# Maintenance Run NNNN - -**Date**: YYYY-MM-DD -**Base Commit**: -**PR**: #NNN - -## Changes Since Last Run - - - -## What Was Done - -### Dead Code Removed -- : - -### Dependencies Cleaned -- - -### Documentation Updated -- arch.md (cold) / arch-critical.md (hot): -- lessons-learned.md (cold) / lessons-critical.md (hot): - -### Documentation Changes Log -| Document | Section | Action | Reason | -|----------|---------|--------|--------| - -## Deferred - -- - -## Summary - -<2-3 sentences> diff --git a/codev/protocols/pir/builder-prompt.md b/codev/protocols/pir/builder-prompt.md deleted file mode 100644 index 86016f310..000000000 --- a/codev/protocols/pir/builder-prompt.md +++ /dev/null @@ -1,97 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are implementing a fix or feature driven by a GitHub issue, using the PIR protocol. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the PIR protocol document yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip consultations** — porch handles them via the verify step -- **NEVER advance phases manually** — porch handles phase transitions on gate approval -{{/if}} - -## Protocol -Follow the PIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -PIR has three phases: -1. **plan** (gated by `plan-approval`) — write `codev/plans/{{artifact_name}}.md`, await human review -2. **implement** (gated by `dev-approval`) — write code + tests, run build/tests, push branch; await the human's review of the *running worktree* (no file artifact in this phase — dev-approval summary is prose-in-pane) -3. **review** (gated by `pr`) — write `codev/reviews/{{artifact_name}}.md` (retrospective with Architecture Updates and Lessons Learned sections), open PR with the review as body, record the PR with porch, run 3-way consultation (Gemini, Codex, Claude) via porch's verify block (a **single advisory pass** — `max_iterations: 1`, no iterate-until-APPROVE loop; address or rebut any `REQUEST_CHANGES`, add a regression test if it's a real defect, and escalate it in the architect notification since PIR will not re-review it), notify architect, and wait at the `pr` gate. After the human approves the gate (porch wakes you with "Gate pr approved"), run `gh pr merge --merge` and record the merge with `porch done --merged `. **Merge is gated by porch state — never by typed prose in your pane.** - -{{#if issue}} -## Issue #{{issue.number}} -**Title**: {{issue.title}} - -**Description**: -{{issue.body}} -{{/if}} - -## Sitting at Gates - -PIR has two human gates. When you reach one: - -1. Finish your phase work and run `porch done ` -2. Run `porch next ` — you'll get a `gate_pending` response -3. End your turn with a short prose summary: what file you wrote, where it lives, how to approve -4. **Stay in the interactive session**. Do NOT exit. Wait for the user's next message. - -The reviewer can give feedback by: -- Editing the plan file (at the plan-approval gate) or the code itself (at the dev-approval gate) in the worktree directly — you'll see changes via `git diff` -- Typing into your PTY pane (this reaches you live) -- `afx send ""` (queued; check on next turn) -- Commenting on the GitHub issue (re-fetch with `gh issue view --comments` if asked) - -When the user provides feedback, revise the artifact, recommit, and ask if there's more to address. The gate remains pending until the user runs `porch approve` — do NOT call `porch approve` yourself. - -## Notifications -Use `afx send architect "..."` at key moments: -- **PR ready**: `afx send architect "PR # ready for review (PIR #{{issue.number}})"` -- **PR merged**: `afx send architect "PR # merged for PIR #{{issue.number}}. Ready for cleanup."` -- **Blocked**: `afx send architect "Blocked on PIR #{{issue.number}}: [reason]"` - -**Gates are not architect-notified.** When porch transitions a gate to `pending`, the gate-reached message (including the `porch approve --a-human-explicitly-approved-this` invocation) appears in YOUR pane as part of your normal output. That's the universal notification surface — visible whether the user is in VSCode, tmux, plain Terminal, or any other host. The user reads it directly from your pane (or runs `porch pending` from a shell) and approves themselves; the architect can't approve gates, so notifying it would be informational noise. - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in the review file under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Resumption After Crash - -If your Claude session crashes mid-flow, Tower's `while true` loop will relaunch you with the same prompt. On startup: - -1. Run `porch next {{project_id}}` to learn what phase you're in -2. If `gate_pending`: read the latest plan file (plan-approval) or `DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||'); git diff "$(git merge-base "${DEFAULT_BRANCH:-main}" HEAD)"` (dev-approval) plus any new GitHub issue comments; check `afx send` queue. Decide whether to revise or just announce you're back. -3. Otherwise: pick up where you left off - -## Getting Started - -1. Read the PIR protocol (provided inline in this prompt). -2. Run `porch next {{project_id}}` to see what to do next -3. Begin work - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/pir/consult-types/impl-review.md b/codev/protocols/pir/consult-types/impl-review.md deleted file mode 100644 index 380bceee9..000000000 --- a/codev/protocols/pir/consult-types/impl-review.md +++ /dev/null @@ -1,78 +0,0 @@ -# Implementation Review Prompt (PIR) - -## Context - -You are reviewing the implementation of a PIR protocol project before it reaches the `dev-approval` human gate. A builder has implemented the approved plan and written a dev-approval summary. Your job is to verify the implementation matches the plan and is ready for human review. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Plan Adherence** - - Does the implementation fulfill the approved plan? - - Are all "Files to Change" actually changed? - - Are the changes scoped to what the plan described, or has scope crept? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs? - - Are error cases handled appropriately? - - Is the change minimal — no unnecessary refactoring or unrelated tidy-ups? - -3. **Test Coverage** - - Are the tests adequate for the changes? - - Do tests cover both the main path and the edge cases the plan called out? - - For a bug fix: is there a regression test that would fail without the fix? - -4. **Review File Quality** - - Does `codev/reviews/-.md` exist and follow the template? - - Does it accurately describe what changed? - - Is "Things to Look At" honest about tricky spots? - - Is "How to Test Locally" specific enough that the human reviewer can act on it? - -5. **PIR-Specific Concerns** - - For UI / mobile / cross-platform changes: does the review file explain platform-specific behavior the human should verify? - - For changes with external integrations: are the integration points documented? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Ready for human at the `dev-approval` gate -- `REQUEST_CHANGES`: Issues that must be fixed before reaching the human -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scope - -- **DO** review the implementation against the approved plan -- **DO** flag missing regression tests for bug fixes -- **DO** flag obvious bugs, code smells, security issues -- **DO NOT** redesign the approach — that was settled at `plan-approval` -- **DO NOT** demand changes outside the plan's scope -- **DO NOT** request architecture-level refactors unless the change introduces a clear new problem - -## Notes - -- This is a pre-gate review; the human is the final authority -- Focus on "is this ready for someone else to test in a browser / simulator" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to iterate diff --git a/codev/protocols/pir/consult-types/pr-review.md b/codev/protocols/pir/consult-types/pr-review.md deleted file mode 100644 index cf49c3a05..000000000 --- a/codev/protocols/pir/consult-types/pr-review.md +++ /dev/null @@ -1,66 +0,0 @@ -# PR Review Prompt (PIR) - -## Context - -You are performing the 3-way review of a PIR protocol PR. The builder has implemented an approved plan, the human has approved the `dev-approval` gate (meaning a human has run the code locally and tested it), and the PR has been opened. This is a single advisory pass (`max_iterations: 1`) — your verdict is surfaced to the human at the `pr` gate, who is the sole remaining reviewer; it is not auto-re-reviewed. - -## Focus Areas - -1. **Completeness** - - Is the PR body the review file content + `Fixes #`? - - Are all commits properly formatted (`[PIR #] ...`)? - - Does the diff match what the review file describes? - -2. **Test Status** - - Do all tests pass on the branch? - - Is test coverage adequate for the change? - - Are there skipped or flaky tests documented? - -3. **Code Quality** - - Any debug code left in? - - Any TODO comments that should be resolved? - - Any `// REVIEW:` markers that weren't addressed? - -4. **Branch Hygiene** - - Is the branch up to date with the default branch? (If not, suggest a rebase. The default branch is whatever `git symbolic-ref --short refs/remotes/origin/HEAD` reports — typically `main`, but may be `dev`, `ci`, etc.) - - Are commits atomic and well-described? - - Is the change diff a reasonable size for the issue scope? - -5. **Issue Linkage** - - Does the PR body contain `Fixes #` (or `Refs #` for partial fixes)? - - Without this, GitHub won't auto-close the issue on merge - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Ready to merge -- `REQUEST_CHANGES`: Issues to fix before merging -- `COMMENT`: Minor items, can merge but note feedback - -## Scope - -- **DO** flag missing `Fixes #` lines -- **DO** flag obvious problems the human reviewer at the gate might have missed -- **DO NOT** redesign the approach — that was settled at `plan-approval` and validated at `dev-approval` -- **DO NOT** demand changes the human reviewer already accepted at the `dev-approval` gate (the human ran the code and approved it; you didn't) -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption or "How to Test Locally" section). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Notes - -- The human at the `dev-approval` gate is the primary reviewer for behavior; you are the secondary reviewer for hygiene and edge cases -- Focus on "what would an integration reviewer catch that the gate reviewer missed" -- If referencing line numbers, use `file:line` format diff --git a/codev/protocols/pir/prompts/implement.md b/codev/protocols/pir/prompts/implement.md deleted file mode 100644 index 9d7f88a8c..000000000 --- a/codev/protocols/pir/prompts/implement.md +++ /dev/null @@ -1,164 +0,0 @@ -# IMPLEMENT Phase Prompt - -You are executing the **IMPLEMENT** phase of the PIR protocol. - -## Your Goal - -Implement the approved plan, write tests, and pause at the `dev-approval` gate so the human can verify behavior by running the worktree locally. No file artifact is produced in this phase — the retrospective (review file) is written in the next phase, after the human has approved the running code. - -## Context - -- **Project ID**: {{project_id}} -- **Issue Number**: #{{issue.number}} -- **Issue Title**: {{issue.title}} -- **Plan File**: `codev/plans/{{artifact_name}}.md` (already approved) - -## Resumption Check (do this FIRST) - -Run `porch next {{project_id}}`. If the response is `gate_pending` on `dev-approval`, the code is already written and you're awaiting review. In that case: - -1. Resolve your repo's default branch and the merge-base. The merge-base anchors the diff at the branch's fork point, so commits the base branch picked up *after* you branched don't show up as phantom "scope creep". (`DEFAULT_BRANCH` falls back to `main` if `origin/HEAD` isn't set.) - - ```bash - DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||') - DEFAULT_BRANCH=${DEFAULT_BRANCH:-main} - MERGE_BASE=$(git merge-base "$DEFAULT_BRANCH" HEAD) - ``` - -2. Check for feedback: - - `git diff "$MERGE_BASE"` — has the reviewer made any direct edits to your code? - - `gh issue view {{issue.number}} --comments` - - `afx send` queue messages -3. If feedback requires code changes: make them, re-run build + tests, recommit. -4. If feedback is a discussion question: respond and stay in the session. - -Otherwise (`tasks` response — first run), continue below. - -## Process - -### 1. Re-Read the Plan - -```bash -cat codev/plans/{{artifact_name}}.md -``` - -The plan is your authoritative scope. Stick to it. If you discover the plan is wrong while implementing, stop and signal `BLOCKED` rather than silently deviating. - -### 2. Implement the Code - -Follow the plan's "Files to Change" section. Apply the changes. - -**Code quality standards:** -- Self-documenting code (clear names, obvious structure) -- No commented-out code -- No debug prints -- Explicit error handling -- Follow project style guide - -**Commit cadence:** commit each logical unit separately. Use the format: - -``` -[PIR #{{issue.number}}] -``` - -**Never use `git add .` or `git add -A`.** Stage files explicitly: - -```bash -git add path/to/changed-file.ts -git commit -m "[PIR #{{issue.number}}] ..." -``` - -### 3. Write Tests - -The plan's "Test Plan" section lists what to verify. Write the corresponding tests: - -- Unit tests for new functions -- Integration tests for cross-component flows -- Regression tests for any bug fixes - -**Test quality:** -- Test behavior, not implementation -- Avoid overmocking — only mock external dependencies (APIs, databases, file systems) -- Use real implementations for internal module boundaries - -### 4. Verify Everything Works - -```bash -npm run build # or project equivalent -npm test # or project equivalent -``` - -Both MUST pass before signaling phase complete. If a test is flaky (intermittent failure unrelated to your changes), skip it with annotation — you'll document each skipped test in the review file in the next phase. - -**Flaky ≠ pre-existing unrelated failure.** If the suite surfaces a *deterministic* failure your diff did not cause (e.g., a stale test broken by another team's earlier refactor, or a type error in an unrelated package), that is **out of scope** — do not fix it, skip it, or quarantine it to force a green. Note it for the review file's Lessons Learned and proceed. Porch's gate `checks` are narrow structural assertions, not a full-suite proof; making an unrelated red go green is scope creep, not diligence. - -### 5. Push Your Branch - -```bash -git push -u origin "$(git branch --show-current)" -``` - -So the reviewer can pull / inspect from elsewhere if they want. - -### 6. Signal Phase Complete - -```bash -porch done {{project_id}} -porch next {{project_id}} -``` - -PIR's `implement` phase has no AI consult — the `dev-approval` gate becomes pending immediately, and the human is the sole reviewer of the running code. (The 3-way consultation runs later, in the `review` phase, after the human approves the gate and the PR is opened.) - -### 7. End Your Turn With a Code-Review Summary (Prose, Not a File) - -When the gate goes pending, output a short prose summary in the pane to orient the human reviewer. This is **not** a committed file — it's a transient message to help them inspect the change. Structure: - -> **What changed**: 2–3 sentence summary. -> -> **Files**: `git diff --stat "$MERGE_BASE"` style list — paths and +/-. (Resolve `$MERGE_BASE` once per session: `DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||'); DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}; MERGE_BASE=$(git merge-base "$DEFAULT_BRANCH" HEAD)`. Anchoring at the merge-base excludes commits the base branch picked up after you branched.) -> -> **Test results**: `npm run build` ✓, `npm test` ✓ (X tests, Y new). -> -> **Things to look at**: tricky spots, platform-specific behavior, anything you want the reviewer to focus on. -> -> **How to test locally**: VSCode → right-click builder → **Run Dev**, or `afx dev pir-{{project_id}}`. View diff via VSCode → **View Diff** (auto-detects the repo's default branch). -> -> Ready for review — type feedback here, or approve with `porch approve {{project_id}} dev-approval --a-human-explicitly-approved-this` (Cmd+K G in VSCode). - -Then **stay in the interactive session**. Do not exit. Wait for the user's next message. - -(Optional: if your team prefers an issue-thread record, you can also post a one-line comment on the GitHub issue pointing reviewers at the worktree branch. The summary itself stays in the pane — don't duplicate it as a committed file. That's the next phase's job, and that file will be a proper retrospective with arch + lessons updates, not a transient dev-approval note.) - -## Signals - -``` -PHASE_COMPLETE # Implementation + tests done; dev-approval gate becomes pending -BLOCKED:reason # Cannot proceed -``` - -## What NOT to Do - -- **Don't write `codev/reviews/-.md` in this phase** — it's the next phase's artifact, with a different shape (retrospective with arch + lessons updates) -- Don't add features not in the plan — scope creep is a `BLOCKED` signal, not a free expansion -- Don't run `porch approve` yourself -- Don't push to the default branch — only to your builder branch -- Don't squash commits — let the merge commit preserve history -- Don't use `git add .` or `git add -A` -- Don't open the PR yet — that's the `review` phase -- Don't exit the interactive session at the gate - -## Handling Feedback at the Gate - -The reviewer will run your code via `afx dev` and test it. They may: - -- Approve immediately → porch advances to the `review` phase -- Type feedback in the pane / send via `afx send` / edit code in the worktree / comment on the issue -- Ask clarifying questions about specific files or behaviors - -When they provide feedback: - -1. If it's code feedback: make the change, run build + tests, recommit -2. If it's a discussion question: answer it in the pane -3. Don't re-run `porch done` unless porch's `verify` block needs to re-validate — porch will tell you - -The gate stays pending until the human approves. diff --git a/codev/protocols/pir/prompts/plan.md b/codev/protocols/pir/prompts/plan.md deleted file mode 100644 index a40cdee2d..000000000 --- a/codev/protocols/pir/prompts/plan.md +++ /dev/null @@ -1,133 +0,0 @@ -# PLAN Phase Prompt - -You are executing the **PLAN** phase of the PIR protocol. - -## Your Goal - -Read the GitHub issue, investigate the codebase, and write a plan to `codev/plans/{{artifact_name}}.md`. The plan is reviewed by a human at the `plan-approval` gate before any code is written. - -## Context - -- **Project ID**: {{project_id}} -- **Issue Number**: #{{issue.number}} -- **Issue Title**: {{issue.title}} -- **Artifact**: `codev/plans/{{artifact_name}}.md` - -## Resumption Check (do this FIRST) - -Run `porch next {{project_id}}`. If the response is `gate_pending`, you have already drafted the plan and are awaiting review. In that case: - -1. Read your current plan file: `cat codev/plans/{{artifact_name}}.md` -2. Check for new feedback that may have arrived while you were idle: - - `git diff HEAD~1 codev/plans/{{artifact_name}}.md` — the reviewer may have edited the file directly - - `gh issue view {{issue.number}} --comments` — check for new comments - - Read any `afx send` queue messages -3. If feedback exists, revise the plan and recommit. If not, end the turn with a short "still awaiting review" message and stay in the interactive session. - -Otherwise (`tasks` response — this is your first run), continue with the steps below. - -## Process - -### 1. Read the Issue - -```bash -gh issue view {{issue.number}} -``` - -Understand what's being asked. For a bug, identify the symptom. For a feature, identify the desired outcome. - -### 2. Investigate the Codebase - -- Use Glob / Grep / Read to find the relevant code -- For a bug: trace the failure path, identify the root cause -- For a feature: find the existing patterns and integration points -- Note any existing utilities, components, or conventions you should reuse - -### 3. Write the Plan - -Create `codev/plans/{{artifact_name}}.md` where `` is a short kebab-case description of the change. Use this structure: - -```markdown -# PIR Plan: - -## Understanding - -What the issue is asking for, in your own words. For a bug, include the root cause you identified — back it up with file:line references. - -## Proposed Change - -The approach you intend to take. Be specific. If there are multiple valid approaches, pick one and explain why. - -## Files to Change - -Concrete file paths. Use `file:line` format for specific edits where possible. - -- `path/to/file.ts:42-55` — what changes -- `path/to/new-file.ts` — new file, what it does - -## Risks & Alternatives Considered - -- Risk: what could go wrong; mitigation -- Alternative: ; why rejected - -## Test Plan - -How to verify this works once implemented. The reviewer will use this at the `dev-approval` gate to test the running worktree. - -- Unit test: -- Manual: -- Cross-platform: -``` - -### 4. Commit and Push - -```bash -git add codev/plans/{{artifact_name}}.md -git commit -m "[PIR #{{issue.number}}] Plan draft" -git push -u origin "$(git branch --show-current)" -``` - -**Never use `git add .` or `git add -A`.** - -### 5. Signal Phase Complete - -```bash -porch done {{project_id}} -porch next {{project_id}} -``` - -`porch next` will respond with `gate_pending` on the `plan-approval` gate. Porch automatically notifies the architect. - -### 6. End Your Turn With a Prose Summary - -Output something like: - -> Plan written to `codev/plans/{{artifact_name}}.md` and committed. Ready for review — type any feedback here, edit the plan file directly in VSCode, or approve with `porch approve {{project_id}} plan-approval --a-human-explicitly-approved-this` (Cmd+K G in VSCode). - -Then **stay in the interactive session**. Do not exit. Wait for the user's next message. - -## Signals - -``` -PHASE_COMPLETE # Plan drafted (informational; the real signal is porch done) -BLOCKED:reason # Cannot proceed -``` - -## What NOT to Do - -- Don't write code — that's the implement phase -- Don't run `porch approve` yourself — only the human can approve the gate -- Don't post the plan content as a GitHub issue comment — the plan lives in the file, not the issue thread. A one-line pointer comment on the issue is fine if you think it helps the discussion. -- Don't use `git add .` or `git add -A` -- Don't exit the interactive session at the gate - -## Handling Feedback - -When the reviewer provides feedback (typed in pane, file-edit, `afx send`, or issue comment): - -1. Re-read the plan file (the user may have edited it) -2. Apply the requested changes to your plan -3. Recommit: `git add codev/plans/{{artifact_name}}.md && git commit -m "[PIR #{{issue.number}}] Plan revised"` -4. Push -5. Output a short "Revised — see commit X" message -6. Wait for next input — the gate remains pending until the human approves diff --git a/codev/protocols/pir/prompts/review.md b/codev/protocols/pir/prompts/review.md deleted file mode 100644 index 952f19c29..000000000 --- a/codev/protocols/pir/prompts/review.md +++ /dev/null @@ -1,269 +0,0 @@ -# REVIEW Phase Prompt - -You are executing the **REVIEW** phase of the PIR protocol. - -## Your Goal - -Write a retrospective at `codev/reviews/{{artifact_name}}.md` including **Summary**, **Architecture Updates**, and **Lessons Learned Updates** sections. Push, open a PR using the review file as the PR body, record the PR with porch, then signal completion — **porch runs 3-way consultation (Gemini, Codex, Claude) once** via the verify block. The consultation is a *single advisory pass* (`max_iterations: 1`): its verdicts are surfaced to the human at the `pr` gate, **not** an iterate-until-APPROVE loop. After the single pass the `pr` gate fires regardless of verdict; you notify the architect (leading with any REQUEST_CHANGES) and wait at the gate while the human merges on GitHub. - -The retrospective ships with the merged PR — it's durable team knowledge, searchable in `codev/reviews/` on `main`. - -## Context - -- **Project ID**: {{project_id}} -- **Issue Number**: #{{issue.number}} -- **Plan File**: `codev/plans/{{artifact_name}}.md` -- **Review File**: `codev/reviews/{{artifact_name}}.md` (you will write this) - -## Prerequisites - -- The `dev-approval` gate has been approved (you're here because `porch next` advanced you) -- Your branch contains the implementation commits -- Build and tests pass - -## Process - -### 1. Write the Review File - -Create `codev/reviews/{{artifact_name}}.md` with these sections: - -```markdown -# PIR Review: - -Fixes #{{issue.number}} - -## Summary - -2–3 sentence overview of what was implemented and why. The reader is someone scanning `codev/reviews/` six months from now trying to understand what this PR did. - -## Files Changed - -Output of `git diff --stat "$MERGE_BASE"`, formatted as a list (resolve once: `DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||'); DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}; MERGE_BASE=$(git merge-base "$DEFAULT_BRANCH" HEAD)`. Anchoring at the merge-base keeps the file list scoped to *your* changes, not commits the base branch absorbed after you branched.): - -- `path/to/file.ts` (+12 / -3) -- `path/to/new-file.ts` (+45 / -0) - -## Commits - -Output of `git log main..HEAD --oneline`: - -- `` [PIR #{{issue.number}}] First change -- `` [PIR #{{issue.number}}] Second change - -## Test Results - -- `npm run build`: ✓ pass -- `npm test`: ✓ pass (X tests, Y new) -- Manual verification: - -## Architecture Updates - -What you routed where, across the **two tiers** (Spec 987): **HOT** = `codev/resources/arch-critical.md` (tiny, hard-capped, always-injected) for a behavior-changing cross-cutting fact (demote a weaker entry into `arch.md` if the hot file is full); **COLD** = `codev/resources/arch.md` for reference detail. Update the file(s) you routed to in this same commit. If nothing qualifies, write a single line explaining why: "No arch changes — this PR fixes a typo without affecting module boundaries." - -Use the `update-arch-docs` skill if available (`.claude/skills/update-arch-docs/SKILL.md`) — it encodes the discipline for what NOT to include in arch docs and how the hot/cold tiers relate. - -## Lessons Learned Updates - -What durable wisdom emerged, routed by tier: **HOT** `codev/resources/lessons-critical.md` for a behavior-changing cross-cutting rule (cap + displacement); **COLD** `codev/resources/lessons-learned.md` for a spec-narrow recipe/reference tip. Update the file(s) you routed to in this commit. If nothing qualifies: "No lessons captured — change was mechanical." - -## Things to Look At During PR Review - -Tricky spots the PR reviewer should focus on. Honest — if a section was hard to get right, flag it. - -## How to Test Locally - -For reviewers pulling the branch: - -- **View diff**: VSCode sidebar → right-click builder pir-{{project_id}} → **Review Diff** (auto-detects the repo's default branch) -- **Run dev**: VSCode sidebar → **Run Dev**, or `afx dev pir-{{project_id}}` -- **What to verify**: - -## Flaky Tests (if any) - -List any tests you skipped due to pre-existing flakiness, with file:line refs and a one-line rationale each. Omit this section if none. -``` - -### 2. Update Architecture / Lessons Docs (if applicable) - -If your "Architecture Updates" or "Lessons Learned Updates" section routed real changes, update the tier you chose — `arch-critical.md` / `lessons-critical.md` (hot, capped) or `arch.md` / `lessons-learned.md` (cold) — accordingly. Use the `update-arch-docs` skill if it's available. - -If neither doc needs updating, your review file's sections still need to explain why — the porch `checks` block enforces section presence. - -### 3. Commit the Review File (and arch / lessons updates) - -```bash -git add codev/reviews/{{artifact_name}}.md -# Add the governance file(s) you routed to, only if changed -git add codev/resources/arch-critical.md # hot — only if changed -git add codev/resources/lessons-critical.md # hot — only if changed -git add codev/resources/arch.md # cold — only if changed -git add codev/resources/lessons-learned.md # cold — only if changed -git commit -m "[PIR #{{issue.number}}] Review + retrospective" -git push -``` - -### 4. Open the PR - -```bash -PR_TITLE="" -BRANCH="$(git branch --show-current)" - -gh pr create \ - --base main \ - --head "$BRANCH" \ - --title "$PR_TITLE" \ - --body-file codev/reviews/{{artifact_name}}.md -``` - -**Verify the PR body contains `Fixes #{{issue.number}}`** (it should — the review file has it at the top). If somehow missing, edit and re-apply: - -```bash -gh pr edit --body-file codev/reviews/{{artifact_name}}.md -``` - -**Exception**: if this PR only partially addresses the issue, use `Refs #{{issue.number}}` instead — the issue stays open until a follow-up PR closes it. - -### 4a. Record the PR with Porch - -Immediately after creating the PR, tell porch about it so `status.yaml` carries the PR number and branch. This is a metadata-only call — it does NOT advance the phase or trigger the consultation: - -```bash -porch done {{project_id}} --pr --branch "$(git branch --show-current)" -``` - -Without this, porch's `history:` for the project stays empty and downstream tooling (status views, analytics, audit trails) can't link the porch project to its GitHub PR. - -### 5. Signal Completion to Porch (porch runs 3-way consultation) - -```bash -porch done {{project_id}} -``` - -Porch will: -1. Run the `pr_exists` / `review_has_arch_updates` / `review_has_lessons_updates` checks. -2. **Run 3-way consultation (Gemini, Codex, Claude) automatically** via the protocol's `verify` block. Outputs land in `codev/projects/{{project_id}}-/{{project_id}}-gemini.txt`, `-codex.txt`, and `-claude.txt`. -3. The consultation runs **exactly once** (`max_iterations: 1`). Whatever the verdicts, porch records them in `status.yaml` and advances to the `pr` gate — there is **no automated re-review pass and no "stays in the review phase" loop**. `APPROVE` and `REQUEST_CHANGES` differ only in what you must surface to the human (steps 6–7), not in whether the gate fires. The output of `porch done` surfaces the verdicts. - -> **Why consult after the human already approved the running code?** The human approved the *running* implementation at the `dev-approval` gate; the 3-way consultation at the PR is a pre-merge hygiene + code-quality pass, not a functional review. - -### 6. Handle a REQUEST_CHANGES Verdict (single-pass — no automated re-review) - -PIR's consultation is one advisory pass (`max_iterations: 1`). If a reviewer returns `REQUEST_CHANGES`, porch does **not** loop or re-run it — it records the verdict and proceeds to the `pr` gate. There is no iter-2. The correctness backstop for a consultation-flagged issue is therefore **(a)** your fix + a regression test and **(b)** the human's `pr`-gate review — *not* an independent model re-review. Treat that as load-bearing: a substantive finding you "address and rebut" gets no second AI opinion. - -For any `REQUEST_CHANGES`: - -1. Read the finding in full (`codev/projects/{{project_id}}-*/{{project_id}}-.txt`). -2. **Assess it honestly:** - - **Real defect** (correctness / cancellation / security / data-loss): fix it in code, add a regression test that fails without the fix, commit + push (the PR updates automatically — no new `gh pr create`). Then document the finding, your fix, and the pinning test in the review file's **"Things to Look At During PR Review"** section. - - **False positive / out of scope**: write a brief rebuttal in that same section explaining why no change is warranted. -3. Do **not** re-run `porch done` expecting another consultation pass — `max_iterations: 1` means it will not re-review. Proceed to step 7. - -Whether you fixed it or rebutted it, a `REQUEST_CHANGES` that PIR will never re-check **must be escalated to the human at the `pr` gate** (step 7) — they are the only remaining reviewer of that decision. - -### 7. Notify the Architect (after the single consultation pass — gate is now pending) - -After the one consultation pass + structural checks, porch fires the **`pr` gate** (pending) **regardless of the verdicts**. Read the verdicts from porch state and notify — and if any verdict is `REQUEST_CHANGES`, **lead with it and state the disposition**, because PIR will not re-review it and the human at the `pr` gate is the only remaining check: - -```bash -GEMINI_VERDICT=$(grep -m1 -i '^\(approve\|request_changes\|comment\)' "codev/projects/{{project_id}}-"*/"{{project_id}}-gemini.txt" || echo UNKNOWN) -CODEX_VERDICT=$(grep -m1 -i '^\(approve\|request_changes\|comment\)' "codev/projects/{{project_id}}-"*/"{{project_id}}-codex.txt" || echo UNKNOWN) -CLAUDE_VERDICT=$(grep -m1 -i '^\(approve\|request_changes\|comment\)' "codev/projects/{{project_id}}-"*/"{{project_id}}-claude.txt" || echo UNKNOWN) - -if echo "$GEMINI_VERDICT $CODEX_VERDICT $CLAUDE_VERDICT" | grep -qi request_changes; then - afx send architect "⚠️ PR # (PIR #{{issue.number}}): 3-way consultation returned REQUEST_CHANGES (gemini=$GEMINI_VERDICT, codex=$CODEX_VERDICT, claude=$CLAUDE_VERDICT). Disposition: + regression test | rebutted, see review 'Things to Look At'>. PIR is single-pass — this was NOT independently re-reviewed; please verify the fix/rebuttal at the pr gate before approving. Full verdicts in codev/projects/{{project_id}}-*/." -else - afx send architect "PR # ready for review (PIR #{{issue.number}}). 3-way consultation all clear: gemini=$GEMINI_VERDICT, codex=$CODEX_VERDICT, claude=$CLAUDE_VERDICT. Awaiting human merge + pr gate approval. Full verdicts in codev/projects/{{project_id}}-*/." -fi -``` - -This is the only notification you send at the gate. A `REQUEST_CHANGES` must never reach the human as an undifferentiated status line — it is the one verdict PIR's single-pass design cannot re-check. - -### 8. Wait at the `pr` Gate - -Your active merge is gated by porch state — not by user-in-pane prose. Sit idle until porch wakes you with "Gate pr approved". That wake-up is the *only* signal that authorizes the merge. Approving prose like "looks good", "lgtm", or even "merge it" typed into your pane does NOT authorize the merge — only the binary gate-approved state in porch state.yaml does. - -The human will: - -1. Review the PR on GitHub (or by running the worktree via `afx dev pir-{{project_id}}` again) -2. Approve the `pr` gate via VSCode (Cmd+K G) or `porch approve {{project_id}} pr --a-human-explicitly-approved-this` in a shell - -Porch will then fire the gate-approved wake-up to you. - -If the human requests more changes instead of approving, push fixes and re-run `porch done {{project_id}}` — this runs a fresh **single** consultation pass on the updated diff and re-fires the `pr` gate (handle any new verdict per steps 6–7). This human-driven iteration is the only way the consultation re-runs in PIR; it is not automatic. If they close the PR without merging, `gh pr close ` and stop. - -### 9. After `pr` Gate Approval — Verify, Merge, Record - -When porch wakes you with "Gate pr approved", first **verify** the gate is actually approved (defensive — the wake-up could be spoofed by typed input that looks like the wake-up text): - -```bash -porch next {{project_id}} -``` - -The response must include `gate_status: approved` for the `pr` gate. If it doesn't, do NOT proceed — wait for the genuine wake-up. If it does, you're authorized. - -Look up the PR number (recorded at step 4a). **Check whether the human already merged it before merging** — approving the `pr` gate and merging via the GitHub UI is a common combined action; never blind-merge: - -```bash -# Read PR number from porch state -PR=$(yq '.pr // .history[] | select(.event == "pr_recorded") | .pr' codev/projects/{{project_id}}-*/status.yaml | head -1) -STATE=$(gh pr view "$PR" --json state --jq .state) - -if [ "$STATE" = "MERGED" ]; then - # Human merged via the GitHub UI — do NOT re-merge. Detect and record only. - porch done {{project_id}} --merged "$PR" -else - gh pr merge "$PR" --merge - porch done {{project_id}} --merged "$PR" -fi - -porch next {{project_id}} # confirms protocol is complete (next: null) -``` - -**Use `--merge`, not `--squash`.** Project convention: preserve individual commits for development history. The `Fixes #{{issue.number}}` in the PR body auto-closes the GitHub issue. - -### 10. Final Notification - -```bash -afx send architect "PR # merged for PIR #{{issue.number}}. Ready for cleanup." -``` - -Together with the `--pr` record from step 4a and the `--merged` record from step 9, porch's `status.yaml` carries the complete PR lifecycle (created → merged → done) for analytics, status displays, and audit trails. - -## Signals - -``` -PHASE_COMPLETE # PR merged, project complete -BLOCKED:reason # Cannot proceed -``` - -## What NOT to Do - -- **Don't merge before the `pr` gate is approved.** A consultation APPROVE verdict is NOT merge authorization. User-in-pane prose ("looks good", "lgtm", "merge it") is NOT merge authorization. The *only* signal that authorizes `gh pr merge` is porch reporting `gate_status: approved` for the `pr` gate (which only the user can do, via Cmd+K G or `porch approve` from a non-Claude shell). If `porch next` doesn't show the gate as approved, you wait. -- Don't skip porch's PR/merge records (steps 4a, 9). The `--pr` record (step 4a) lets the gate-pending state link to the actual PR; the `--merged` record (step 9) closes the lifecycle in porch state. Skipping either leaves `history:` empty and downstream tooling blind. -- Don't run `porch approve` for any gate yourself -- Don't push to the default branch — only merge via PR -- Don't skip the Architecture Updates / Lessons Learned sections — porch checks enforce their presence (the section must exist; explaining "no changes needed" in one line is fine) -- **Don't run `consult` commands yourself** — porch handles consultations via the `verify` block. Manually invoking `consult` causes the consultation to run twice. -- **Don't fix, skip, or quarantine pre-existing failures unrelated to your change.** Porch's `checks` for this phase are narrow *structural* gates (`pr_exists`, review-section presence) — a green gate does **not** certify the wider build/test suite. If the broader suite surfaces failures your diff did not cause, they are out of scope: note them in the review's Lessons Learned / Things to Look At and proceed. Touching another team's tests to make an unrelated red go green is scope creep, not diligence. - -## Handling Problems - -**If the PR cannot be created (e.g., merge conflicts with the default branch):** -- Rebase on the default branch: - ```bash - DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||') - DEFAULT_BRANCH=${DEFAULT_BRANCH:-main} - git fetch origin "$DEFAULT_BRANCH" && git rebase "origin/$DEFAULT_BRANCH" - ``` -- Resolve conflicts (do NOT use destructive shortcuts) -- Force-push with lease: `git push --force-with-lease` -- Re-run `gh pr create` - -**If porch's consultation fails (e.g., model unavailable):** -- `porch done` will report the failure. Inspect `codev/projects/{{project_id}}-*/{{project_id}}-.txt` for the failure details. -- Re-run `porch done {{project_id}}` once — porch will retry the consult. -- If the model is persistently unavailable, notify the architect and ask whether to proceed without that model's verdict. They may direct you to skip via a manual override. - -**If the architect doesn't respond within a reasonable window:** -- Send one follow-up via `afx send architect "..."` after a few hours -- Do not auto-merge diff --git a/codev/protocols/pir/protocol.json b/codev/protocols/pir/protocol.json deleted file mode 100644 index 067e64765..000000000 --- a/codev/protocols/pir/protocol.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "pir", - "alias": "plan-implement-review", - "version": "1.0.0", - "description": "PIR: Plan → Implement → Review with build-verify cycles and two pre-PR human gates (plan-approval, dev-approval), for GitHub-issue-driven work.", - "input": { - "type": "github-issue", - "required": true, - "default_for": ["--issue", "-i"] - }, - "hooks": { - "pre-spawn": { - "collision-check": true, - "comment-on-issue": "On it! Working on this with the PIR protocol (plan + dev-approval gates before PR)." - } - }, - "phases": [ - { - "id": "plan", - "name": "Plan", - "description": "Read the issue, investigate the codebase, write codev/plans/-.md, await plan-approval", - "type": "build_verify", - "build": { - "prompt": "plan.md", - "artifact": "codev/plans/${PROJECT_TITLE}.md" - }, - "verify": null, - "max_iterations": 1, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "plan_exists": "test -f codev/plans/${PROJECT_TITLE}.md" - }, - "gate": "plan-approval", - "next": "implement" - }, - { - "id": "implement", - "name": "Implement", - "description": "Write code + tests, run build/test checks, await dev-approval on the running worktree", - "type": "build_verify", - "build": { - "prompt": "implement.md", - "artifact": "src/**/*.{ts,tsx,js,jsx,py,go,rs}" - }, - "verify": null, - "max_iterations": 1, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "build": { - "command": "npm run build", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "npm test", - "on_fail": "retry", - "max_retries": 2 - } - }, - "gate": "dev-approval", - "next": "review" - }, - { - "id": "review", - "name": "Review", - "description": "Write retrospective (arch + lessons), push, open PR with review as body, run 3-way consultation, then wait at pr gate while the human merges on GitHub", - "type": "build_verify", - "build": { - "prompt": "review.md", - "artifact": "codev/reviews/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "impl", - "models": ["gemini", "codex"], - "parallel": true - }, - "max_iterations": 1, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "pr_exists": { - "command": "gh pr list --state all --head \"$(git branch --show-current)\" --json number --jq 'length' | grep -q '^[1-9]'", - "description": "PR must be created before signaling completion" - }, - "review_has_arch_updates": { - "command": "grep -q '## Architecture Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Architecture Updates' section (what changed in arch.md, or why no changes needed)" - }, - "review_has_lessons_updates": { - "command": "grep -q '## Lessons Learned Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Lessons Learned Updates' section (what changed in lessons-learned.md, or why no changes needed)" - } - }, - "gate": "pr", - "next": null - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current build phase is complete", - "transitions_to": "next_phase" - }, - "BLOCKED": { - "description": "Signal implementation is blocked", - "requires": "reason" - } - }, - "defaults": { - "mode": "strict", - "max_iterations": 1, - "consultation": { - "enabled": true, - "parallel": true - } - } -} diff --git a/codev/protocols/protocol-schema.json b/codev/protocols/protocol-schema.json deleted file mode 100644 index 375108b3d..000000000 --- a/codev/protocols/protocol-schema.json +++ /dev/null @@ -1,290 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://codev.dev/protocol-schema.json", - "title": "Protocol Definition", - "description": "Schema for porch protocol definitions", - "type": "object", - "required": ["name", "version", "description", "phases"], - "properties": { - "name": { - "type": "string", - "description": "Protocol identifier (e.g., 'spir', 'tick', 'bugfix')" - }, - "version": { - "type": "string", - "pattern": "^\\d+\\.\\d+\\.\\d+$", - "description": "Semantic version of the protocol" - }, - "description": { - "type": "string", - "description": "Human-readable description of the protocol" - }, - "phases": { - "type": "array", - "description": "Ordered list of protocol phases", - "items": { - "$ref": "#/definitions/phase" - }, - "minItems": 1 - }, - "input": { - "$ref": "#/definitions/protocolInput" - }, - "hooks": { - "$ref": "#/definitions/protocolHooks" - }, - "signals": { - "type": "object", - "description": "Signal definitions for state transitions", - "additionalProperties": { - "$ref": "#/definitions/signal" - } - }, - "defaults": { - "type": "object", - "description": "Default configuration for the protocol", - "properties": { - "mode": { - "type": "string", - "enum": ["strict", "soft"], - "description": "Default orchestration mode for the protocol" - }, - "consultation": { - "$ref": "#/definitions/consultationDefaults" - }, - "checks": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - } - }, - "definitions": { - "phase": { - "type": "object", - "required": ["id", "name", "type"], - "properties": { - "id": { - "type": "string", - "description": "Unique phase identifier" - }, - "name": { - "type": "string", - "description": "Human-readable phase name" - }, - "description": { - "type": "string", - "description": "Phase description" - }, - "type": { - "type": "string", - "enum": ["once", "per_plan_phase"], - "description": "Whether phase runs once or per plan phase" - }, - "steps": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of steps within the phase" - }, - "checks": { - "type": "object", - "description": "Build/test checks for this phase", - "additionalProperties": { - "$ref": "#/definitions/check" - } - }, - "consultation": { - "$ref": "#/definitions/consultation" - }, - "gate": { - "$ref": "#/definitions/gate" - }, - "transition": { - "$ref": "#/definitions/transition" - } - } - }, - "check": { - "type": "object", - "required": ["command"], - "properties": { - "command": { - "type": "string", - "description": "Command to run" - }, - "on_fail": { - "type": "string", - "description": "Action on failure: 'retry' or phase name to return to" - }, - "max_retries": { - "type": "integer", - "minimum": 0, - "description": "Maximum retry attempts" - }, - "retry_delay": { - "type": "integer", - "minimum": 0, - "description": "Delay between retries in seconds" - } - } - }, - "consultation": { - "type": "object", - "properties": { - "on": { - "type": "string", - "enum": ["review", "complete"], - "description": "When to trigger consultation" - }, - "models": { - "type": "array", - "items": { - "type": "string" - }, - "description": "AI models to consult" - }, - "type": { - "type": "string", - "description": "Review type (spec, plan, impl, pr, phase, integration)" - }, - "parallel": { - "type": "boolean", - "description": "Run consultations in parallel" - }, - "max_rounds": { - "type": "integer", - "minimum": 1, - "description": "Maximum revision rounds" - }, - "next": { - "type": "string", - "description": "Phase to proceed to after consultation" - } - } - }, - "consultationDefaults": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether consultation is enabled by default" - }, - "models": { - "type": "array", - "items": { - "type": "string" - } - }, - "parallel": { - "type": "boolean" - } - } - }, - "gate": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "description": "Gate identifier" - }, - "description": { - "type": "string", - "description": "What this gate checks" - }, - "requires": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Items that must be complete to pass" - }, - "next": { - "type": ["string", "null"], - "description": "Next phase after gate (null for terminal)" - } - } - }, - "transition": { - "type": "object", - "properties": { - "on_complete": { - "type": "string", - "description": "Phase to transition to on completion" - }, - "on_fail": { - "type": "string", - "description": "Phase to return to on failure" - }, - "on_too_complex": { - "type": "string", - "description": "Action when task is too complex" - }, - "on_all_phases_complete": { - "type": "string", - "description": "Phase to transition to when all plan phases are done" - } - } - }, - "signal": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "transitions_to": { - "type": "string" - }, - "requires": { - "type": "string" - } - } - }, - "protocolInput": { - "type": "object", - "description": "Protocol input configuration - defines what input types a protocol accepts", - "properties": { - "type": { - "type": "string", - "enum": ["spec", "github-issue", "task", "protocol", "shell", "worktree"], - "description": "Primary input type for this protocol" - }, - "required": { - "type": "boolean", - "description": "Whether an input of this type is required" - }, - "default_for": { - "type": "array", - "items": { - "type": "string" - }, - "description": "CLI flags this protocol is the default for (e.g., ['--issue', '-i'])" - } - } - }, - "protocolHooks": { - "type": "object", - "description": "Hooks triggered at various points in the spawn lifecycle", - "properties": { - "pre-spawn": { - "type": "object", - "description": "Hooks executed before spawning the builder", - "properties": { - "collision-check": { - "type": "boolean", - "description": "Check for worktree/PR collisions before spawning" - }, - "comment-on-issue": { - "type": "string", - "description": "Comment to post on GitHub issue when spawning" - } - } - } - } - } - } -} diff --git a/codev/protocols/release/protocol.md b/codev/protocols/release/protocol.md index ce9471433..39ebb85e4 100644 --- a/codev/protocols/release/protocol.md +++ b/codev/protocols/release/protocol.md @@ -39,8 +39,9 @@ Execute the MAINTAIN protocol to ensure: - CLAUDE.md and AGENTS.md are in sync ```bash -# Review what MAINTAIN will do -cat codev/protocols/maintain/protocol.md +# Review what MAINTAIN will do (Spec 1252: the codev/protocols shadow tree was +# deleted — framework protocols live in codev-skeleton/, the single owner) +cat codev-skeleton/protocols/maintain/protocol.md ``` ### 3. Run E2E Tests diff --git a/codev/protocols/research/builder-prompt.md b/codev/protocols/research/builder-prompt.md deleted file mode 100644 index 088262853..000000000 --- a/codev/protocols/research/builder-prompt.md +++ /dev/null @@ -1,91 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are conducting multi-agent research. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the RESEARCH protocol yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Use `consult` for the 3-way investigation and critique phases -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way consultation** — always follow porch next → porch done cycle -{{/if}} - -## Protocol -Follow the RESEARCH protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## RESEARCH Overview - -The RESEARCH protocol produces a high-confidence research report through triangulation: - -1. **Scope** — Define the precise question, scope, and acceptance criteria. Write a research brief. Gate: architect approval before proceeding. -2. **Investigate** — Dispatch the brief to 3 models (Gemini, Codex, Claude) in parallel. Each investigates independently. No anchoring — they don't see each other's work. -3. **Synthesize** — Read all 3 reports. Identify consensus, disagreements, and unique contributions. Write a single synthesis report organized by topic (not by model). -4. **Critique** — Send the synthesis back to all 3 models for critique. Incorporate valid feedback. Document rejected critique. Finalize the report. - -## Output Location - -All artifacts go to `codev/research/`: -- `-brief.md` — the scoped question (Phase 1) -- `-gemini.md`, `-codex.md`, `-claude.md` — individual investigations (Phase 2) -- `.md` — the final synthesis report (Phase 3+4, this is the deliverable) -- `-critique-rebuttals.md` — critique responses (Phase 4) - -{{#if task}} -## Research Topic -{{task_text}} -{{/if}} - -## Key Principles - -- **Triangulate**: consensus across 3 models > any single model's claim -- **Cite sources**: tell investigators to provide sources where possible -- **Be candid about uncertainty**: "I don't know" > confabulation -- **Organize by topic, not by model**: the synthesis is a standalone document -- **Note surprises**: the most valuable findings are often unexpected -- **Keep it concise**: the synthesis should be shorter than the sum of the investigations - -## Using consult for 3-way Investigation - -For the investigate phase, use the `consult` CLI to dispatch to each model: - -```bash -# Phase 2: parallel investigation -consult -m gemini --prompt-file codev/research/-brief.md --output codev/research/-gemini.md & -consult -m codex --prompt-file codev/research/-brief.md --output codev/research/-codex.md & -consult -m claude --prompt-file codev/research/-brief.md --output codev/research/-claude.md & -wait -``` - -For the critique phase: -```bash -# Phase 4: parallel critique -consult -m gemini --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-gemini.md & -consult -m codex --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-codex.md & -consult -m claude --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-claude.md & -wait -``` - -## Getting Started -1. Read the RESEARCH protocol document -2. Understand the research question from the architect -3. Write the research brief (Phase 1) -4. Wait for scope-approval before proceeding to investigation - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/research/protocol.json b/codev/protocols/research/protocol.json deleted file mode 100644 index 44203709e..000000000 --- a/codev/protocols/research/protocol.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "research", - "version": "1.0.0", - "description": "Multi-agent research with 3-way investigation, synthesis, and critique", - "input": { - "type": "none", - "required": false, - "default_for": [] - }, - "hooks": { - "pre-spawn": {} - }, - "phases": [ - { - "id": "scope", - "name": "Scope", - "description": "Define the research question, scope, and acceptance criteria", - "type": "once", - "steps": [ - "clarify_question", - "define_scope", - "define_acceptance_criteria", - "create_research_brief" - ], - "gate": { - "name": "scope-approval", - "description": "Architect confirms the research question is correctly scoped", - "requires": ["research_brief_exists"], - "next": "investigate" - } - }, - { - "id": "investigate", - "name": "Investigate", - "description": "3-way parallel investigation — each model researches independently", - "type": "once", - "steps": [ - "dispatch_gemini_investigation", - "dispatch_codex_investigation", - "dispatch_claude_investigation", - "collect_all_reports" - ], - "consultation": { - "enabled": true, - "models": ["codex"], - "parallel": true, - "type": "investigation" - }, - "transition": { - "on_complete": "synthesize" - } - }, - { - "id": "synthesize", - "name": "Synthesize", - "description": "Merge the 3 investigation reports into a single coherent research document", - "type": "once", - "steps": [ - "read_all_investigation_reports", - "identify_consensus_and_disagreements", - "resolve_conflicts", - "write_synthesis_report" - ], - "transition": { - "on_complete": "critique" - } - }, - { - "id": "critique", - "name": "Critique", - "description": "3-way review of the synthesis — each model critiques for gaps, errors, and bias", - "type": "once", - "steps": [ - "dispatch_gemini_critique", - "dispatch_codex_critique", - "dispatch_claude_critique", - "incorporate_feedback", - "finalize_report" - ], - "consultation": { - "enabled": true, - "models": ["codex"], - "parallel": true, - "type": "critique" - }, - "gate": { - "name": "research-complete", - "description": "Research report finalized", - "requires": ["report_finalized"], - "next": null - } - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current phase is complete", - "transitions_to": "next_phase" - }, - "BLOCKED": { - "description": "Signal research is blocked", - "requires": "reason" - }, - "SCOPE_REJECTED": { - "description": "Architect rejects the scope — rework needed", - "transitions_to": "scope" - } - }, - "defaults": { - "mode": "strict", - "consultation": { - "enabled": true, - "models": ["codex"], - "parallel": true - }, - "checks": {} - } -} diff --git a/codev/protocols/spike/builder-prompt.md b/codev/protocols/spike/builder-prompt.md deleted file mode 100644 index 6d30dc649..000000000 --- a/codev/protocols/spike/builder-prompt.md +++ /dev/null @@ -1,68 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are executing a time-boxed technical feasibility spike. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the SPIKE protocol yourself (no porch orchestration) -- Stay focused on the question — don't gold-plate -- The findings document is your deliverable, not the code -{{/if}} - -## Protocol -Follow the SPIKE protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -{{#if task}} -## Spike Question -{{task_text}} -{{/if}} - -## Recommended Workflow - -Follow this 3-step workflow. You can skip or reorder steps as the investigation demands. - -### 1. Research -- Read documentation, examine existing code, search for prior art -- Identify constraints, dependencies, and potential blockers -- Understand the problem space before writing any code - -### 2. Iterate -- Build minimal proof-of-concept code to test approaches -- Focus on answering the feasibility question, not building production code -- POC code doesn't need tests or polish -- **Skip this step** if the answer is clear from research alone - -### 3. Findings -- Write findings to `codev/spikes/-.md` using the template -- Provide a clear feasibility verdict: Feasible / Not Feasible / Feasible with Caveats -- Commit the findings document -- Notify the architect: `afx send architect "Spike complete. Verdict: [verdict]"` - -## Key Principles - -- **Time-boxing**: Stay focused on the question. Don't explore tangents. -- **Exploration over perfection**: POC code doesn't need tests or polish. -- **Clear output**: The findings document is the deliverable, not the code. -- **Know when to stop**: Once you can answer the feasibility question, write findings and stop. Don't keep iterating. -- **Document failures**: "Not feasible" is a valid and valuable finding. - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your findings under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the SPIKE protocol document -2. Understand the question you're investigating -3. Start with research — don't jump straight to code - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/spike/protocol.json b/codev/protocols/spike/protocol.json deleted file mode 100644 index 9db384b30..000000000 --- a/codev/protocols/spike/protocol.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "spike", - "version": "1.0.0", - "description": "Time-boxed technical feasibility exploration", - "input": { - "type": "task", - "required": false, - "default_for": [] - }, - "phases": [ - { - "id": "spike", - "name": "Spike", - "description": "Execute the spike — research, iterate, write findings", - "type": "once" - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal spike is complete" - }, - "BLOCKED": { - "description": "Signal spike is blocked", - "requires": "reason" - } - }, - "defaults": { - "mode": "soft", - "consultation": { - "enabled": false, - "models": [], - "parallel": false - } - } -} diff --git a/codev/protocols/spike/templates/findings.md b/codev/protocols/spike/templates/findings.md deleted file mode 100644 index 3fa8c2c36..000000000 --- a/codev/protocols/spike/templates/findings.md +++ /dev/null @@ -1,67 +0,0 @@ -# Spike: [Title] - -**Date**: YYYY-MM-DD - -**Verdict**: Feasible | Not Feasible | Feasible with Caveats - -## Question - -What technical question was being investigated? Be specific: -- What are you trying to determine? -- What prompted this investigation? -- What decision depends on the answer? - -## Research Summary - -What was explored during the research phase: -- Documentation read -- Existing code examined -- Prior art found -- Key constraints identified - -## Approaches Tried - -What was built or tested during the iterate phase: - -### Approach 1: [Name] -- **What**: Brief description of what was tried -- **Result**: What happened -- **Verdict**: Worked / Didn't work / Partially worked - -### Approach 2: [Name] -*(Add more approaches as needed, or remove if research alone answered the question)* - -## Constraints Discovered - -Technical limitations, dependencies, and gotchas found during the investigation: -- [Constraint 1] -- [Constraint 2] - -## Recommended Approach - -*(If feasible)* How should full implementation proceed? -- Recommended library/technique/pattern -- Key architectural decisions -- Things to watch out for - -*(If not feasible)* Why not, and what alternatives exist? - -## Effort Estimate - -Rough sizing for a full SPIR project: **Small** | **Medium** | **Large** - -- Small: < 300 LOC, 1-2 files, straightforward -- Medium: 300-1000 LOC, multiple files, some complexity -- Large: 1000+ LOC, architectural changes, significant complexity - -## Next Steps - -- [ ] [Recommended action — e.g., "Create SPIR spec for WebSocket integration"] -- [ ] [Or: "Do not pursue — blocked by X"] -- [ ] [Or: "Investigate Y further before deciding"] - -## References - -- [Link to relevant documentation] -- [Link to relevant code/commits] -- [Link to external resources consulted] diff --git a/codev/protocols/spir/builder-prompt.md b/codev/protocols/spir/builder-prompt.md deleted file mode 100644 index 580e269c5..000000000 --- a/codev/protocols/spir/builder-prompt.md +++ /dev/null @@ -1,96 +0,0 @@ -# {{protocol_name}} Builder ({{mode}} mode) - -You are implementing {{input_description}}. - -{{#if mode_soft}} -## Mode: SOFT -You are running in SOFT mode. This means: -- You follow the protocol document yourself (no porch orchestration) -- The architect monitors your work and verifies you're adhering to the protocol -- Run consultations manually when the protocol calls for them -- You have flexibility in execution, but must stay compliant with the protocol -{{/if}} - -{{#if mode_strict}} -## Mode: STRICT -You are running in STRICT mode. This means: -- Porch orchestrates your work -- Run: `porch next` to get your next tasks -- Follow porch signals and gate approvals -- Do not deviate from the porch-driven workflow - -### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to -- **NEVER skip the 3-way review** — always follow porch next → porch done cycle -- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval -{{/if}} - -## Protocol -Follow the SPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. - -## Baked Decisions - -If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. - -If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. - -{{#if spec}} -## Spec -Read the specification at: `{{spec.path}}` -{{/if}} - -{{#if plan}} -## Plan -Follow the implementation plan at: `{{plan.path}}` -{{/if}} - -{{#if issue}} -## Issue #{{issue.number}} -**Title**: {{issue.title}} - -**Description**: -{{issue.body}} -{{/if}} - -{{#if task}} -## Task -{{task_text}} -{{/if}} - -## PR Strategy - -**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. - -By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. - -### Architect-requested PRs - -The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. - -## Notifications -Always use `afx send architect "..."` to notify the architect at key moments: -- **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` -- **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} complete. PR merged. Ready for cleanup."` -- **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` - -## Handling Flaky Tests - -If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use any workaround to avoid the failure -3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section -5. Commit the skip and continue with your work - -## Getting Started -1. Read the protocol document thoroughly -2. Review the spec and plan (if available) -3. Begin implementation following the protocol phases - ---- - -## Protocol Reference (full text) - -{{protocol_reference}} diff --git a/codev/protocols/spir/consult-types/impl-review.md b/codev/protocols/spir/consult-types/impl-review.md deleted file mode 100644 index de01b8d00..000000000 --- a/codev/protocols/spir/consult-types/impl-review.md +++ /dev/null @@ -1,72 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work during the Implement phase. A builder has completed a plan phase and needs feedback before proceeding. Your job is to verify the implementation matches the spec and plan. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Spec Adherence** - - Does the implementation fulfill the spec requirements for this phase? - - Are acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate for this phase? - - Do tests cover the main paths AND edge cases? - -4. **Plan Alignment** - - Does the implementation follow the plan? - - Are there plan items skipped or partially completed? - -5. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - If spec says "async" or "non-blocking", is it actually async? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Phase is complete, builder can proceed -- `REQUEST_CHANGES`: Issues that must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scoping (Multi-Phase Plans) - -When the implementation plan has multiple phases (e.g., scaffolding, landing, media_rtl): -- **ONLY review work belonging to the current plan phase** -- The query will specify which phase you are reviewing -- Do NOT request changes for functionality scheduled in later phases -- Do NOT flag missing features that are out of scope for this phase -- If unsure whether something belongs to this phase, check the plan file - -## Notes - -- This is a phase-level review, not the final PR review -- Focus on "does this phase work" not "is the whole feature done" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to continue diff --git a/codev/protocols/spir/consult-types/phase-review.md b/codev/protocols/spir/consult-types/phase-review.md deleted file mode 100644 index de01b8d00..000000000 --- a/codev/protocols/spir/consult-types/phase-review.md +++ /dev/null @@ -1,72 +0,0 @@ -# Implementation Review Prompt - -## Context -You are reviewing implementation work during the Implement phase. A builder has completed a plan phase and needs feedback before proceeding. Your job is to verify the implementation matches the spec and plan. - -## CRITICAL: Verify Before Flagging - -Before requesting changes for missing configuration, incorrect patterns, or framework issues: -1. **Check `package.json`** for actual dependency versions — framework conventions change between major versions -2. **Read the actual config files** (or confirm their deliberate absence) before flagging missing configs -3. **Do not assume** your training data reflects the version in use — verify against project files -4. If "Previous Iteration Context" is provided, read it carefully before re-raising concerns that were already disputed - -## Focus Areas - -1. **Spec Adherence** - - Does the implementation fulfill the spec requirements for this phase? - - Are acceptance criteria met? - -2. **Code Quality** - - Is the code readable and maintainable? - - Are there obvious bugs or issues? - - Are error cases handled appropriately? - -3. **Test Coverage** - - Are the tests adequate for this phase? - - Do tests cover the main paths AND edge cases? - -4. **Plan Alignment** - - Does the implementation follow the plan? - - Are there plan items skipped or partially completed? - -5. **UX Verification** (if spec has UX requirements) - - Does the actual user experience match what the spec describes? - - If spec says "async" or "non-blocking", is it actually async? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Phase is complete, builder can proceed -- `REQUEST_CHANGES`: Issues that must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but note feedback - -## Scoping (Multi-Phase Plans) - -When the implementation plan has multiple phases (e.g., scaffolding, landing, media_rtl): -- **ONLY review work belonging to the current plan phase** -- The query will specify which phase you are reviewing -- Do NOT request changes for functionality scheduled in later phases -- Do NOT flag missing features that are out of scope for this phase -- If unsure whether something belongs to this phase, check the plan file - -## Notes - -- This is a phase-level review, not the final PR review -- Focus on "does this phase work" not "is the whole feature done" -- If referencing line numbers, use `file:line` format -- The builder needs actionable feedback to continue diff --git a/codev/protocols/spir/consult-types/plan-review.md b/codev/protocols/spir/consult-types/plan-review.md deleted file mode 100644 index 485ff3183..000000000 --- a/codev/protocols/spir/consult-types/plan-review.md +++ /dev/null @@ -1,65 +0,0 @@ -# Plan Review Prompt - -## Context -You are reviewing an implementation plan during the Plan phase. The spec has been approved - now you must evaluate whether the plan adequately describes HOW to implement it. - -## Baked Decisions - -If the issue body or the approved spec's Constraints section includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed (this extends the existing "don't re-litigate spec decisions" rule with explicit baked-decision language). Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns; reserve `REQUEST_CHANGES` for the case where the plan **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions, do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Spec Coverage** - - Does the plan address all requirements in the spec? - - Are there spec requirements not covered by any phase? - - Are there phases that go beyond the spec scope? - -2. **Phase Breakdown** - - Are phases appropriately sized (not too large or too small)? - - Is the sequence logical (dependencies respected)? - - Can each phase be completed and committed independently? - -3. **Technical Approach** - - Is the implementation approach sound? - - Are the right files/modules being modified? - - Are there obvious better approaches being missed? - -4. **Testability** - - Does each phase have clear test criteria? - - Will the Defend step (writing tests) be feasible? - - Are edge cases from the spec addressable? - -5. **Risk Assessment** - - Are there potential blockers not addressed? - - Are dependencies on other systems identified? - - Is the plan realistic given constraints? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Plan is ready for human review -- `REQUEST_CHANGES`: Significant issues with approach or coverage -- `COMMENT`: Minor suggestions, plan is workable but could improve - -## Notes - -- The spec has already been approved - don't re-litigate spec decisions -- Focus on the quality of the plan as a guide for builders -- Consider: Would a builder be able to follow this plan successfully? -- If referencing existing code, verify file paths seem accurate diff --git a/codev/protocols/spir/consult-types/pr-review.md b/codev/protocols/spir/consult-types/pr-review.md deleted file mode 100644 index 837cdea33..000000000 --- a/codev/protocols/spir/consult-types/pr-review.md +++ /dev/null @@ -1,76 +0,0 @@ -# PR Ready Review Prompt - -## Context -You are performing a final self-check during the Review phase. The builder has completed all implementation phases and is about to create a PR. This is the last check before the work goes to the architect for integration review. - -## Focus Areas - -1. **Completeness** - - Are all spec requirements implemented? - - Are all plan phases complete? - - Is the review document written (`codev/reviews/XXXX-name.md`)? - - Are all commits properly formatted (`[Spec XXXX][Phase]`)? - -2. **Test Status** - - Do all tests pass? - - Is test coverage adequate for the changes? - - Are there any skipped or flaky tests? - -3. **Code Cleanliness** - - Is there any debug code left in? - - Are there any TODO comments that should be resolved? - - Are there any `// REVIEW:` comments that weren't addressed? - - Is the code properly formatted? - -4. **Documentation** - - Are inline comments clear where needed? - - Is the review document comprehensive? - - Are any new APIs documented? - -5. **PR Readiness** - - Is the branch up to date with its base (the integration branch the PR targets)? - - Are commits atomic and well-described? - - Is the change diff reasonable in size? - -## Scope - -- **DO NOT** flag the syntax of `git diff` examples that appear in review-file prose (e.g., `git diff ci..HEAD` inside a "Files Changed" caption or "How to Test Locally" section). Quoted diff syntax is documentation, not a command. Apply two-dot/three-dot scrutiny only to diffs you compute yourself. - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... - -PR_SUMMARY: | - ## Summary - [2-3 sentences describing what this PR does] - - ## Key Changes - - [Change 1] - - [Change 2] - - ## Test Plan - - [How to test] -``` - -**Verdict meanings:** -- `APPROVE`: Ready to create PR -- `REQUEST_CHANGES`: Issues to fix before PR creation -- `COMMENT`: Minor items, can create PR but note feedback - -## Notes - -- This is the builder's final self-review before hand-off -- The PR_SUMMARY in your output can be used as the PR description -- Focus on "is this ready for someone else to review" not "is this perfect" -- Any issues found here are cheaper to fix than during integration review diff --git a/codev/protocols/spir/consult-types/spec-review.md b/codev/protocols/spir/consult-types/spec-review.md deleted file mode 100644 index b537e7cc6..000000000 --- a/codev/protocols/spir/consult-types/spec-review.md +++ /dev/null @@ -1,61 +0,0 @@ -# Specification Review Prompt - -## Context -You are reviewing a feature specification during the Specify phase. Your role is to ensure the spec is complete, correct, and feasible before it moves to human approval. - -## Baked Decisions - -If the issue body or the spec's Constraints section includes content under a "Baked Decisions" heading, the architect has marked those choices as fixed. Do not autonomously challenge them: do not propose alternative languages, frameworks, deployment shapes, or dependencies that contradict a baked decision. You may `COMMENT` with concerns about a baked decision (the architect decides whether to rescind it); reserve `REQUEST_CHANGES` for the case where the spec **fails to honor** a stated baked decision — that is a real defect. - -If the baked decisions themselves contain contradictions (e.g., two different language choices), do not pick one — `REQUEST_CHANGES` and ask the architect to clarify before proceeding. - -## Focus Areas - -1. **Completeness** - - Are all requirements clearly stated? - - Are success criteria defined? - - Are edge cases considered? - - Is scope well-bounded (not too broad or vague)? - -2. **Correctness** - - Do requirements make sense technically? - - Are there contradictions? - - Is the problem statement accurate? - -3. **Feasibility** - - Can this be implemented with available tools/constraints? - - Are there obvious technical blockers? - - Is the scope realistic for a single spec? - -4. **Clarity** - - Would a builder understand what to build? - - Are acceptance criteria testable? - - Is terminology consistent? - -## Verdict Format - -After your review, provide your verdict in exactly this format: - -``` ---- -VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT] -SUMMARY: [One-line summary of your assessment] -CONFIDENCE: [HIGH | MEDIUM | LOW] ---- -KEY_ISSUES: -- [Issue 1 or "None"] -- [Issue 2] -... -``` - -**Verdict meanings:** -- `APPROVE`: Spec is ready for human review -- `REQUEST_CHANGES`: Significant issues must be fixed before proceeding -- `COMMENT`: Minor suggestions, can proceed but consider feedback - -## Notes - -- You are NOT reviewing code - you are reviewing the specification document -- Focus on WHAT is being built, not HOW it will be implemented (that's for plan review) -- Be constructive - identify issues AND suggest solutions -- If the spec references other specs, note if context seems missing diff --git a/codev/protocols/spir/prompts/implement.md b/codev/protocols/spir/prompts/implement.md deleted file mode 100644 index bacc8502e..000000000 --- a/codev/protocols/spir/prompts/implement.md +++ /dev/null @@ -1,215 +0,0 @@ -# IMPLEMENT Phase Prompt - -You are executing the **IMPLEMENT** phase of the SPIR protocol. - -## Your Goal - -Write clean, well-structured code AND tests that implement the current plan phase. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Plan Phase**: {{plan_phase_id}} - {{plan_phase_title}} - -## ⚠️ SCOPE RESTRICTION — READ THIS FIRST - -**You are implementing ONLY the current plan phase: {{plan_phase_id}} ({{plan_phase_title}}).** - -- **DO NOT** implement other phases. Other phases will be handled in subsequent porch iterations. -- **DO NOT** read the full plan file and implement everything you see. -- The plan phase details are included below under "Current Plan Phase Details". That is your ONLY scope. -- If you need to reference the spec for requirements, read `codev/specs/{{project_id}}-*.md` but ONLY implement what the current phase requires. - -## What Happens After You Finish - -When you signal `PHASE_COMPLETE`, porch will: -1. Run 3-way consultation (Gemini, Codex, Claude) on your implementation -2. Check that tests exist and pass -3. If reviewers request changes, you'll be respawned with their feedback -4. Once approved, porch commits and moves to the next plan phase - -## Spec Compliance (CRITICAL) - -**The spec is the source of truth. Code that doesn't match the spec is wrong, even if it "works".** - -### Trust Hierarchy - -``` -SPEC (source of truth) - ↓ -PLAN (implementation guide derived from spec) - ↓ -EXISTING CODE (NOT TRUSTED - must be validated against spec) -``` - -**Never trust existing code over the spec.** Previous implementations may have drifted. - -### Pre-Implementation Sanity Check (PISC) - -**Before writing ANY code:** - -1. ✅ "Have I read the spec in the last 30 minutes?" -2. ✅ "If the spec has a 'Traps to Avoid' section, have I read it?" -3. ✅ "Does my approach match the spec's Technical Implementation section?" -4. ✅ "If the spec has code examples, am I following them?" -5. ✅ "Does the existing code I'm building on actually match the spec?" - -**If ANY answer is "no" or "unsure" → STOP and re-read the spec.** - -### Avoiding "Fixing Mode" - -A dangerous pattern: You start looking at symptoms in code, making incremental fixes, copying existing patterns - without going back to the spec. This leads to: -- Cargo-culting patterns that may be wrong -- Building on broken foundations -- Implementing something different from the spec - -**When you catch yourself "fixing" code:** -1. STOP -2. Ask: "What does the spec say about this?" -3. Re-read the spec's Traps to Avoid section -4. Verify existing code matches the spec before building on it - -## Prerequisites - -Before implementing, verify: -1. Previous phase (if any) is committed to git -2. You've read the plan phase you're implementing -3. You understand the success criteria for this phase -4. Dependencies from earlier phases are available - -## Process - -### 1. Review the Plan Phase - -Read the current phase in the plan: -- What is the objective? -- What files need to be created/modified? -- What are the success criteria? -- What dependencies exist? - -### 2. Set Up - -- Verify you're on the correct branch -- Check that previous phase is committed: `git log --oneline -5` -- Ensure build passes before starting: `npm run build` (or equivalent) - -### 3. Implement the Code - -Write the code following these principles: - -**Code Quality Standards**: -- Self-documenting code (clear names, obvious structure) -- No commented-out code -- No debug prints in final code -- Explicit error handling -- Follow project style guide - -**Implementation Approach**: -- Work on one file at a time -- Make small, incremental changes -- Document complex logic with comments - -### 4. Write Tests - -**Tests are required.** For each piece of functionality you implement: - -- Write unit tests for core logic -- Write integration tests if the phase involves multiple components -- Test error cases and edge conditions -- Ensure tests are deterministic (no flaky tests) - -**Test file locations** (follow project conventions): -- `tests/` or `__tests__/` directories -- `*.test.ts` or `*.spec.ts` naming - -### 5. Verify Everything Works - -Run both build and tests: - -```bash -npm run build # Must pass -npm test # Must pass -``` - -**Important**: Don't assume these commands exist. Check `package.json` first. - -Fix any errors before signaling completion. - -### 6. Self-Review - -Before signaling completion: -- Read through all code changes -- Read through all test changes -- Verify code matches the spec requirements -- Ensure no accidental debug code -- Check test coverage is adequate - -## Output - -When complete, you should have: -- Modified/created source files as specified in the plan phase -- Tests covering the new functionality -- All build checks passing -- All tests passing - -## Signals - -When implementation AND tests are complete and passing: - -``` -PHASE_COMPLETE -``` - -If you encounter a blocker: - -``` -BLOCKED:reason goes here -``` - -If you need spec/plan clarification: - -``` - -Your specific questions here - -``` - -## Important Notes - -1. **Follow the plan** - Implement what's specified, not more -2. **Don't over-engineer** - Simplest solution that works -3. **Don't skip error handling** - But don't go overboard either -4. **Keep changes focused** - Only touch files in this phase -5. **Build AND tests must pass** - Don't signal complete until both pass -6. **Write tests** - Every implementation phase needs tests - -## What NOT to Do - -- Don't modify files outside this phase's scope -- Don't add features not in the spec -- Don't leave TODO comments for later (fix now or note as blocker) -- Don't skip writing tests -- Don't use `git add .` or `git add -A` when you commit (security risk) - -## Handling Problems - -**If the plan is unclear**: -Signal `AWAITING_INPUT` with your specific question. - -**If you discover the spec is wrong**: -Signal `BLOCKED` and explain the issue. The Architect may need to update the spec. - -**If a dependency is missing**: -Signal `BLOCKED` with details about what's missing. - -**If build or tests fail and you can't fix it**: -Signal `BLOCKED` with the error message. - -**If you encounter pre-existing flaky tests** (tests that fail intermittently but are unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks -2. **DO NOT** skip porch checks or use workarounds to avoid the failure -3. **DO** mark the flaky test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: intermittent timeout, skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section so the team can follow up -5. Commit the skip and continue with your work diff --git a/codev/protocols/spir/prompts/plan.md b/codev/protocols/spir/prompts/plan.md deleted file mode 100644 index 2c12250dd..000000000 --- a/codev/protocols/spir/prompts/plan.md +++ /dev/null @@ -1,118 +0,0 @@ -# PLAN Phase Prompt - -You are executing the **PLAN** phase of the SPIR protocol. - -## Your Goal - -Transform the approved specification into an executable implementation plan with clear phases. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` -- **Plan File**: `codev/plans/{{artifact_name}}.md` - -## Prerequisites - -Before planning, verify: -1. The specification exists and has been approved -2. You've read and understood the entire spec -3. Success criteria are clear and measurable - -## Process - -### 1. Analyze the Specification - -Read the spec thoroughly. Identify: -- All functional requirements -- Non-functional requirements -- Dependencies and constraints -- Success criteria to validate against - -### 2. Identify Implementation Phases - -Break the work into logical phases. Each phase should be: -- **Self-contained** - A complete unit of functionality -- **Independently testable** - Can be verified on its own -- **Valuable** - Delivers observable progress -- **Committable** - Can be a single atomic commit - -Good phase examples: -- "Database Schema" - Creates all tables/migrations -- "Core API Endpoints" - Implements main REST routes -- "Authentication Flow" - Handles login/logout/session - -Bad phase examples: -- "Setup" - Too vague -- "Part 1" - Not descriptive -- "Everything" - Not broken down - -### 3. Define Each Phase - -For each phase, document: -- **Objective** - Single clear goal -- **Files to modify/create** - Specific paths -- **Dependencies** - Which phases must complete first -- **Success criteria** - How to know it's done -- **Test approach** - What tests will verify it - -### 4. Order Phases by Dependencies - -Arrange phases so dependencies are satisfied: -``` -Phase 1: Database Schema (no dependencies) -Phase 2: Data Models (depends on Phase 1) -Phase 3: API Endpoints (depends on Phase 2) -Phase 4: Frontend Integration (depends on Phase 3) -``` - -### 5. Finalize - -After completing the plan draft, signal completion. Porch will run 3-way consultation (Gemini, Codex, Claude) automatically via the verify step. If reviewers request changes, you'll be respawned with their feedback. - -## Output - -Create the plan file at `codev/plans/{{artifact_name}}.md`, following the template below: - -{{> protocols/spir/templates/plan.md}} - -## Signals - -Emit appropriate signals based on your progress: - -- After completing the plan draft: - ``` - PLAN_DRAFTED - ``` - -## Commit Cadence - -Make commits at these milestones: -1. `[Spec {{project_id}}] Initial implementation plan` -2. `[Spec {{project_id}}] Plan with multi-agent review` -3. `[Spec {{project_id}}] Plan with user feedback` -4. `[Spec {{project_id}}] Final approved plan` - -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: -```bash -git add codev/plans/{{artifact_name}}.md -``` - -## Important Notes - -1. **No time estimates** - Don't include hours/days/weeks -3. **Be specific about files** - Exact paths, not "the config file" -4. **Keep phases small** - 1-3 files per phase is ideal -5. **Document dependencies clearly** - Prevents blocked work - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't write code (that's for Implement phase) -- Don't estimate time (meaningless in AI development) -- Don't create phases that can't be independently tested -- Don't skip dependency analysis -- Don't make phases too large (if >5 files, split it) -- Don't use `git add .` or `git add -A` (security risk) diff --git a/codev/protocols/spir/prompts/review.md b/codev/protocols/spir/prompts/review.md deleted file mode 100644 index 22af9aec4..000000000 --- a/codev/protocols/spir/prompts/review.md +++ /dev/null @@ -1,278 +0,0 @@ -# REVIEW Phase Prompt - -You are executing the **REVIEW** phase of the SPIR protocol. - -## Your Goal - -Perform a comprehensive review, document lessons learned, and prepare for PR submission. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` -- **Plan File**: `codev/plans/{{artifact_name}}.md` -- **Review File**: `codev/reviews/{{artifact_name}}.md` - -## Prerequisites - -Before review, verify: -1. All implementation phases are committed -2. All tests are passing -3. Build is passing -4. Spec compliance verified for all phases - -Verify commits: `git log --oneline | grep "[Spec {{project_id}}]"` - -## Process - -### 1. Comprehensive Review - -Review the entire implementation: - -**Code Quality**: -- Is the code readable and maintainable? -- Are there any code smells? -- Is error handling consistent? -- Are there any security concerns? - -**Architecture**: -- Does the implementation fit well with existing code? -- Are there any architectural concerns? -- Is the design scalable if needed? - -**Documentation**: -- Is code adequately commented where needed? -- Are public APIs documented? -- Is README updated if needed? - -### 2. Spec Comparison - -Compare final implementation to original specification: - -- What was delivered vs what was specified? -- Any deviations? Document why. -- All success criteria met? - -### 3. Create Review Document - -Create `codev/reviews/{{artifact_name}}.md`: - -```markdown -# Review: {{title}} - -## Summary -Brief description of what was implemented. - -## Spec Compliance -- [x] Requirement 1: Implemented as specified -- [x] Requirement 2: Implemented with deviation (see below) -- [x] Requirement 3: Implemented as specified - -## Deviations from Plan -- **Phase X**: [What changed and why] - -## Lessons Learned - -### What Went Well -- [Positive observation 1] -- [Positive observation 2] - -### Challenges Encountered -- [Challenge 1]: [How it was resolved] -- [Challenge 2]: [How it was resolved] - -### What Would Be Done Differently -- [Insight 1] -- [Insight 2] - -### Methodology Improvements -- [Suggested improvement to SPIR protocol] -- [Suggested improvement to tooling] - -## Technical Debt -- [Any shortcuts taken that should be addressed later] - -## Consultation Feedback - -[See instructions below] - -## Flaky Tests -- [Any pre-existing tests that were skipped as flaky during this project] -- [Include test name, file path, and observed failure mode] -- [If none: "No flaky tests encountered"] - -## Follow-up Items -- [Any items identified for future work] -``` - -### 3b. Include Consultation Feedback - -**IMPORTANT**: The review document MUST include a `## Consultation Feedback` section that summarizes all consultation concerns raised during every phase of the project and how the builder responded. - -Read the consultation output files from the project directory (`codev/projects/{project-id}-*/`). For each phase that had consultation, create a subsection organized by phase, round, and model: - -```markdown -## Consultation Feedback - -### Specify Phase (Round 1) - -#### Gemini -- **Concern**: [Summary of the concern] - - **Addressed**: [What was changed to resolve it] - -#### Codex -- **Concern**: [Summary] - - **Rebutted**: [Why the current approach is correct] - -#### Claude -- No concerns raised (APPROVE) - -### Plan Phase (Round 1) -... -``` - -**Response types** — each concern gets exactly one: -- **Addressed**: Builder made a change to resolve the concern -- **Rebutted**: Builder explains why the concern doesn't apply -- **N/A**: Concern is out of scope, already handled elsewhere, or moot - -**Edge cases**: -- If all reviewers approved with no concerns: "No concerns raised — all consultations approved" -- For COMMENT verdicts: include their feedback (non-blocking but useful context) -- For CONSULT_ERROR (model failure): note "Consultation failed for [model]" -- If a phase had multiple rounds, give each round its own subsection - -### 4. Update Architecture and Lessons Learned Documentation - -**MANDATORY**: The review document MUST include `## Architecture Updates` and `## Lessons Learned Updates` sections. Porch will block advancement if these are missing. - -Each governance doc has **two tiers** (Spec 987) — **route** each new fact/lesson to the right tier; do **not** just append to the cold archive: -- **HOT** — `codev/resources/arch-critical.md` / `lessons-critical.md`: tiny, **hard-capped**, **always injected** into every prompt and into CLAUDE.md/AGENTS.md. The behavior-changer. -- **COLD** — `codev/resources/arch.md` / `lessons-learned.md`: full, on-demand reference. - -**Architecture Updates**: -1. Read `arch-critical.md` (hot) and skim `arch.md` (cold). -2. If this project produced a system-shape fact, route it: - - **Behavior-changing + cross-cutting** (an invariant/decision a future builder must know up front) → add to **`arch-critical.md`**. Respect the cap: if the hot file is full, **demote** a weaker entry into `arch.md` to make room. If you add/rename a top-level `arch.md` section, keep the hot file's cold-doc map accurate. - - **Reference detail** (subsystem mechanism, file location, one-off) → add to **`arch.md`** (cold). -3. Describe what you routed where in the `## Architecture Updates` section. If nothing qualifies: write "No architecture updates needed" with a brief reason. - -**Lessons Learned Updates**: -1. Read `lessons-critical.md` (hot) and skim `lessons-learned.md` (cold). -2. If this project produced a durable lesson, route it: - - **Behavior-changing + cross-cutting** (a rule that should change how the next project is built) → add to **`lessons-critical.md`**, respecting the cap (demote a weaker entry into `lessons-learned.md` if full). - - **Spec-narrow recipe / reference tip** → add to **`lessons-learned.md`** (cold). Spec-narrow recipes belong in the cold archive, never the always-on hot file. -3. Describe what you routed where in the `## Lessons Learned Updates` section. If nothing qualifies: write "No lessons learned updates needed" with a brief reason. - -**Never** grow a hot file past its cap by appending — route to cold or displace. The cap is what keeps the hot tier cheap enough to always inject. - -### 4b. Update Other Documentation - -If needed, also update: -- README.md (new features, changed behavior) -- API documentation - -### 5. Final Verification - -Before PR: -- [ ] All tests pass (use project-specific test command) -- [ ] Build passes (use project-specific build command) -- [ ] Lint passes (if configured) -- [ ] No uncommitted changes: `git status` -- [ ] Review document complete - -### 6. Create Pull Request - -**IMPORTANT: Create the PR BEFORE signaling completion.** The PR must exist so that -porch consultation reviews the actual PR, and the architect can review a real PR -when the pr gate fires. - -**PR body requirements**: The PR body MUST include `Closes #` (for feature issues) -or `Fixes #` (for bug issues) for the driving GitHub issue. If the PR closes -multiple issues (e.g. duplicates consolidated), include one keyword per issue. -Without this, GitHub will not auto-close the issue on merge. - -**Exception**: if this PR only partially addresses the issue (e.g. one phase of a -multi-PR effort), DO NOT use `Closes`/`Fixes` — reference the issue with `Refs #` -or `Part of #` instead. The issue stays open until the follow-up PR closes it. - -```bash -gh pr create --title "[Spec {{project_id}}] {{title}}" --body "$(cat <<'EOF' -## Summary -[Brief description of the implementation] - -Closes # - -## Changes -- [Change 1] -- [Change 2] - -## Testing -- All unit tests passing -- Integration tests added for [X] -- Manual testing completed for [Y] - -## Spec -Link: codev/specs/{{artifact_name}}.md - -## Review -Link: codev/reviews/{{artifact_name}}.md -EOF -)" -``` - -### 7. Signal Completion - -After the PR is created, signal completion. Porch will run 3-way consultation -(Gemini, Codex, Claude) automatically via the verify step. If reviewers request -changes, you'll be respawned with their feedback. - -## Output - -- Review document at `codev/reviews/{{artifact_name}}.md` -- Updated documentation (if needed) -- Pull request created and ready for review - -## Signals - -- After review document is complete: - ``` - REVIEW_COMPLETE - ``` - -- After PR is created — signal completion so porch runs consultation: - ``` - PR_READY - ``` - -## Important Notes - -1. **Be honest in lessons learned** - Future you will thank present you -3. **Document deviations** - They're not failures, they're learnings -4. **Update methodology** - If you found a better way, document it -5. **Don't skip the checklist** - It catches last-minute issues -6. **Clean PR description** - Makes review easier - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't skip lessons learned ("nothing to report") -- Don't merge your own PR (Architect handles integration) -- Don't leave uncommitted changes -- Don't forget to update documentation -- Don't rush this phase - it's valuable for learning -- Don't use `git add .` or `git add -A` (security risk) - -## Review Prompts for Reflection - -Ask yourself: -- What surprised me during implementation? -- Where did I spend the most time? Was it avoidable? -- What would have helped me go faster? -- Did the spec adequately describe what was needed? -- Did the plan phases make sense in hindsight? -- What tests caught issues? What tests were unnecessary? - -Capture these reflections in the lessons learned section. diff --git a/codev/protocols/spir/prompts/specify.md b/codev/protocols/spir/prompts/specify.md deleted file mode 100644 index 3716f7969..000000000 --- a/codev/protocols/spir/prompts/specify.md +++ /dev/null @@ -1,145 +0,0 @@ -# SPECIFY Phase Prompt - -You are executing the **SPECIFY** phase of the SPIR protocol. - -## Your Goal - -Create a comprehensive specification document that thoroughly explores the problem space and proposed solution. - -## Context - -- **Project ID**: {{project_id}} -- **Project Title**: {{title}} -- **Current State**: {{current_state}} -- **Spec File**: `codev/specs/{{artifact_name}}.md` - -## Process - -### 0. Check for Existing Spec (ALWAYS DO THIS FIRST) - -**Before asking ANY questions**, check if a spec already exists: - -```bash -ls codev/specs/{{project_id}}-*.md -``` - -**If a spec file exists:** -1. READ IT COMPLETELY - the answers to your questions are already there -2. The spec author has already made the key decisions -3. DO NOT ask clarifying questions - proceed directly to consultation -4. Your job is to REVIEW and IMPROVE the existing spec, not rewrite it from scratch - -**If no spec exists:** Proceed to Step 1 below. - -### 0.5 Baked Decisions - -Before exploring solution approaches, check the issue body for a section named "Baked Decisions" (any heading level, case-insensitive). If present, copy its content verbatim into the spec's Constraints section and treat each item as fixed. Do not autonomously relitigate the architect's choices in your Solution Exploration. If you discover a serious problem with a baked decision, raise it via `afx send architect` rather than overriding it in the spec. - -If two baked decisions contradict each other (e.g., two different language choices), do not pick one — pause, flag the contradiction via `afx send`, and wait for resolution before drafting. - -### 1. Clarifying Questions (ONLY IF NO SPEC EXISTS) - -Before writing anything, ask clarifying questions to understand: -- What problem is being solved? -- Who are the stakeholders? -- What are the constraints? -- What's in scope vs out of scope? -- What does success look like? - -If this is your first iteration AND no spec exists, ask these questions now and wait for answers. - -**CRITICAL**: Do NOT ask questions if a spec already exists. The spec IS the answer. - -**On subsequent iterations**: If questions were already answered, acknowledge the answers and proceed to the next step. - -### 2. Problem Analysis - -Once you have answers, document: -- The problem being solved (clearly articulated) -- Current state vs desired state -- Stakeholders and their needs -- Assumptions and constraints - -### 3. Solution Exploration - -Generate multiple solution approaches. For each: -- Technical design overview -- Trade-offs (pros/cons) -- Complexity assessment -- Risk assessment - -### 4. Open Questions - -List uncertainties categorized as: -- **Critical** - blocks progress -- **Important** - affects design -- **Nice-to-know** - optimization - -### 5. Success Criteria - -Define measurable acceptance criteria: -- Functional requirements (MUST, SHOULD, COULD) -- Non-functional requirements (performance, security) -- Test scenarios - -### 6. Finalize - -After completing the spec draft, signal completion. Porch will run 3-way consultation (Gemini, Codex, Claude) automatically via the verify step. If reviewers request changes, you'll be respawned with their feedback. - -## Output - -Create or update the specification file at `codev/specs/{{artifact_name}}.md`. - -**IMPORTANT**: Keep spec/plan/review filenames in sync: -- Spec: `codev/specs/{{artifact_name}}.md` -- Plan: `codev/plans/{{artifact_name}}.md` -- Review: `codev/reviews/{{artifact_name}}.md` - -## Signals - -Emit appropriate signals based on your progress: - -- When waiting for clarifying question answers, **include your questions in the signal**: - ``` - - Please answer these questions: - 1. What should the primary use case be - internal tooling or customer-facing? - 2. What are the key constraints we should consider? - 3. Who are the main stakeholders? - - ``` - - The content inside the signal tag is displayed prominently to the user. - -- After completing the initial spec draft: - ``` - SPEC_DRAFTED - ``` - - -## Commit Cadence - -Make commits at these milestones: -1. `[Spec {{project_id}}] Initial specification draft` -2. `[Spec {{project_id}}] Specification with multi-agent review` -3. `[Spec {{project_id}}] Specification with user feedback` -4. `[Spec {{project_id}}] Final approved specification` - -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: -```bash -git add codev/specs/{{artifact_name}}.md -``` - -## Important Notes - -1. **Be thorough** - A good spec prevents implementation problems -3. **Be specific** - Vague specs lead to wrong implementations -4. **Include examples** - Concrete examples clarify intent - -## What NOT to Do - -- Don't run `consult` commands yourself (porch handles consultations) -- Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) -- Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) diff --git a/codev/protocols/spir/protocol.json b/codev/protocols/spir/protocol.json deleted file mode 100644 index 02ecb8941..000000000 --- a/codev/protocols/spir/protocol.json +++ /dev/null @@ -1,172 +0,0 @@ -{ - "$schema": "../../protocol-schema.json", - "name": "spir", - "alias": "spider", - "version": "2.2.0", - "description": "SPIR: Specify → Plan → Implement → Review with build-verify cycles", - "input": { - "type": "spec", - "required": false, - "default_for": ["--project", "-p"] - }, - "phases": [ - { - "id": "specify", - "name": "Specify", - "description": "Write specification with 3-way review", - "type": "build_verify", - "build": { - "prompt": "specify.md", - "artifact": "codev/specs/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "spec", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "gate": "spec-approval", - "next": "plan" - }, - { - "id": "plan", - "name": "Plan", - "description": "Write implementation plan with 3-way review", - "type": "build_verify", - "build": { - "prompt": "plan.md", - "artifact": "codev/plans/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "plan", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "plan_exists": "test -f codev/plans/${PROJECT_TITLE}.md", - "has_phases_json": "grep -qE '\"phases\"\\s*:' codev/plans/${PROJECT_TITLE}.md", - "min_two_phases": "grep -o '\"id\": *\"[^\"]*\"' codev/plans/${PROJECT_TITLE}.md | wc -l | awk '$1 >= 2 {exit 0} {exit 1}'" - }, - "gate": "plan-approval", - "next": "implement" - }, - { - "id": "implement", - "name": "Implement", - "description": "Implement code with 3-way review per plan phase", - "type": "per_plan_phase", - "build": { - "prompt": "implement.md", - "artifact": "src/**/*.{ts,tsx,js,jsx}" - }, - "verify": { - "type": "impl", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "build": { - "command": "npm run build", - "on_fail": "retry", - "max_retries": 2 - }, - "tests": { - "command": "npm test -- --exclude='**/e2e/**'", - "description": "Unit tests only - e2e tests run in review phase", - "on_fail": "retry", - "max_retries": 2 - } - }, - "transition": { - "on_complete": "implement", - "on_all_phases_complete": "review" - } - }, - { - "id": "review", - "name": "Review", - "description": "Final review and PR with 3-way review", - "type": "build_verify", - "build": { - "prompt": "review.md", - "artifact": "codev/reviews/${PROJECT_TITLE}.md" - }, - "verify": { - "type": "pr", - "models": ["gemini", "codex", "claude"], - "parallel": true - }, - "max_iterations": 8, - "on_complete": { - "commit": true, - "push": true - }, - "checks": { - "pr_exists": { - "command": "gh pr list --state all --head \"$(git branch --show-current)\" --json number --jq 'length' | grep -q '^[1-9]'", - "description": "PR must be created before signaling completion" - }, - "review_has_arch_updates": { - "command": "grep -q '## Architecture Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Architecture Updates' section (what changed in arch.md, or why no changes needed)" - }, - "review_has_lessons_updates": { - "command": "grep -q '## Lessons Learned Updates' codev/reviews/${PROJECT_TITLE}.md", - "description": "Review must include '## Lessons Learned Updates' section (what changed in lessons-learned.md, or why no changes needed)" - }, - "e2e_tests": { - "command": "npm run test:e2e 2>&1 || echo 'e2e tests skipped (not configured)'", - "description": "Full e2e test suite - only runs in review phase", - "optional": true - } - }, - "gate": "pr", - "next": "verify" - }, - { - "id": "verify", - "name": "Verify", - "description": "Post-merge environmental verification (optional — skip with porch verify --skip)", - "type": "once", - "gate": "verify-approval", - "next": null - } - ], - "signals": { - "PHASE_COMPLETE": { - "description": "Signal current build phase is complete", - "transitions_to": "verify" - }, - "BLOCKED": { - "description": "Signal implementation is blocked", - "requires": "reason" - } - }, - "phase_completion": { - "build_succeeds": "npm run build 2>&1", - "tests_pass": "npm test 2>&1", - "commit_has_code": "git log -1 --name-only --pretty=format: | grep -qE '\\.(ts|tsx|js|jsx|py|go|rs)$'" - }, - "defaults": { - "mode": "strict", - "max_iterations": 8, - "verify": { - "models": ["gemini", "codex", "claude"], - "parallel": true - } - } -} diff --git a/codev/protocols/spir/templates/plan.md b/codev/protocols/spir/templates/plan.md deleted file mode 100644 index 831199848..000000000 --- a/codev/protocols/spir/templates/plan.md +++ /dev/null @@ -1,204 +0,0 @@ -# Plan: [Title] - -## Metadata -- **ID**: plan-[YYYY-MM-DD]-[short-name] -- **Status**: draft -- **Specification**: [Link to codev/specs/spec-file.md] -- **Created**: [YYYY-MM-DD] - -## Executive Summary -[Brief overview of the implementation approach chosen and why. Reference the specification's selected approach.] - -## Success Metrics -[Copy from specification and add implementation-specific metrics] -- [ ] All specification criteria met -- [ ] Test coverage >90% -- [ ] Performance benchmarks achieved -- [ ] Zero critical security issues -- [ ] Documentation complete - -## Phases (Machine Readable) - - - -```json -{ - "phases": [ - {"id": "phase_1", "title": "Phase 1 Title Here"}, - {"id": "phase_2", "title": "Phase 2 Title Here"}, - {"id": "phase_3", "title": "Phase 3 Title Here"} - ] -} -``` - -## Phase Breakdown - -### Phase 1: [Descriptive Name] -**Dependencies**: None - -#### Objectives -- [Clear, single objective for this phase] -- [What value does this phase deliver?] - -#### Deliverables -- [ ] [Specific deliverable 1] -- [ ] [Specific deliverable 2] -- [ ] [Tests for this phase] -- [ ] [Documentation updates] - -#### Implementation Details -[Specific technical approach for this phase. Include: -- Key files/modules to create or modify -- Architectural decisions -- API contracts -- Data models] - -#### Acceptance Criteria -- [ ] [Testable criterion 1] -- [ ] [Testable criterion 2] -- [ ] All tests pass -- [ ] Code review completed - -#### Test Plan -- **Unit Tests**: [What to test] -- **Integration Tests**: [What to test] -- **Manual Testing**: [Scenarios to verify] - -#### Rollback Strategy -[How to revert this phase if issues arise] - -#### Risks -- **Risk**: [Specific risk for this phase] - - **Mitigation**: [How to address] - ---- - -### Phase 2: [Descriptive Name] -**Dependencies**: Phase 1 - -[Repeat structure for each phase] - ---- - -### Phase 3: [Descriptive Name] -**Dependencies**: Phase 2 - -[Continue for all phases] - -## Dependency Map -``` -Phase 1 ──→ Phase 2 ──→ Phase 3 - ↓ - Phase 4 (optional) -``` - -## Resource Requirements -### Development Resources -- **Engineers**: [Expertise needed] -- **Environment**: [Dev/staging requirements] - -### Infrastructure -- [Database changes] -- [New services] -- [Configuration updates] -- [Monitoring additions] - -## Integration Points -### External Systems -- **System**: [Name] - - **Integration Type**: [API/Database/Message Queue] - - **Phase**: [Which phase needs this] - - **Fallback**: [What if unavailable] - -### Internal Systems -[Repeat structure] - -## Risk Analysis -### Technical Risks -| Risk | Probability | Impact | Mitigation | Owner | -|------|------------|--------|------------|-------| -| [Risk 1] | L/M/H | L/M/H | [Strategy] | [Name] | - -### Schedule Risks -| Risk | Probability | Impact | Mitigation | Owner | -|------|------------|--------|------------|-------| -| [Risk 1] | L/M/H | L/M/H | [Strategy] | [Name] | - -## Validation Checkpoints -1. **After Phase 1**: [What to validate] -2. **After Phase 2**: [What to validate] -3. **Before Production**: [Final checks] - -## Monitoring and Observability -### Metrics to Track -- [Metric 1: Description and threshold] -- [Metric 2: Description and threshold] - -### Logging Requirements -- [What to log and at what level] -- [Retention requirements] - -### Alerting -- [Alert condition and severity] -- [Who to notify] - -## Documentation Updates Required -- [ ] API documentation -- [ ] Architecture diagrams -- [ ] Runbooks -- [ ] User guides -- [ ] Configuration guides - -## Post-Implementation Tasks -- [ ] Performance validation -- [ ] Security audit -- [ ] Load testing -- [ ] User acceptance testing -- [ ] Monitoring validation - -## Expert Review -**Date**: [YYYY-MM-DD] -**Model**: [Model consulted] -**Key Feedback**: -- [Feasibility assessment] -- [Missing considerations] -- [Risk identification] -- [Alternative suggestions] - -**Plan Adjustments**: -- [How the plan was modified based on feedback] - -## Approval -- [ ] Technical Lead Review -- [ ] Engineering Manager Approval -- [ ] Resource Allocation Confirmed -- [ ] Expert AI Consultation Complete - -## Change Log -| Date | Change | Reason | Author | -|------|--------|--------|--------| -| [Date] | [What changed] | [Why] | [Who] | - -## Notes -[Additional context, assumptions, or considerations] - ---- - -## Amendment History - -This section tracks all TICK amendments to this plan. TICKs modify both the spec and plan together as an atomic unit. - - - - \ No newline at end of file diff --git a/codev/protocols/spir/templates/review.md b/codev/protocols/spir/templates/review.md deleted file mode 100644 index af72f0e62..000000000 --- a/codev/protocols/spir/templates/review.md +++ /dev/null @@ -1,120 +0,0 @@ -# Review: [Feature/Project Name] - -## Summary - -[1-3 sentences: what was built, how many phases, net outcome.] - -## Spec Compliance - -- [x] AC1: [Description] (Phase N) -- [x] AC2: [Description] (Phase N) -- [ ] ACn: [Not met — reason] - -## Deviations from Plan - -- **Phase N**: [What changed and why] - -## Key Metrics - -- **Commits**: [N] on the branch -- **Tests**: [N] passing ([N] existing + [N] new) -- **Files created**: [list] -- **Files deleted**: [list] -- **Net LOC impact**: [+/-N lines] - -## Timelog - -All times [timezone], [date range]. - -| Time | Event | -|------|-------| -| HH:MM | First commit: [description] | -| HH:MM | [Phase/milestone] | -| — | **GATE: [gate-name]** (human approval required) | -| HH:MM | Implementation begins | -| HH:MM | Phase N complete after N iterations | -| HH:MM | **GATE: pr** | - -### Autonomous Operation - -| Period | Duration | Activity | -|--------|----------|----------| -| Spec + Plan | ~Nm | [Summary] | -| Human gate wait | ~Nh Nm | Idle — waiting for approval | -| Implementation → PR | ~Nh Nm | N phases, N consultation rounds | - -**Total wall clock** (first commit to pr): **Xh Ym** -**Total autonomous work time** (excluding gate waits): **~Xh Ym** -**Context window resets**: [N] (resumed automatically / required manual restart) - -## Consultation Iteration Summary - -[N] consultation files produced ([N] rounds x [N] models). [N] APPROVE, [N] REQUEST_CHANGES, [N] COMMENT. - -| Phase | Iters | Who Blocked | What They Caught | -|-------|-------|-------------|------------------| -| Specify | N | [Model] | [Brief description] | -| Plan | N | [Model] | [Brief description] | -| Phase 1 | N | [Model] | [Brief description] | -| Phase N | N | [Model] | [Brief description] | -| Review | N | [Model] | [Brief description] | - -**Most frequent blocker**: [Model] — blocked in N of N rounds, focused on: [pattern]. - -### Avoidable Iterations - -Iterations that could have been prevented with better builder behavior: - -1. **[Pattern]**: [Specific thing the builder should have done without needing reviewer feedback. E.g., "Run exhaustive grep before claiming all instances fixed."] - -2. **[Pattern]**: [Another avoidable iteration pattern.] - -## Consultation Feedback - -[For each phase that had consultation, summarize every reviewer's concerns and how the builder responded. Use **Addressed** (fixed), **Rebutted** (disagreed with reasoning), or **N/A** (out of scope/moot) for each concern. If all reviewers approved with no concerns: "No concerns raised — all consultations approved."] - -### [Phase] Phase (Round N) - -#### Gemini -- **Concern**: [Summary of concern] - - **Addressed**: [What was changed] - -#### Codex -- **Concern**: [Summary of concern] - - **Rebutted**: [Why current approach is correct] - -#### Claude -- No concerns raised (APPROVE) - -## Lessons Learned - -### What Went Well -- [Specific positive observation — what worked and why] - -### Challenges Encountered -- **[Challenge]**: [How it was resolved. How many iterations it cost.] - -### What Would Be Done Differently -- [Actionable improvement for future builders] - -## Architecture Updates - -[What you routed where — HOT `codev/resources/arch-critical.md` (tiny, capped, always-injected) vs COLD `codev/resources/arch.md` (reference) — or why no changes were needed.] - -- Routed: [hot | cold] — [fact/section] — [what was added/changed; note any demotion if the hot file was full] -- Or: "No architecture updates needed — [brief reason]" - -## Lessons Learned Updates - -[What you routed where — HOT `codev/resources/lessons-critical.md` (capped) vs COLD `codev/resources/lessons-learned.md` (reference) — or why no changes were needed.] - -- Routed: [hot | cold] — [category] — [lesson summary] -- Or: "No lessons learned updates needed — [brief reason]" - -## Technical Debt - -- [Any shortcuts taken or inconsistencies introduced] - -## Follow-up Items - -- [Items identified for future work, outside this spec's scope] diff --git a/codev/protocols/spir/templates/spec.md b/codev/protocols/spir/templates/spec.md deleted file mode 100644 index 03c17315d..000000000 --- a/codev/protocols/spir/templates/spec.md +++ /dev/null @@ -1,182 +0,0 @@ -# Specification: [Title] - - - -## Metadata -- **ID**: spec-[YYYY-MM-DD]-[short-name] -- **Status**: draft -- **Created**: [YYYY-MM-DD] - -## Clarifying Questions Asked - -[List the questions you asked to understand the problem better and the responses received. This shows the discovery process.] - -## Problem Statement -[Clearly articulate the problem being solved. Include context about why this is important, who is affected, and what the current pain points are.] - -## Current State -[Describe how things work today. What are the limitations? What workarounds exist? Include specific examples.] - -## Desired State -[Describe the ideal solution. How should things work after implementation? What specific improvements will users see?] - -## Stakeholders -- **Primary Users**: [Who will directly use this feature?] -- **Secondary Users**: [Who else is affected?] -- **Technical Team**: [Who will implement and maintain this?] -- **Business Owners**: [Who has decision authority?] - -## Success Criteria -- [ ] [Specific, measurable criterion 1] -- [ ] [Specific, measurable criterion 2] -- [ ] [Specific, measurable criterion 3] -- [ ] All tests pass with >90% coverage -- [ ] Performance benchmarks met (specify below) -- [ ] Documentation updated - -## Constraints -### Technical Constraints -- [Existing system limitations] -- [Technology stack requirements] -- [Integration points] - -### Business Constraints -- [Timeline requirements] -- [Budget considerations] -- [Compliance requirements] - -## Assumptions -- [List assumptions being made] -- [Include dependencies on other work] -- [Note any prerequisites] - -## Solution Approaches - -### Approach 1: [Name] -**Description**: [Brief overview of this approach] - -**Pros**: -- [Advantage 1] -- [Advantage 2] - -**Cons**: -- [Disadvantage 1] -- [Disadvantage 2] - -**Estimated Complexity**: [Low/Medium/High] -**Risk Level**: [Low/Medium/High] - -### Approach 2: [Name] -[Repeat structure for additional approaches] - -[Add as many approaches as appropriate for the problem] - -## Open Questions - -### Critical (Blocks Progress) -- [ ] [Question that must be answered before proceeding] - -### Important (Affects Design) -- [ ] [Question that influences technical decisions] - -### Nice-to-Know (Optimization) -- [ ] [Question that could improve the solution] - -## Performance Requirements -- **Response Time**: [e.g., <200ms p95] -- **Throughput**: [e.g., 1000 requests/second] -- **Resource Usage**: [e.g., <500MB memory] -- **Availability**: [e.g., 99.9% uptime] - -## Security Considerations -- [Authentication requirements] -- [Authorization model] -- [Data privacy concerns] -- [Audit requirements] - -## Test Scenarios -### Functional Tests -1. [Scenario 1: Happy path] -2. [Scenario 2: Edge case] -3. [Scenario 3: Error condition] - -### Non-Functional Tests -1. [Performance test scenario] -2. [Security test scenario] -3. [Load test scenario] - -## Dependencies -- **External Services**: [List any external APIs or services] -- **Internal Systems**: [List internal dependencies] -- **Libraries/Frameworks**: [List required libraries] - -## References -- [Link to relevant documentation in codev/ref/] -- [Link to related specifications] -- [Link to architectural diagrams] -- [Link to research materials] - -## Risks and Mitigation -| Risk | Probability | Impact | Mitigation Strategy | -|------|------------|--------|-------------------| -| [Risk 1] | Low/Med/High | Low/Med/High | [How to address] | -| [Risk 2] | Low/Med/High | Low/Med/High | [How to address] | - -## Expert Consultation - -**Date**: [YYYY-MM-DD] -**Models Consulted**: [e.g., GPT-5 and Gemini Pro] -**Sections Updated**: -- [Section name]: [Brief description of change based on consultation] -- [Section name]: [Brief description of change based on consultation] - -Note: All consultation feedback has been incorporated directly into the relevant sections above. - -## Approval -- [ ] Technical Lead Review -- [ ] Product Owner Review -- [ ] Stakeholder Sign-off -- [ ] Expert AI Consultation Complete - -## Notes -[Any additional context or considerations not covered above] - ---- - -## Amendments - -This section tracks all TICK amendments to this specification. TICKs are lightweight changes that refine an existing spec rather than creating a new one. - - - - \ No newline at end of file diff --git a/codev/resources/1252-behavior-baseline.md b/codev/resources/1252-behavior-baseline.md new file mode 100644 index 000000000..589b4ecf3 --- /dev/null +++ b/codev/resources/1252-behavior-baseline.md @@ -0,0 +1,166 @@ + + +# Behavioural metrics (Spec 1252, M12 / Appendix D) + +## B1 — CMAP verdict distribution + +Total verdicts: **160** across 18 projects with review history. + +| Verdict | Count | Share | +|---|---:|---:| +| REQUEST_CHANGES | 83 | 51.88% | +| APPROVE | 66 | 41.25% | +| COMMENT | 11 | 6.88% | + +**B1 REQUEST_CHANGES rate: 51.88%** — the load-bearing metric. + +## B2 — review rounds per plan phase + +mean **1.12**, median 1, max 2 (n=49 phases) + +> Advisory only. The observed range is too narrow to detect a subtle +> regression. Note also that phases advance on builder *rebuttal*, not on +> unanimous approval — 0 terminal phases in this corpus end with 3x APPROVE — +> so a "rounds to unanimity" metric would never resolve. + +## B4 — review rounds per project + +mean **3.06**, median 3 (n=18 projects). Advisory. + +## B3 — candidate scar-rule violations + +Scanned **349** files (codev/reviews + codev/state threads). +Candidate hits: **44** + +> **These are CANDIDATES, not findings.** Keyword mining cannot distinguish +> "we did this" from "never do this". Every hit requires human adjudication +> before the hard rollback trigger fires. B3 is the metric that matters most — +> it is the only one that would catch a compressed scar rule losing its force. + +| Rule | Candidate hits | +|---|---:| +| restart-tower | 21 | +| destructive-git | 9 | +| auto-approve-gate | 7 | +| kill-shellper | 6 | +| afx-from-worktree | 1 | + +### Excerpts for adjudication + +- `codev/reviews/0078-porch-e2e-testing.md:43` **[auto-approve-gate]** — 3. Auto-approve mechanism inconsistency (flag vs env var) - **NOTED**: Env var is more flexible for testing +- `codev/reviews/0078-porch-e2e-testing.md:51` **[auto-approve-gate]** — 3. Spec/plan inconsistency on auto-approve - **NOTED**: Env var approach is valid +- `codev/reviews/0078-porch-e2e-testing.md:56` **[auto-approve-gate]** — Chose `PORCH_AUTO_APPROVE` environment variable over `--auto-approve-gates` flag because: +- `codev/reviews/0078-porch-e2e-testing.md:79` **[auto-approve-gate]** — | Full Lifecycle | ✅ | End-to-end with auto-approve | +- `codev/reviews/0116-shellper-resource-leakage.md:25` **[kill-shellper]** — - E2E test: Tower periodic cleanup timer removes stale sockets during runtime (2s interval, externally killed shellper) +- `codev/reviews/0118-shellper-multi-client.md:41` **[kill-shellper]** — - **Removed stale tests from session-manager.test.ts**: Two tests were removed (`repeated calls are idempotent` and `kills child process when readShellperInfo fails`). These were fragile timing-based +- `codev/reviews/1096-vscode-codev-openissuebynumber.md:53` **[restart-tower]** — - Manual verification: the human approved the running worktree at the `dev-approval` gate. Note the GitHub browser-open path requires the running Tower to serve the updated `issue-view` script (rebuil +- `codev/reviews/1096-vscode-codev-openissuebynumber.md:99` **[restart-tower]** — from the worktree root, `pnpm build && pnpm -w run local-install` (rebuilds + restarts Tower with the new `issue-view` script), then reload the VSCode window. +- `codev/reviews/1118-consolidate-state-db-tables-in.md:144` **[afx-from-worktree]** — Nesting is an unsupported anti-pattern (`afx spawn` from inside a worktree), so this is a +- `codev/reviews/1140-afx-workspace-recover-respawne.md:52` **[kill-shellper]** — 2. Kill that builder's shellper (or reboot), run `afx workspace recover --apply` from main's terminal +- `codev/reviews/1145-codev-adopt-launchinstance-mai.md:73` **[restart-tower]** — - **Run locally**: `pnpm build && pnpm -w run local-install` (restarts Tower) +- `codev/reviews/1149-tower-recovery-claude-architec.md:59` **[restart-tower]** — - **Run**: `pnpm build && pnpm -w run local-install` (restarts Tower with this branch) +- `codev/reviews/1149-tower-recovery-claude-architec.md:63` **[kill-shellper]** — 3. Kill the architect's claude process (not the shellper) +- `codev/reviews/1149-tower-recovery-claude-architec.md:66` **[restart-tower]** — 6. Escape hatch: repeat the corruption, restart Tower with `CODEV_SKIP_RESUME=1`, verify the architect starts fresh with no crash cycle at all +- `codev/reviews/438-aspir-protocol.md:31` **[auto-approve-gate]** — - **Phase 3 documentation wording**: The plan suggested specific bullet points for the CLAUDE.md/AGENTS.md ASPIR section. During implementation, the root CLAUDE.md was written first with slightly diff +- `codev/reviews/438-aspir-protocol.md:127` **[auto-approve-gate]** — - **Concern**: CLAUDE.md says gates are "auto-approved" which contradicts protocol.json (gates are absent) +- `codev/reviews/841-feat-vscode-architects-tree-ad.md:63` **[destructive-git]** — None skipped. Note (not flaky — pre-existing and unrelated): `packages/vscode/src/__tests__/terminal-adapter.test.ts` and `reconnect-link-provider.test.ts` fail to *collect* under plain vitest (dynami +- `codev/reviews/883-vscode-builder-cleanup-no-long.md:107` **[restart-tower]** — - **Build + install**: `pnpm build && pnpm -w run local-install` (restarts Tower, picks up the patched extension) +- `codev/reviews/916-vscode-sidebar-data-builders-b.md:116` **[restart-tower]** — - Simulate a transient blip (stop/restart Tower, or toggle network so the SSE drops then reconnects): +- `codev/reviews/920-vscode-editor-tab-webview-for-.md:83` **[restart-tower]** — 1. `cd .builders/pir-920 && pnpm -w run local-install` — rebuilds + restarts Tower so it serves `/api/issue-search` and resolves the `issue-search` concept. +- `codev/reviews/930-vscode-mark-recently-created-b.md:67` **[destructive-git]** — behavior (confirmed via `git stash` that the `status.ts`/`workspace.ts`/ +- `codev/reviews/961-core-extract-transport-agnosti.md:73` **[restart-tower]** — - Restart Tower; confirm a fresh connect resets the counter on both surfaces. +- `codev/reviews/982-vscode-tower-no-active-termina.md:59` **[kill-shellper]** — - Persistent: kill a builder's shellper so its session can't reconnect → after the retries, the actionable toast appears; **Retry** re-attempts, **Recover Builders** opens a terminal running `afx work +- `codev/reviews/983-vscode-tower-detect-installed-.md:7` **[restart-tower]** — The v3.1.7 #791 preflight verifies the *installed* `codev` CLI version but is blind to whether the *running* Tower process is executing that same code — after an `npm install -g` upgrade without a Tow +- `codev/reviews/983-vscode-tower-detect-installed-.md:59` **[restart-tower]** — - **Codex REQUEST_CHANGES (3-way consult, addressed)** — Codex (HIGH confidence) flagged that the `too-old` (404) path had the same futile-remedy bug we'd already fixed for the ext-version comparison: +- `codev/reviews/983-vscode-tower-detect-installed-.md:63` **[restart-tower]** — - **Self-invoked restart safety** — the in-extension `Restart Tower` action is only safe because #991 (already on main) scoped `afx tower stop` to the listening Tower process; before it, the unfiltere +- `codev/reviews/983-vscode-tower-detect-installed-.md:73` **[restart-tower]** — - Stale: bump the globally-installed `@cluesmith/codev/package.json` version (simulates an upgrade) without restarting Tower, reload the Ext Dev Host → divergence toast with `Restart Tower`; clicking +- `codev/reviews/983-vscode-tower-detect-installed-.md:75` **[restart-tower]** — - Unreachable: stop Tower → only the existing "not connected" path, no new toast +- `codev/reviews/991-terminal-stale-tab-on-a-pre-re.md:67` **[restart-tower]** — - **Deploy ordering:** the host-kill fix lives in `afx tower stop`; the id-preservation lives in the Tower server. Both ship via `local-install`, which restarts Tower using the freshly-installed `afx` +- `codev/reviews/997-tower-reconcile-terminal-sessi.md:58` **[restart-tower]** — - **Run / verify** (this repo restarts Tower to pick up the change): +- `codev/reviews/997-tower-reconcile-terminal-sessi.md:59` **[restart-tower]** — 1. `pnpm -w run local-install` with a builder/architect terminal active (rebuilds + restarts Tower) +- `codev/state/air-1238_thread.md:67` **[restart-tower]** — Did NOT restart Tower to observe the startup sweep live — that would kill every running +- `codev/state/aspir-1210_thread.md:86` **[auto-approve-gate]** — - **STOPPED at pr gate — awaiting human approval.** Not auto-approving (human-only gate). Architect +- `codev/state/bugfix-1122_thread.md:21` **[destructive-git]** — While proving the regression test fails without the fix, I ran a `git stash push` +- `codev/state/bugfix-1122_thread.md:23` **[destructive-git]** — then a paired `git stash pop` — which popped the PRE-EXISTING `stash@{0}: On main: +- `codev/state/bugfix-1122_thread.md:35` **[destructive-git]** — - `git reset --hard HEAD` reverted the 12 tracked modifications and removed the 32 +- `codev/state/bugfix-1122_thread.md:39` **[destructive-git]** — - Verified `git stash list` still shows `stash@{0}` intact afterward. +- `codev/state/bugfix-1224_thread.md:104` **[kill-shellper]** — - SessionManager maxRestarts give-up: logStderrTail (capture child reason) + kill shellper group +- `codev/state/bugfix-838_thread.md:36` **[destructive-git]** — Both fail against pre-fix package.json (verified via `git stash`); both +- `codev/state/pir-1118_thread.md:158` **[destructive-git]** — (a git stash pop unstaged it); committed the deletion (14604d24). CI now GREEN. +- `codev/state/pir-933_thread.md:11` **[destructive-git]** — - `git reset --hard fcea5028` (pristine porch-init commit) → porch back in the +- `codev/state/pir-983_thread.md:34` **[restart-tower]** — - **vscode**: `decideTowerStatus` + `towerDivergenceMessage` (pure, in preflight-core, 8 new unit tests); `probeTowerVersion` fired on each `connected` transition in `extension.ts`; dedicated `showTow +- `codev/state/pir-983_thread.md:48` **[restart-tower]** — **Rebased on main (picked up PIR #991 / PR #999).** Clean rebase, no conflicts. Re-verified every line ref in the plan — all still accurate (RouteContext tower-routes.ts:131, routeCtx tower-server.ts: +- `codev/state/pir-991_thread.md:66` **[restart-tower]** — Pending reviewer re-test with a freshly-built vsix (reload window once, then restart Tower only): expect Codev output `Tower reconnected — re-syncing N terminal(s)` → `recoverSuccessor(...): poll 1/5 + +## B5 — consult cost/duration + +**Not captured here.** `consult stats` is a rolling 30-day machine-local DB, +so it is not reproducible from a commit. Capture it separately as advisory +context; it is excluded from T14 determinism and drives no rollback trigger. + +## Sample provenance + +- 0092-terminal-file-links +- 0120-codex-sdk-integration +- 0124-test-suite-consolidation +- 403-af-send-typing-awareness +- 456-dashboard-statistics-tab-in-ri +- 462-add-spike-protocol-for-technic +- 467-add-open-files-shells-section- +- 468-af-rename-command-to-rename-cu +- 589-support-non-github-repositorie +- 723-improve-arch-md-lessons-learne +- 746-spir-architect-s-baked-archite +- 755-multi-architect-support-per-ar +- 761-surface-multiple-architects-in +- 778-gemini-cli-antigravity-cli-jun +- 786-multi-architect-feature-is-und +- 823-multi-architect-coordination-b +- 927-needs-attention-surface-prs-vi +- 987-engineering-wisdom-is-write-on + + +--- + +## B5 — consult cost/duration: forward snapshot (advisory) + +**Captured 2026-07-27 via `consult stats --json` (rolling 30-day machine-local +DB). NON-DETERMINISTIC: this section is appended at capture time, not +regenerated by the measurement script, and it is excluded from T14's +determinism assertion and from every rollback trigger.** It exists as advisory +context for interpreting a B1 movement in the verify phase — e.g. a REQUEST_CHANGES +rise accompanied by a duration collapse suggests degraded review quality rather +than degraded prompts. + +| Model | Calls (30d) | Avg duration | Total cost | Success rate | +|---|---:|---:|---:|---:| +| gemini | 1272 | 23.3s | n/a (no cost data) | 89.8% | +| claude | 971 | 107.6s | $900.06 | 91.9% | +| codex | 875 | 77.5s | $577.95 | 87.9% | +| **total** | **3349** | — | **$1478.01** (1278 of 3349 with cost data) | 90.6% | + +Verify-phase comparison: capture the same snapshot at verify time and compare +per-model averages directionally only. No threshold keys off this table. diff --git a/codev/resources/1252-shadow-tree-audit.md b/codev/resources/1252-shadow-tree-audit.md new file mode 100644 index 000000000..a955baff7 --- /dev/null +++ b/codev/resources/1252-shadow-tree-audit.md @@ -0,0 +1,273 @@ +# Spec 1252 — Shadow-tree local-unique content audit (M11) + + + +## Count correction vs the spec + +The spec said **76** shadow copies. The mechanical enumeration finds **77**: +the spec's count missed `consult-types/integration-review.md` (the drift +audit's `FRAMEWORK_DRIFT_DIRS` covers `protocols`, `roles`, AND +`consult-types`). 73 protocols-tree files (63 .md + 10 .json), 3 roles, 1 +consult-types. Drifted: 17, matching the spec. + +## Classification method (D1/D2) + +- **rot** — local lags the skeleton (missing content, stale references, + superseded structure). Evidence recorded per row. → TS1: reconcile to + skeleton (Phase 3), delete with the tree (Phase 4). +- **local-unique** — content present locally, absent from the skeleton, that + plausibly encodes codev-specific functionality. → **escalated to the + architect; nothing overwritten or deleted until ruled** (blocking for that + file only). +- Ambiguity defaults to local-unique/escalate per D2. + +Every hunk of each drifted file was classified, not just the file as a whole +(a local-unique paragraph inside an otherwise-rotted file is exactly the loss +M11 exists to prevent). Key evidence used: + +- **TICK is retired**: no `tick/` protocol dir exists in either tree; porch + source references it only in one stale test; the porch skill text naming + TICK is stale. All TICK references in local copies are therefore rot. (But + note: the skeleton's own porch phase prompts still emit TICK-amendment + language — upstream inconsistency, flagged for Phase 8's governance sweep.) +- **Obsolete gate IDs**: local `spir/protocol.md`'s retained porch section uses + `spec_approval` (underscore) — porch's actual gate is `spec-approval`. The + "local additions" predate the skeleton's restructure; they are what the + skeleton deleted, not new content. +- **architect.md**: the skeleton *generalized* the labels section to + `/` placeholders for adopters; the codev-specific `area/` recipes the + local copy hardcodes are already owned by CLAUDE.md (single-owner rule), so + taking the skeleton loses nothing. + +## Audit table (77 rows) + +| # | File | Divergence | Classification | Terminal state | Ruling / note | +|---|---|---|---|---|---| +| 1 | `consult-types/integration-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 2 | `protocols/air/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 3 | `protocols/air/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 4 | `protocols/air/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 5 | `protocols/air/prompts/implement.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 6 | `protocols/air/prompts/pr.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 7 | `protocols/air/protocol.json` | identical | local-unique | TS1 | RULED TS1 (architect, 2026-07-28): cwd migrated to .codev/config.json porch.checks (all four protocols); skeleton json taken | +| 8 | `protocols/air/protocol.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: 1-line delta; skeleton wording current) | +| 9 | `protocols/aspir/builder-prompt.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: missing Multi-PR Mechanics + Verify Phase sections (skeleton has them)) | +| 10 | `protocols/aspir/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 11 | `protocols/aspir/consult-types/phase-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 12 | `protocols/aspir/consult-types/plan-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 13 | `protocols/aspir/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 14 | `protocols/aspir/consult-types/spec-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 15 | `protocols/aspir/prompts/implement.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 16 | `protocols/aspir/prompts/plan.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 17 | `protocols/aspir/prompts/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 18 | `protocols/aspir/prompts/specify.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 19 | `protocols/aspir/protocol.json` | identical | local-unique | TS1 | RULED TS1 (architect, 2026-07-28): same ruling as spir | +| 20 | `protocols/aspir/protocol.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 21 | `protocols/aspir/templates/plan.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local-only TICK Amendments section; TICK retired (no protocol dir in either tree; porch refs only in one stale test)) | +| 22 | `protocols/aspir/templates/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 23 | `protocols/aspir/templates/spec.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: same TICK Amendments section) | +| 24 | `protocols/bugfix/builder-prompt.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local says SPIR/TICK; TICK retired) | +| 25 | `protocols/bugfix/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 26 | `protocols/bugfix/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 27 | `protocols/bugfix/prompts/fix.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 28 | `protocols/bugfix/prompts/investigate.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 29 | `protocols/bugfix/prompts/pr.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 30 | `protocols/bugfix/protocol.json` | identical | local-unique | TS1 | RULED TS1 (architect, 2026-07-28): same ruling as air | +| 31 | `protocols/bugfix/protocol.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 32 | `protocols/experiment/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 33 | `protocols/experiment/protocol.json` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 34 | `protocols/experiment/protocol.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local TICK handoff section; TICK retired) | +| 35 | `protocols/experiment/templates/notes.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 36 | `protocols/maintain/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 37 | `protocols/maintain/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 38 | `protocols/maintain/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 39 | `protocols/maintain/prompts/maintain.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 40 | `protocols/maintain/prompts/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 41 | `protocols/maintain/protocol.json` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 42 | `protocols/maintain/protocol.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 43 | `protocols/maintain/templates/maintenance-run.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 44 | `protocols/pir/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 45 | `protocols/pir/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 46 | `protocols/pir/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 47 | `protocols/pir/prompts/implement.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 48 | `protocols/pir/prompts/plan.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 49 | `protocols/pir/prompts/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 50 | `protocols/pir/protocol.json` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 51 | `protocols/pir/protocol.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 52 | `protocols/protocol-schema.json` | identical | rot | TS1 | RECONCILED Phase 3 (was: local example lists tick; TICK retired) | +| 53 | `protocols/research/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 54 | `protocols/research/protocol.json` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 55 | `protocols/research/protocol.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 56 | `protocols/spike/builder-prompt.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 57 | `protocols/spike/protocol.json` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 58 | `protocols/spike/protocol.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local mentions TICK; TICK retired) | +| 59 | `protocols/spike/templates/findings.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 60 | `protocols/spir/builder-prompt.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: THE HEADLINE DRIFT: local missing Multi-PR Mechanics + Verify Phase + "Entering verify phase." string) | +| 61 | `protocols/spir/consult-types/impl-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 62 | `protocols/spir/consult-types/phase-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 63 | `protocols/spir/consult-types/plan-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 64 | `protocols/spir/consult-types/pr-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 65 | `protocols/spir/consult-types/spec-review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 66 | `protocols/spir/prompts/implement.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 67 | `protocols/spir/prompts/plan.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 68 | `protocols/spir/prompts/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 69 | `protocols/spir/prompts/specify.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 70 | `protocols/spir/protocol.json` | identical | local-unique | TS1 | RULED TS1 (architect, 2026-07-28): accept skeleton max_iterations 3 — B2 evidence (rounds 1-2, mean 1.12) persuasive; >3 rounds is a human-attention moment | +| 71 | `protocols/spir/protocol.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local keeps pre-restructure porch section with obsolete underscore gate IDs (spec_approval); skeleton moved to build-verify model) | +| 72 | `protocols/spir/templates/plan.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: local-only TICK Amendments section; TICK retired) | +| 73 | `protocols/spir/templates/review.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 74 | `protocols/spir/templates/spec.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: same TICK Amendments section) | +| 75 | `roles/architect.md` | identical | rot | TS1 | RECONCILED Phase 3 (was: skeleton generalized labels section to / placeholders; codev-specific area/ recipes already owned by CLAUDE.md — no content lost) | +| 76 | `roles/builder.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +| 77 | `roles/consultant.md` | identical | rot | TS1 | byte-identical redundant copy; nothing to lose | +## Local-only entries (NOT shadow copies — preserved, T8) + +| File | Why it survives | +|---|---| +| `codev/protocols/release/` (whole dir) | Genuine local-only protocol; no skeleton counterpart | +| `codev/protocols/maintain/templates/audit-report.md` | Local-only template; no skeleton counterpart | +| `codev/protocols/maintain/templates/lessons-learned.md` | Local-only template; no skeleton counterpart | + +## Open escalations (4 files, 2 questions) + +Sent to the architect via afx send (Phase 2). Blocking those 4 files only; +the 13 rot files proceed to Phase 3 reconciliation. + +1. **max_iterations 8 (local) vs 3 (skeleton)** — `spir/protocol.json`, + `aspir/protocol.json`. Behavioral: bounds the CMAP iterate-until-approve + loop. No config override exists for this field. Options: accept skeleton's 3 + (TS1); retain forked json codev-only (TS3, allowlisted); promote 8 into the + skeleton (TS2). +2. **`"cwd": "packages/codev"` in check commands** — `air/protocol.json`, + `bugfix/protocol.json`. Functional: monorepo check cwd. The sanctioned + mechanism is `.codev/config.json` → `porch.checks` cwd overrides (Spec + #550), which this repo does not currently use. Recommended: migrate cwd to + config (making spir/aspir/air/bugfix consistent), then take skeleton json — + TS1-after-migration. Note spir/aspir currently pass only because the repo + root's package.json happens to have build/test scripts. + +## M7 compatibility audit — COMPLETE (Phase 4, step 4a) + +Repo-wide classification of every literal `codev/protocols/` / `codev/roles/` +reference. Production consumers were audited in spec Appendix B (all +resolver-routed or inert). This completes the test tier and non-TypeScript +consumers, as M7 requires before any deletion. + +### Test tier — 4 real repo-readers (MUST repoint at `codev-skeleton/` in the deletion commit) + +| Test | What it reads | Fix | +|---|---|---| +| `baked-decisions.test.ts` | `codev/protocols/{spir,aspir,air}/builder-prompt.md` + prompt files (Spec 746 PHASE lists) | repoint `relPath` entries to `codev-skeleton/...`; skeleton mirror entries collapse to the same path | +| `bugfix-742-consult-templates.test.ts` | 4 consult-type files under `codev/protocols/{bugfix,spir}` | repoint `repoRoot` joins to `codev-skeleton/` | +| `protocol-prompt-audit.test.ts` | walks `codev/protocols/` wholesale | walk `codev-skeleton/protocols/` | +| `bugfix-685-close-keyword.test.ts` | 6 prompt files across protocols | repoint table to `codev-skeleton/` | + +After deletion, `codev-skeleton/` is the single in-repo source (the installed +skeleton is its build-time copy), so repointing keeps these tests validating +the same content agents are served — no assertion weakens. + +### Test tier — safe (temp fixtures or string literals only) + +`consult.test.ts`, `pr-gate-audit.test.ts` (both build `codev/` trees inside +temp roots), `porch/protocol.test.ts`, `protocol-overrides.test.ts`, +`roles.test.ts`, `spawn-roles.test.ts`, `af-architect.test.ts`, +`tower-utils.test.ts`, `bugfix-527`, `bugfix-744`, `bugfix-619`, +`governance-sweep.test.ts` (strings/paths in messages only), +`framework-ref-audit.test.ts` (scans the skeleton by design). + +### Non-TypeScript consumers + +| File | Kind | Deletion-safe? | +|---|---|---| +| `scripts/measure-prompt-surface.sh` | two-tier resolve (`codev/` then `codev-skeleton/`) — this project's own script, built deletion-aware | **Yes** — falls through to skeleton | +| `apps/vscode/scripts/publish.sh:15` | comment referencing `codev/protocols/release/` | **Yes** — and `release/` is preserved anyway | + +No other shell/yaml/json consumer found outside `node_modules`/`dist`/worktrees. + +### Verdict + +Deletion is safe once (a) the four repo-reading tests are repointed in the same +commit, and (b) the four ESCALATED json rulings resolve. No production code +path reads the shadow tree by literal path. + +## Escalation rulings (architect, 2026-07-28) + +- **E1 → TS1**: skeleton's `max_iterations: 3` accepted for spir + aspir. The + B2 baseline evidence (rounds run 1–2, mean 1.12) was the deciding factor — + ">3 rounds is a human-attention moment, not an automation moment." +- **E2 → migrate-then-TS1**: `cwd` moved to `.codev/config.json` → + `porch.checks` for **all four** protocols; skeleton jsons taken. + +## E2 config-reach verification (required by the ruling) + +`.codev/config.json` is untracked (`.gitignore:11`), so the ruling required +verifying the config reaches every context that runs porch checks before +classifying E2 resolved. Verified against code, not assumption: + +| Context | Mechanism | Verified | +|---|---|---| +| Builder worktrees (future spawns) | `spawn-worktree.ts:100–113` symlinks main's `.codev/config.json` into every new worktree when it exists | code read | +| Builder worktrees (existing) | `afx setup ` re-applies symlinks; independently covered by the fallback below | docs + fallback | +| Main checkout | file must be created there once (snippet sent to the architect — a builder cannot write outside its worktree) | fallback covers the gap meanwhile | +| Fresh clone (no config anywhere) | porch runs checks at the workspace root; **root `package.json` delegates** `build`/`test` to `packages/codev` via pnpm filters | **empirically proven** — spir/aspir checks ran cwd-less at this worktree's root, green, all session | +| CI | `.github/workflows/test.yml` never invokes porch checks (it only excludes porch e2e dirs from a vitest run) | grep of workflows | + +**Key finding: the migration is defense-in-depth, not load-bearing.** Every +context has a working fallback (root delegation) even with no config file +anywhere, so no context can break. No escalate-back needed. This worktree's +`.codev/config.json` now carries the overrides +(`build/test/e2e_tests/build_succeeds/tests_pass → cwd: packages/codev`). + +## M7 correction (Phase 4b): 8 repo-reading tests, not 4 + +The step-4a classification used a path-construction regex and had **four false +negatives** — tests that read `codev/protocols/*` via `path.join` segments, +template literals, or `__dirname` traversal that the regex missed: +`bugfix-744-spir-pr-strategy`, `governance-sweep`, `review-prompt-routing` +(iterated both trees), and `bugfix-619-aspir-prompt`. The deletion itself +caught them (ENOENT), which is the correct failure mode — loud, at the point +of change. All eight are now repointed at `codev-skeleton/`; mirror-parity +constructs collapsed to skeleton-only with explanatory comments. Lesson for +the review: a grep classification of consumers is a hypothesis, not a proof — +the deletion is the test. + +## Phase 4 result + +- 77 shadow copies deleted; `codev/roles/` and `codev/consult-types/` removed + entirely; `codev/protocols/` retains only the three preserved local-only + files (`release/protocol.md`, `maintain/templates/{audit-report,lessons-learned}.md`). +- `copyRoles`/`copyProtocols` (124 lines) removed from `scaffold.ts` with a + tombstone comment; `copyRoles` test block removed. +- M10 equivalence: `shadow-removal-manifest.json` (77 pre-deletion sha256s) + + `shadow-removal-equivalence.test.ts` prove the resolver serves byte-identical + content post-deletion FROM THE SKELETON TIER (path asserted, not just + content), and assembled-prompt equivalence is exercised directly: the real + `buildPromptFromTemplate` ran against the pre-deletion tree (git archive) for + all nine protocols under a fixed context, snapshots committed, and the live + assembly must reproduce them byte-for-byte. The FULL served prompt (preamble + + template) is additionally guarded: the spawn preamble had instructed + "Read codev/roles/builder.md" — a literal-path fetch of a deleted file + (caught by Codex, Phase 4 iter-4) — now replaced by a single-owner + `builderPreamble()` that points at the harness-injected role + (`.builder-role.md`), with tests asserting no framework path is fetched. +- Allowlist: **empty**. Drift gate: zero findings. All T11 guards green with + zero pending rows. + +## Phase 4 iter-2 additions + +- `codev/protocols/release/protocol.md:43` repointed (`cat codev-skeleton/...`) + — the M7 sweep had not audited codev/'s own preserved content. Verified no + other fetch of deleted paths exists in preserved files. +- **Deferred to Phase 8 (recorded so it is not lost)**: `CLAUDE.md`/`AGENTS.md` + contain ~10 prose references to deleted `codev/protocols/...` paths + (available-protocol listing, RELEASE pointer, SPIR instruction). References, + not fetches; both files receive Phase 5/7/8 edits where these repoint to + `codev-skeleton/` (or resolver-neutral wording) as part of governance sync. diff --git a/codev/resources/1252-word-after-phase7.md b/codev/resources/1252-word-after-phase7.md new file mode 100644 index 000000000..f36be3fe7 --- /dev/null +++ b/codev/resources/1252-word-after-phase7.md @@ -0,0 +1,58 @@ + +# Prompt-surface measurement + +Commit: `883b3a8a` + +## Per-surface word counts + +| Surface | Words | Files | Load | +|---|---:|---:|---| +| CLAUDE.md | 4330 | 1 | always-on (hot tier inlined) | +| AGENTS.md | 4330 | 1 | always-on twin (other tools) | +| arch-critical.md (HOT) | 422 | 1 | inlined in CLAUDE.md + every phase prompt | +| lessons-critical.md (HOT) | 320 | 1 | same | +| arch.md (COLD) | 20240 | 1 | on demand | +| lessons-learned.md (COLD) | 21270 | 1 | on demand | +| codev-skeleton/** | 78804 | 123 | resolver tier 4 | +| — skeleton protocols/ | 43812 | — | | +| — skeleton roles/ | 3836 | — | | +| codev/protocols/ (shadow) | 2347 | 3 | wins over skeleton | +| codev/roles/ (shadow) | 0 | 0 | wins over skeleton | +| .claude/skills/** | 16769 | 14 | on demand | + +## Always-on load per builder (derived from resolved artifacts) + + CLAUDE.md 4330 + + spawn prompt (proxy) 4564 (builder-prompt.md 861 + protocol.md 3703) + + phase task (proxy) x 10 11430 (hot tier 742 + porch prompt mean 401, per iteration) + ------------------------------ + = ALWAYS_ON 20324 + +Proxies deliberately exclude per-project variable content (issue body, +task-JSON boilerplate) — those are not trimmable prompt surface, and including +them would let a rerun's delta be polluted by whichever issue happened to spawn +the measuring builder. AGENTS.md and the hot-tier files are likewise excluded +from the top-level sum: AGENTS.md is the byte-identical twin (one loads per +session, not both), and the hot-tier files appear inside CLAUDE.md's count +(they ARE counted once per phase task, where porch injects them separately). + +ALWAYS_ON_WORDS=20324 + +## N1 delta vs baseline (required record) + +| | Baseline (Phase 1, `1252-word-baseline.md`) | After Phase 7 | Delta | +|---|---:|---:|---:| +| CLAUDE.md | 5,773 | 4,330 | −1,443 | +| Spawn proxy (served) | 4,723 | 4,564 | −159 | +| Phase task ×10 | 11,360 | 11,430 | +70 | +| **ALWAYS_ON** | **21,856** | **20,324** | **−1,532** | + +**Achieved: −7.0% against the ≥20% target. N1 is a target, not a gate; this is +the honest figure.** Decomposition: CLAUDE.md relocations/trims delivered the +bulk; drift repair *added* served words the prompts were supposed to have +(Multi-PR + Verify, ~207); D3's promotion of three user-global scar rules +added ~120; the remaining always-on surface is single-owned prose whose +largest block (protocol.md, 3,703 words) is protocol semantics — excluded by +the spec's Non-goals. The 20% arithmetic assumed more of the surface was +duplicated rules than measurement bore out. Whether even −7% moved behaviour +is the verify phase's question (M12b). diff --git a/codev/resources/1252-word-baseline.md b/codev/resources/1252-word-baseline.md new file mode 100644 index 000000000..99aa8abe5 --- /dev/null +++ b/codev/resources/1252-word-baseline.md @@ -0,0 +1,39 @@ + +# Prompt-surface measurement + +Commit: `b37f7db1` + +## Per-surface word counts + +| Surface | Words | Files | Load | +|---|---:|---:|---| +| CLAUDE.md | 5773 | 1 | always-on (hot tier inlined) | +| AGENTS.md | 5773 | 1 | always-on twin (other tools) | +| arch-critical.md (HOT) | 416 | 1 | inlined in CLAUDE.md + every phase prompt | +| lessons-critical.md (HOT) | 320 | 1 | same | +| arch.md (COLD) | 20240 | 1 | on demand | +| lessons-learned.md (COLD) | 21270 | 1 | on demand | +| codev-skeleton/** | 77955 | 113 | resolver tier 4 | +| — skeleton protocols/ | 44784 | — | | +| — skeleton roles/ | 3813 | — | | +| codev/protocols/ (shadow) | 47511 | 66 | wins over skeleton | +| codev/roles/ (shadow) | 3687 | 3 | wins over skeleton | +| .claude/skills/** | 16743 | 14 | on demand | + +## Always-on load per builder (derived from resolved artifacts) + + CLAUDE.md 5773 + + spawn prompt (proxy) 4723 (builder-prompt.md 636 + protocol.md 4087) + + phase task (proxy) x 10 11360 (hot tier 736 + porch prompt mean 400, per iteration) + ------------------------------ + = ALWAYS_ON 21856 + +Proxies deliberately exclude per-project variable content (issue body, +task-JSON boilerplate) — those are not trimmable prompt surface, and including +them would let a rerun's delta be polluted by whichever issue happened to spawn +the measuring builder. AGENTS.md and the hot-tier files are likewise excluded +from the top-level sum: AGENTS.md is the byte-identical twin (one loads per +session, not both), and the hot-tier files appear inside CLAUDE.md's count +(they ARE counted once per phase task, where porch injects them separately). + +ALWAYS_ON_WORDS=21856 diff --git a/codev/resources/arch-critical.md b/codev/resources/arch-critical.md index 7f329b625..84921a8f8 100644 --- a/codev/resources/arch-critical.md +++ b/codev/resources/arch-critical.md @@ -8,14 +8,14 @@ and keeps the map in sync with arch.md's top-level sections. See codev/resources ## Critical facts (consult before deciding) - Framework files resolve at RUNTIME via the four-tier chain (.codev/ → codev/ → cache → skeleton); they are NOT copied into projects. Don't wire features to "scaffold copies it." - Governance docs are two-tier (Spec 987): HOT arch-critical.md/lessons-critical.md are capped + always-injected; COLD arch.md/lessons-learned.md are reference. Route new facts/lessons by tier; never grow a hot file past its cap (demote to cold). -- Two trees: codev/ = our instance, codev-skeleton/ = the template shipped to adopters. Mirror every framework change in BOTH. -- CLAUDE.md and AGENTS.md MUST stay byte-identical (same content, two tool ecosystems). -- Porch is a pure planner: it emits task JSON, Claude Code executes. Never hand-edit status.yaml. +- codev-skeleton/ is the single owner of framework protocols/roles/consult-types (Spec 1252 deleted the codev/ shadow tree; shadow drift now fails CI). CLAUDE.md and AGENTS.md MUST stay byte-identical. +- Porch is a pure planner: it emits task JSON, Claude Code executes. +- Never hand-edit `status.yaml` — only porch commands modify project state. - State lives in a single user-global ~/.agent-farm/global.db (Issue #1118 retired the per-workspace state.db; architect/builders keyed by workspace_path); one Tower on port 4100. Never modify state by hand. -- Worktrees in .builders/ are Agent-Farm-managed — never delete manually (use afx cleanup); run afx from the main workspace root only. +- Worktrees in .builders/ are Agent-Farm-managed: architect-driven `afx cleanup` retires FINISHED builders; never destroy a live one (scar rule — use `afx spawn --resume`, ask when in doubt); run afx from the main workspace root only. - Forge concept commands abstract the VCS provider — add a dedicated concept; don't bolt env flags onto a shared one. - Two human gates (spec-approval, plan-approval) plus the pr gate; only humans transition conceived→specified and committed→integrated. -- Never `git add -A` / `.` / `--all` — stage files explicitly. +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ## Map of arch.md (consult when…) - Invariants & Constraints — touching state, ports, worktrees, or anything "MUST remain true." diff --git a/codev/resources/arch.md b/codev/resources/arch.md index edcad92c0..805c7814a 100644 --- a/codev/resources/arch.md +++ b/codev/resources/arch.md @@ -16,12 +16,12 @@ Codev is a Human-Agent Software Development Operating System. This repository se - **Shared Runtime**: `packages/core/` — TowerClient, auth, workspace encoding, EscapeBuffer, ReconnectPolicy - **VS Code Extension**: `apps/vscode/` — thin client over Tower API - **Dashboard**: `apps/web/` — React SPA served by Tower -- **Consult Tool**: See `packages/codev/src/commands/consult/` and `codev/roles/consultant.md` -- **Protocols**: Read the relevant protocol in `codev/protocols/{spir,maintain,experiment}/protocol.md` +- **Consult Tool**: See `packages/codev/src/commands/consult/` and `codev-skeleton/roles/consultant.md` (resolved from the skeleton at runtime; Spec 1252 removed the `codev/roles/` shadow copies) +- **Protocols**: Read the relevant protocol in `codev-skeleton/protocols/{spir,maintain,experiment}/protocol.md` (the single owner; the runtime resolves the embedded copy) **To add a new feature to Codev:** 1. Create a GitHub Issue describing the feature -2. Create spec using template from `codev/protocols/spir/templates/spec.md` +2. Create spec using template from `codev-skeleton/protocols/spir/templates/spec.md` (porch delivers it via the resolver at runtime) 3. Follow SPIR protocol: Specify → Plan → Implement → Review ## Quick Tracing Guide @@ -84,17 +84,29 @@ tail -f ~/.agent-farm/tower.log | **node-pty** | Native PTY session manager, multiplexed over WebSocket | | **Shellper** | Detached Node.js process owning a PTY for session persistence across Tower restarts (Spec 0104) | | **SessionManager** | Tower-side orchestrator for shellper process lifecycle (spawn, reconnect, kill, auto-restart) | -| **Skeleton** | Template files (`codev-skeleton/`) copied to projects on init/adopt | +| **Skeleton** | The framework source tree (`codev-skeleton/`), embedded into the package at build time and served as the resolver's tier-4 fallback at RUNTIME — framework files are not copied into projects (Spec 1252 / arch-critical fact #1); init/adopt copy only root docs, skills, and hot/cold-tier starters | ## Invariants & Constraints +- **Single-owner prompt regime (Spec 1252).** Every instruction on the prompt + surface has exactly one owning surface, recorded in + `codev/resources/prompt-ownership.yaml` (machine-readable; the .md companion + is validated against it). Cross-surface duplication of a normative line + fails CI (T12 catch-all guard). Shared template-family content lives in + `codev-skeleton/partials/` and is expanded into served prompts by + `resolveCodevIncludes` — authored once, served everywhere it applies. Scar + rules (codev/resources/scar-rules.yaml, eight, D3-ratified) are the + deliberate exception: byte-verbatim replicas on every listed surface, + delete/reword fails CI. + + **These MUST remain true - violating them will break the system:** 1. **State Consistency**: the user-global `~/.agent-farm/global.db` is the single source of truth for architect/builder/util state (Issue #1118 retired the per-workspace `.agent-farm/state.db`; rows are disambiguated by `workspace_path`). Never modify it manually. 2. **Single Tower Port**: All projects are served through Tower on port 4100. Per-project port blocks were removed in Spec 0098. Terminal sessions and workspace metadata are tracked in `~/.agent-farm/global.db`. -3. **Worktree Integrity**: Worktrees in `.builders/` are managed by Agent Farm. Never delete them manually (use `afx cleanup`). +3. **Worktree Integrity**: Worktrees in `.builders/` are managed by Agent Farm. Never delete them manually or autonomously — architect-driven `afx cleanup` retires *finished* builders; a live worktree is resumed (`afx spawn --resume`), never bulldozed (scar rule: never-destroy-worktrees). 4. **CLAUDE.md ≡ AGENTS.md**: These files MUST be identical. They are the same content for different tool ecosystems. @@ -286,7 +298,7 @@ Architect sessions use `restartOnExit: true` in `SessionManager.createSession()` All architect sessions (at all 3 creation points) receive a role prompt injected via `buildArchitectArgs()` in `tower-utils.ts`. This function: -1. Loads the architect role from `codev/roles/architect.md` (local) or `skeleton/roles/architect.md` (bundled fallback) via `loadRolePrompt()` +1. Loads the architect role via `loadRolePrompt()` — resolver order `.codev/roles/` → `codev/roles/` → embedded skeleton; since Spec 1252 removed the shadow copies, the skeleton copy is what resolves here 2. Writes the role content to `.architect-role.md` in the project directory 3. Delegates the CLI-specific injection to the configured `HarnessProvider` (`agent-farm/utils/harness.ts`, Spec 591): claude `--append-system-prompt`, codex `-c model_instructions_file=`, gemini `GEMINI_SYSTEM_MD` env var @@ -500,7 +512,7 @@ When spawning a builder (`afx spawn 3 --protocol spir`): 4. **Setup Files**: - `.builder-prompt.txt`: Initial prompt for the builder - - `.builder-role.md`: Role definition (from `codev/roles/builder.md`) + - `.builder-role.md`: Role definition (resolved via the four-tier chain; the skeleton's `roles/builder.md` since Spec 1252) - `.builder-start.sh`: Launch script for builder session - Root `.env` and shared `.codev/config.json`: symlinked into the worktree, along with configured `worktree.symlinks` @@ -1193,11 +1205,22 @@ This is where the Codev project uses Codev to develop itself: - `plans/` - Implementation plans for Codev features - `reviews/` - Lessons learned from Codev development - `resources/` - Reference materials (this file, testing-guide.md, lessons-learned.md, etc.) - - `protocols/` - Working copies of protocols for development + - `protocols/` - **local-only protocols exclusively** (e.g. `release/`). + Spec 1252 (2026-07) deleted the 77 framework shadow copies this directory + used to hold: they were tier-2 copies that outranked the installed + skeleton in the resolver, drifted silently for months (17 files stale, + including a served SPIR builder prompt missing its Verify Phase), and the + drift audit (#1210) reported it to `codev doctor` unread the whole time. + Framework protocols and roles now resolve from the skeleton (tier 4) here + exactly as they do for adopters; `shadow-drift-gate.test.ts` fails CI on + any reintroduced shadow copy, and `skeleton-embed-sync.test.ts` keeps the + embedded build copy byte-identical to `codev-skeleton/`. - `agents/` - Agent definitions (canonical location) - - `roles/` - Role definitions for architect-builder pattern - `templates/` - HTML templates for Agent Farm (`afx`) dashboard and annotation viewer - - Note: Shell command configuration is in `.codev/config.json` at the project root + - Note: `codev/roles/` and `codev/consult-types/` were removed with the + shadow tree — roles resolve from the skeleton too. Shell command + configuration is in `.codev/config.json` at the project root; porch check + cwd overrides live under its `porch.checks` key (Spec #550). **Example**: `codev/specs/0001-test-infrastructure.md` documents the test infrastructure feature we built for Codev. @@ -1418,7 +1441,7 @@ codev/ # Project root (pnpm monorepo) ### 1. Development Protocols -#### SPIR Protocol (`codev/protocols/spir/`) +#### SPIR Protocol (`codev-skeleton/protocols/spir/`) **Purpose**: Multi-phase development with multi-agent consultation **Phases**: @@ -1443,7 +1466,7 @@ codev/ # Project root (pnpm monorepo) - `templates/plan.md` - Planning template - `templates/review.md` - Review template -#### BUGFIX Protocol (`codev/protocols/bugfix/`) +#### BUGFIX Protocol (`codev-skeleton/protocols/bugfix/`) **Purpose**: Lightweight protocol for minor bugfixes using GitHub Issues **Workflow**: @@ -1580,7 +1603,7 @@ afx spawn 3 --protocol spir --builder-cmd "claude --model sonnet" "dir": "codev/templates" }, "roles": { - "dir": "codev/roles" + "dir": "codev/roles" // resolver tier-2 slot; empty since Spec 1252 — falls through to the skeleton } } ``` @@ -1601,7 +1624,7 @@ See the [Port System](#port-system) section above for details on the global regi #### Role Files -**Location**: `codev/roles/` +**Location**: `codev-skeleton/roles/` (single owner; `codev/roles/` was removed by Spec 1252 — the resolver's tier-2 slot exists but is empty) **architect.md** - Comprehensive architect role: - Responsibilities: decompose work, spawn builders, monitor progress, review and integrate @@ -1902,7 +1925,7 @@ consult -m claude spec 42 **Query building**: Five subcommands (`pr`, `spec`, `plan`, `impl`, `general`) each build a prompt that includes the spec/plan/diff content plus a verdict template (`VERDICT: [APPROVE | REQUEST_CHANGES | COMMENT]`). PR diffs truncated to 50k chars, impl diffs to 80k chars. **Role resolution** uses `readCodevFile()` with local-first, embedded-skeleton-fallback: -1. `codev/roles/consultant.md` (local override) +1. `codev/roles/consultant.md` (tier-2 local override slot — empty since Spec 1252; next tier resolves) 2. `skeleton/roles/consultant.md` (embedded default) **Porch integration**: Porch's `next.ts` spawns 3 parallel `consult` commands with `--output` flags, collects results, parses verdicts via `verdict.ts` (scans backward for `VERDICT:` line, defaults to `REQUEST_CHANGES` if not found). diff --git a/codev/resources/commands/agent-farm.md b/codev/resources/commands/agent-farm.md index cf1b26faf..6302a09ad 100644 --- a/codev/resources/commands/agent-farm.md +++ b/codev/resources/commands/agent-farm.md @@ -971,3 +971,152 @@ Codev reserves the `CODEV_*` prefix. Tower injects these variables into the arch - [codev](codev.md) - Project management commands - [consult](consult.md) - AI consultation - [overview](overview.md) - CLI overview + +## Runnable Worktrees (afx dev) + +When configured, each builder worktree (`.builders//`) becomes runnable — reviewers can run whatever your dev command starts against the builder's branch — a dev server, `cargo run`, `expo start`, a test watcher, a build script, whatever iterates on your project — without `cd`'ing, manually installing, or finding the right command. Opt-in via `.codev/config.json`; unconfigured repos see zero behavior change. + +### Config: the `worktree` block + +```jsonc +{ + "worktree": { + "symlinks": ["..."], // glob patterns of files to symlink from root into each new worktree + "postSpawn": ["..."], // shell commands run inside each new worktree after createWorktree + "devCommand": "..." // consumed by `afx dev ` + } +} +``` + +- `symlinks`: globs resolve from the workspace root; matches symlink into the worktree at the same relative path. Root `.env` and `.codev/config.json` are *always* symlinked regardless. **Symlinks, not copies** — edits to main's env files reflect instantly in any running dev session. A directory match is silently skipped (so a glob can't mask the worktree's own source) **unless** the entry ends with a trailing slash: `".local-user-data/"` is treated as a literal path and symlinks the directory whole (shared with the parent, not branch-isolated; a dangling link is fine if the source doesn't exist yet). +- `postSpawn`: each command runs sequentially with `cwd` = worktree path. Non-zero exit aborts the spawn loud (half-built worktree stays for inspection). +- `devCommand`: the foreground command that starts your dev process (a server, a watcher, `cargo run`, `expo start`, a build script — whatever iterates on your project). Required for `afx dev` to work. + +**Codev does not auto-detect your stack.** Pick the recipe below that matches your toolchain. + +### CLI + +```bash +afx dev # start dev in 's worktree +afx dev main # start dev in the MAIN workspace (Codev-managed) +afx dev --stop # stop the currently running dev PTY (builder or main) +``` + +Only one dev PTY runs at a time (by design — see "URLs are load-bearing" below), across **{main + all builders}**. `main` is a reserved target: it runs `worktree.devCommand` in the main checkout as a Codev-managed, swappable PTY, symmetric with builders. Starting any target while another is up prompts for swap (`afx dev ` while `main` runs, or vice-versa); same-target requests print the existing terminal URL and exit. Like builder dev, main dev is a **non-persistent** PTY — a Tower restart (`pnpm -w run local-install`, crash) kills it; re-run to restart. + +**Launch main dev via `afx dev main`, not a bare `pnpm dev`.** A manually-run `pnpm dev` at the repo root is invisible to Codev (the deliberate "never kill what it didn't spawn" policy) — start a builder dev while it holds the ports and the builder dev silently fails to bind, or worse serves main's code under the worktree URL. `afx dev main` makes it a managed PTY that swap-detection can cleanly stop first. This only helps if you use it *consistently*; a hand-started `pnpm dev` stays unmanaged. + +### VSCode + +The same actions are available via right-click on any builder row in the Codev sidebar (Builders or Needs Attention view): + +- **Codev: Open Builder Terminal** — opens that builder's AI terminal in a VSCode tab (same as left-clicking the row). +- **Codev: Open Worktree Folder** — opens `.builders//` in the OS file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux). +- **Codev: Run Worktree Setup** — applies the configured `worktree.symlinks` and runs the `worktree.postSpawn` commands against the existing worktree (mirrors what spawn does, minus the git steps). Idempotent: existing symlinks are skipped, missing ones added. Useful when the lockfile changed (reinstall deps), `symlinks` or `postSpawn` was extended after the builder spawned, a symlink was accidentally deleted, or the original setup aborted mid-run. Opens a fresh VSCode terminal so install output streams live. Available via CLI too: `afx setup `. +- **Codev: View Diff** — opens a single unified diff editor for `main...HEAD` of that builder's worktree, with a file-list pane on the left (matches VSCode's built-in Source Control "Working Tree" view). Status icons indicate added / modified / deleted. Empty diff → friendly toast. +- **Codev: Run Dev** — reads `worktree.devCommand` from `.codev/config.json`, asks Tower to spawn a dev PTY in the builder's worktree, and opens it as a VSCode terminal tab named `Codev: (dev)`. If another builder's dev is already running, you get a modal asking whether to swap. +- **Codev: Stop Dev** — kills the running dev PTY and closes its tab. + +The Codev sidebar's **Workspace** view also carries a dev control for *whatever folder this VSCode window is rooted at* (it is not "main"-specific): + +- **Start Dev** — runs `worktree.devCommand` for the current workspace. Target is resolved from the open folder: the main checkout → `main`; a `.builders//` worktree opened as its own window (e.g. via *Open Worktree as Workspace*) → that builder. Same single-slot swap model as builder dev (prompts if another dev is running). The row tooltip names the resolved target. +- **Stop Dev** — stops this workspace's dev; the row appears only while it is running. Scoped to the resolved target — it does not touch other devs. + +The three commands are also available from the command palette (Cmd+Shift+P). No default keybindings; bind via `keybindings.json` if you use them often. + +### URLs are load-bearing + +The dev PTY uses **the same ports and URLs as main** intentionally. OAuth callbacks, CORS allowlists, cookie scoping, CSP `connect-src`, webhook URLs are all keyed off origin — running the worktree on a different port would break them. Consequence: stop main's `pnpm dev` before `afx dev`. If you don't, the spawned dev fails at bind time with its own `EADDRINUSE`. Prefer `afx dev main` (or the Workspace view's *Start Dev* row) over a hand-run `pnpm dev` so Codev owns the PTY and swap-detection can stop it for you automatically. + +### Cleanup semantics + +`afx dev --stop` and the swap path kill the entire PTY process group (SIGTERM, escalating to SIGKILL after 5s via `PtySession.kill`). That signals every grandchild of a monorepo dev orchestrator (`pnpm dev`, `turbo dev`, `pnpm -r --parallel run dev`, etc.) simultaneously. The OS reclaims ports as a consequence — Codev never touches ports directly. + +**Orphan recovery** — if Tower itself hard-crashes mid-dev and a process is left holding a port outside Codev's records: + +```bash +lsof -ti : | xargs kill # one port +lsof -ti :3000,:3001,:4000 | xargs kill # several at once +``` + +### Runnable Worktree Recipes + +Ready-to-paste blocks per stack. Adjust ports / paths to your project. + +**pnpm monorepo (Next.js + Turbo style):** +```json +{ + "worktree": { + "symlinks": [".env.local", ".env.development.local", "packages/*/.env", "packages/*/.env.local", "turbo.json"], + "postSpawn": ["pnpm install --frozen-lockfile"], + "devCommand": "pnpm dev" + } +} +``` + +**npm (single package):** +```json +{ + "worktree": { + "symlinks": [".env.local", ".env.development"], + "postSpawn": ["npm ci"], + "devCommand": "npm run dev" + } +} +``` + +**yarn:** +```json +{ + "worktree": { + "symlinks": [".env.local"], + "postSpawn": ["yarn install --frozen-lockfile"], + "devCommand": "yarn dev" + } +} +``` + +**bun:** +```json +{ + "worktree": { + "symlinks": [".env.local"], + "postSpawn": ["bun install --frozen-lockfile"], + "devCommand": "bun dev" + } +} +``` + +**cargo (Rust):** +```json +{ + "worktree": { + "symlinks": [".env"], + "postSpawn": [], + "devCommand": "cargo run" + } +} +``` + +**poetry / uv (Python):** +```json +{ + "worktree": { + "symlinks": [".env", ".env.local"], + "postSpawn": ["uv sync"], + "devCommand": "uv run python -m myapp" + } +} +``` + +**go mod:** +```json +{ + "worktree": { + "symlinks": [".env"], + "postSpawn": ["go mod download"], + "devCommand": "go run ./cmd/server" + } +} +``` + diff --git a/codev/resources/lessons-learned.md b/codev/resources/lessons-learned.md index 3e3ec782d..0e7a6256f 100644 --- a/codev/resources/lessons-learned.md +++ b/codev/resources/lessons-learned.md @@ -10,6 +10,21 @@ Generalizable wisdom extracted from review documents, ordered by impact. Updated ## Critical (Prevent Major Failures) +### A detector that reports without failing is a detector nobody reads (Spec 1252) + +`protocol-drift-audit` (#1210) correctly detected 17 drifted framework shadow +copies and reported them via `codev doctor` for months. Nobody acted. One of +the drifted files was the served SPIR builder prompt, silently missing its +Verify Phase section — and Spec 746's test comments even *described* the drift +("PRE-EXISTING and not Phase 1's responsibility") before stepping around it. +Detection was never the gap; consequence was. When a check guards an invariant +that matters, wire it to fail the build — advisory output is background noise. +Corollaries from the same project: a frozen-file "pure addition" baseline is a +drift bomb (derive baselines instead); a grep classification of consumers is a +hypothesis, not a proof (the deletion is the test); and a metric must not +reward moving text between files (measure the served artifact, not the +authored one). + - [From 0008] Single source of truth beats distributed state - consolidate to one implementation - [From 0009] Check for existing work (PRs, git history) before implementing from scratch - [From bug reports] Tests passing does NOT mean requirements are met - manually verify the actual user experience before marking complete diff --git a/codev/resources/prompt-ownership.md b/codev/resources/prompt-ownership.md new file mode 100644 index 000000000..cabfea33b --- /dev/null +++ b/codev/resources/prompt-ownership.md @@ -0,0 +1,76 @@ +# Prompt Ownership Map — human companion (Spec 1252, M1) + +**The machine-readable source of truth is `prompt-ownership.yaml`** — tests +derive from it, and this companion summarizes it for humans. If they disagree, +the YAML wins; fix this file. + +## The single-owner rule + +Every instruction has exactly one owning surface; all other surfaces reference +or summarize it, never restate it. Two carve-outs, both deliberate: + +- **Scar rules** (8, registered in `scar-rules.yaml`) replicate **verbatim** on + every surface they apply to — their enforcement lives in that registry and + `scar-rules.test.ts` (T6), not here, so ownership of scar enforcement itself + stays single. +- **File-local process instructions** (a phase prompt's "don't start the next + phase", a role doc's workflow steps) are implicitly owned by their file. The + completeness machinery permits them via a catch-all that **cannot** absorb + any text appearing on 2+ files — cross-surface duplication always demands an + explicit disposition. + +## Inventory boundary + +What the extractor scans (out-of-boundary content is out of scope *by +declaration*): `CLAUDE.md`, the two hot-tier files, the 3 role docs, the 9 +builder-prompts, and the 10 porch phase prompts. `AGENTS.md` is excluded from +scanning only because it is byte-identical to `CLAUDE.md` (enforced by T6). + +Deliberately outside: protocol.md docs, templates, consult-types (on-demand, +correctly tiered), COLD `arch.md`/`lessons-learned.md`, and `codev/resources/` +generally — user-evolved files where divergence is legitimate, which is also +why `FRAMEWORK_DRIFT_DIRS` omits `resources` (Q7). + +## Instruction classes (non-scar, cross-surface) + +Discovered by the extractor at Phase 6. Phase 7 extracted the uniform blocks +into shared partials (single authored owner; served prompts still carry the +full text via `{{> partials/...}}` include expansion) and flipped those +classes to `automated`. Classes whose remaining copies are protocol-specific +variants stay `manual` or carry declared `retained_restatements` (each +justified in the YAML): + +| Class | Owner | Enforcement | Refs / retained restatements | +|---|---|---|---| +| no-skip-porch-checks | partial-flaky | automated | — | +| no-skip-3way-review | partial-3way | automated | — | +| no-advance-phases-manually | partial-strict-restrictions | automated | — | +| baked-decisions-handling | partial-baked | automated | retained: bp-air, pp-specify, pp-implement, partial-pr-strategy, bp-spir, bp-aspir, spir-protocol-doc | +| pr-single-by-default | partial-pr-strategy | automated | — | +| porch-workflow-fidelity | partial-fidelity | automated | — | +| multi-pr-mechanics | partial-multi-pr | automated | — | +| notify-architect-key-moments | partial-notifications | automated | retained: bp-air, bp-bugfix | +| soft-mode-protocol-compliance | partial-soft-mode | automated | — | +| no-time-estimates | partial-no-time-estimates | automated | retained: spir-protocol-doc | + +## Phase-6 measurement + + +164 normative candidates over the boundary post-Phase-7 (the boundary now +includes the ten shared partials, so text moved there cannot bypass +extraction; every served prompt still receives the full text at assembly): +**15 mapped**, **39 scar** (registry-enforced), +**110 file-local**. Zero undispositioned; zero multi-file texts hiding behind +the catch-all. The parity marker above is +asserted against the live extractor by `prompt-ownership.test.ts` — if these +numbers drift from reality, CI fails until this companion is updated. + +## Enforcement + +- `prompt-ownership.test.ts` — T12 completeness (zero undispositioned; no + multi-file text via catch-all; seeded-line validated) and T7 single-owner + (derived from the YAML; machinery fixture-proven; live classes activate as + they flip to `automated`). +- `scar-rules.test.ts` — T6 verbatim replication for the eight scar rules. +- `shadow-drift-gate.test.ts` — tier-2 shadow copies of framework files fail CI. +- `skeleton-embed-sync.test.ts` — source skeleton ↔ embedded skeleton byte-parity. diff --git a/codev/resources/prompt-ownership.yaml b/codev/resources/prompt-ownership.yaml new file mode 100644 index 000000000..e48d98eca --- /dev/null +++ b/codev/resources/prompt-ownership.yaml @@ -0,0 +1,275 @@ +# Prompt-ownership map (Spec 1252, M1/M4 — Appendix A). +# +# THE SINGLE-OWNER RULE: every instruction has exactly one owning surface; all +# other surfaces reference or summarize it, never restate it. Scar rules are +# the ratified exception (see codev/resources/scar-rules.yaml — they replicate +# verbatim; their enforcement lives there, NOT here, so ownership of scar +# enforcement itself stays single). +# +# COMPLETENESS CONTRACT (T12, prompt-ownership.test.ts): a mechanical extractor +# collects every normative line (MUST/NEVER/ALWAYS/DO NOT/…) from the +# inventory_boundary below. Every candidate must resolve to a disposition: +# `mapped` (an instruction class below), `scar` (registered in +# scar-rules.yaml), or `out-of-scope` (with justification). No fourth state. +# The final catch-all may absorb only SINGLE-FILE candidates — any normative +# text appearing on 2+ boundary files must have a specific disposition, so new +# cross-surface duplication fails CI the moment it is introduced. +# +# Content OUTSIDE the boundary is out of scope BY DECLARATION, not by +# omission: protocol.md docs, templates, consult-types (on-demand reference, +# correctly tiered — see spec "What is working"), COLD arch.md / +# lessons-learned.md (user-evolved reference), and codev/resources/ generally. +# codev/resources/ is also deliberately excluded from the shadow-drift regime: +# FRAMEWORK_DRIFT_DIRS omits it because those are user-evolved files where +# divergence from any template is legitimate (Q7 — recording the WHY is +# required M1 coverage). + +inventory_boundary: + # Always-on + - CLAUDE.md + - codev/resources/arch-critical.md + - codev/resources/lessons-critical.md + # Spawn-delivered + - codev-skeleton/roles/architect.md + - codev-skeleton/roles/builder.md + - codev-skeleton/roles/consultant.md + - codev-skeleton/protocols/air/builder-prompt.md + - codev-skeleton/protocols/aspir/builder-prompt.md + - codev-skeleton/protocols/bugfix/builder-prompt.md + - codev-skeleton/protocols/experiment/builder-prompt.md + - codev-skeleton/protocols/maintain/builder-prompt.md + - codev-skeleton/protocols/pir/builder-prompt.md + - codev-skeleton/protocols/research/builder-prompt.md + - codev-skeleton/protocols/spike/builder-prompt.md + - codev-skeleton/protocols/spir/builder-prompt.md + # Per-phase (porch-injected) + - codev-skeleton/porch/prompts/defend.md + - codev-skeleton/porch/prompts/diagnose.md + - codev-skeleton/porch/prompts/evaluate.md + - codev-skeleton/porch/prompts/fix.md + - codev-skeleton/porch/prompts/implement.md + - codev-skeleton/porch/prompts/plan.md + - codev-skeleton/porch/prompts/pr.md + - codev-skeleton/porch/prompts/review.md + - codev-skeleton/porch/prompts/specify.md + - codev-skeleton/porch/prompts/test.md + # Shared partials — the single authored owners Phase 7 created; normative + # text added here must not bypass extraction (Codex, Phase-7 iter-3) + - codev-skeleton/partials/soft-mode-compliance.md + - codev-skeleton/partials/builder-notifications.md + - codev-skeleton/partials/multi-pr-mechanics.md + - codev-skeleton/partials/strict-mode-restrictions.md + - codev-skeleton/partials/no-time-estimates.md + - codev-skeleton/partials/flaky-test-handling.md + - codev-skeleton/partials/porch-workflow-fidelity.md + - codev-skeleton/partials/no-skip-3way-review.md + - codev-skeleton/partials/baked-decisions.md + - codev-skeleton/partials/pr-strategy.md + # NOTE: AGENTS.md is byte-identical to CLAUDE.md (enforced by T6); scanning + # both would double-count every candidate. + +surfaces: + - { id: claude-md, path: CLAUDE.md, load: always-on } + - { id: agents-md, path: AGENTS.md, load: always-on } + - { id: arch-critical, path: codev/resources/arch-critical.md, load: always-on } + - { id: lessons-critical, path: codev/resources/lessons-critical.md, load: always-on } + - { id: role-architect, path: codev-skeleton/roles/architect.md, load: spawn } + - { id: role-builder, path: codev-skeleton/roles/builder.md, load: spawn } + - { id: role-consultant, path: codev-skeleton/roles/consultant.md, load: spawn } + - { id: bp-air, path: codev-skeleton/protocols/air/builder-prompt.md, load: spawn } + - { id: bp-aspir, path: codev-skeleton/protocols/aspir/builder-prompt.md, load: spawn } + - { id: bp-bugfix, path: codev-skeleton/protocols/bugfix/builder-prompt.md, load: spawn } + - { id: bp-experiment, path: codev-skeleton/protocols/experiment/builder-prompt.md, load: spawn } + - { id: bp-maintain, path: codev-skeleton/protocols/maintain/builder-prompt.md, load: spawn } + - { id: bp-pir, path: codev-skeleton/protocols/pir/builder-prompt.md, load: spawn } + - { id: bp-research, path: codev-skeleton/protocols/research/builder-prompt.md, load: spawn } + - { id: bp-spike, path: codev-skeleton/protocols/spike/builder-prompt.md, load: spawn } + - { id: bp-spir, path: codev-skeleton/protocols/spir/builder-prompt.md, load: spawn } + - { id: pp-defend, path: codev-skeleton/porch/prompts/defend.md, load: phase-prompt } + - { id: pp-diagnose, path: codev-skeleton/porch/prompts/diagnose.md, load: phase-prompt } + - { id: pp-evaluate, path: codev-skeleton/porch/prompts/evaluate.md, load: phase-prompt } + - { id: pp-fix, path: codev-skeleton/porch/prompts/fix.md, load: phase-prompt } + - { id: pp-implement, path: codev-skeleton/porch/prompts/implement.md, load: phase-prompt } + - { id: pp-plan, path: codev-skeleton/porch/prompts/plan.md, load: phase-prompt } + - { id: pp-pr, path: codev-skeleton/porch/prompts/pr.md, load: phase-prompt } + - { id: pp-review, path: codev-skeleton/porch/prompts/review.md, load: phase-prompt } + - { id: pp-specify, path: codev-skeleton/porch/prompts/specify.md, load: phase-prompt } + - { id: pp-test, path: codev-skeleton/porch/prompts/test.md, load: phase-prompt } + # Ownership anchors outside the scan boundary (on-demand reference docs) + - { id: spir-protocol-doc, path: codev-skeleton/protocols/spir/protocol.md, load: on-demand } + - { id: agent-farm-doc, path: codev/resources/commands/agent-farm.md, load: on-demand } + # Shared partials — single authored owner, expanded into every served prompt + # at assembly time via {{> partials/...}} (resolveCodevIncludes) + - { id: partial-soft-mode, path: codev-skeleton/partials/soft-mode-compliance.md, load: spawn } + - { id: partial-notifications, path: codev-skeleton/partials/builder-notifications.md, load: spawn } + - { id: partial-multi-pr, path: codev-skeleton/partials/multi-pr-mechanics.md, load: spawn } + - { id: partial-strict-restrictions, path: codev-skeleton/partials/strict-mode-restrictions.md, load: spawn } + - { id: partial-no-time-estimates, path: codev-skeleton/partials/no-time-estimates.md, load: phase-prompt } + - { id: partial-flaky, path: codev-skeleton/partials/flaky-test-handling.md, load: spawn } + - { id: partial-fidelity, path: codev-skeleton/partials/porch-workflow-fidelity.md, load: spawn } + - { id: partial-3way, path: codev-skeleton/partials/no-skip-3way-review.md, load: spawn } + - { id: partial-baked, path: codev-skeleton/partials/baked-decisions.md, load: spawn } + - { id: partial-pr-strategy, path: codev-skeleton/partials/pr-strategy.md, load: spawn } + +# Non-scar instruction classes with cross-surface duplication, discovered by +# the extractor at Phase 6 and resolved in Phase 7 by SHARED PARTIALS, not +# prose references: builder/phase prompts are SERVED surfaces — each agent +# sees only its own prompt, so removing a rule from one prompt would delete +# it from that agent's context, not deduplicate it. The partial is the single +# AUTHORED owner; assembly expands it into every served prompt (per-agent +# single delivery — a rule appears at most once per served artifact, enforced +# by the assembled-prompt guard in prompt-ownership.test.ts). `references` +# remains for cross-tier pointer surfaces (which must never reproduce the +# rule text); `retained_restatements` declares protocol-specific variants +# kept by decision. +instructions: + - id: no-skip-porch-checks + summary: Never skip or work around porch checks to avoid a failure. + owner: partial-flaky + scar: false + pattern: "skip porch checks or use any workaround" + enforcement: automated + references: [] + # Phase-7 iter-4: line 4's documentation target was harmonized to + # protocol-neutral wording ("the artifact where your protocol records + # outcomes"), so all nine protocol prompts and the porch implement prompt + # now share the single partial — no retentions remain for this class. + + - id: no-skip-3way-review + summary: Never skip the 3-way review; follow the porch next/done cycle. + owner: partial-3way + scar: false + pattern: "NEVER skip the 3-way review" + enforcement: automated + references: [] + + - id: no-advance-phases-manually + summary: Porch advances plan phases; never advance them manually. + owner: partial-strict-restrictions + scar: false + pattern: "NEVER advance plan phases manually" + enforcement: automated + references: [] + + - id: baked-decisions-handling + summary: Treat issue-body Baked Decisions as fixed; escalate conflicts, never override. + owner: partial-baked + scar: false + pattern: "## Baked Decisions" + enforcement: automated + # served_max 3: every spawn prompt legitimately carries (1) the instruction + # section from the partial, plus the spir protocol doc's DESCRIPTION of the + # convention inlined via protocol_reference — (2) its "## Baked Decisions + # (Optional)" section header and (3) a backtick-quoted mention in prose. + # The doc is a declared retention (spir-protocol-doc); post-assembly the + # guard cannot attribute hits, so the ceiling is explicit. A 4th + # appearance still fails. + served_max: 3 + retained_restatements: [bp-air, pp-specify, pp-implement, partial-pr-strategy, bp-spir, bp-aspir, spir-protocol-doc] + manual_justification: > + Extracted for spir/aspir. bp-air keeps its protocol-specific wording + (Spec 746 wrote per-protocol clauses); the drafting prompts carry their + own 0.5-section variants; the pattern phrase also appears incidentally + in pr-strategy and the include lines. Retentions by decision, revisit + in MAINTAIN. + + - id: pr-single-by-default + summary: Builders do not autonomously open per-phase PRs; one PR by default. + owner: partial-pr-strategy + scar: false + pattern: "Do not autonomously open a PR per implementation phase" + enforcement: automated + references: [] + + - id: porch-workflow-fidelity + summary: Strict-mode builders follow the porch-driven workflow without deviation. + owner: partial-fidelity + scar: false + pattern: "Do not deviate from the porch-driven workflow" + enforcement: automated + references: [] + + - id: multi-pr-mechanics + summary: Sequential-PR mechanics (branch off origin, never checkout the integration branch). + owner: partial-multi-pr + scar: false + pattern: "git checkout " + enforcement: automated + references: [] + + - id: notify-architect-key-moments + summary: Builders notify the architect via afx send at key moments. + owner: partial-notifications + scar: false + pattern: "notify the architect at key moments" + enforcement: automated + retained_restatements: [bp-air, bp-bugfix] + manual_justification: > + AUTOMATED for the extracted spir/aspir pair. bp-air and bp-bugfix carry + protocol-specific notification templates (issue-number based, no gates) + by decision; revisit in MAINTAIN. + + - id: soft-mode-protocol-compliance + summary: Soft-mode builders have execution flexibility but must stay protocol-compliant. + owner: partial-soft-mode + scar: false + pattern: "must stay compliant with the protocol" + enforcement: automated + references: [] + + - id: no-time-estimates + summary: Plans and specs carry no time estimates; AI development makes them meaningless. + owner: partial-no-time-estimates + scar: false + pattern: "estimate time" + enforcement: automated + retained_restatements: [spir-protocol-doc] + manual_justification: > + spir-protocol-doc (on-demand) retains its own No-Time-Estimates + section as protocol reference prose by decision. + +# Disposition table — first match wins; the catch-all is last and may only +# absorb single-file candidates (enforced by T12). +dispositions: + # --- scar rules (enforced externally by scar-rules.yaml + T6) --- + - { match: "git add -A", disposition: scar } + - { match: "hand-edit `status.yaml`", disposition: scar } + - { match: "porch gate as approved", disposition: scar } + - { match: "destroy builder worktrees", disposition: scar } + - { match: "git reset --hard", disposition: scar } + - { match: "only from the main workspace root", disposition: scar } + - { match: "shellper process", disposition: scar } + - { match: "restart or stop Tower", disposition: scar } + + # --- mapped non-scar duplicated classes --- + - { match: "skip porch checks or use any workaround", disposition: mapped, class: no-skip-porch-checks } + - { match: "NEVER skip the 3-way review", disposition: mapped, class: no-skip-3way-review } + - { match: "NEVER advance plan phases manually", disposition: mapped, class: no-advance-phases-manually } + - { match: "Baked Decisions", disposition: mapped, class: baked-decisions-handling } + - { match: "baked-decisions section contains internal contradictions", disposition: mapped, class: baked-decisions-handling } + - { match: "git checkout ", disposition: mapped, class: multi-pr-mechanics } + - { match: "notify the architect at key moments", disposition: mapped, class: notify-architect-key-moments } + - { match: "must stay compliant with the protocol", disposition: mapped, class: soft-mode-protocol-compliance } + - { match: "Do not autonomously open a PR per implementation phase", disposition: mapped, class: pr-single-by-default } + - { match: "Do not deviate from the porch-driven workflow", disposition: mapped, class: porch-workflow-fidelity } + - { match: "/[Dd]on't estimate time|[Nn]o time estimates|NEVER include time estimates/", disposition: mapped, class: no-time-estimates } + + # --- known multi-file texts that are NOT instruction classes --- + - match: "DO NOT start implementation" + disposition: out-of-scope + note: > + Phase-boundary guard in specify/plan porch prompts — each phase prompt + legitimately owns its own "you are in phase X, don't do phase Y" line; + the duplication is structural to the phase machinery, not a rule restated. + - match: "DO NOT start phase_2" + disposition: out-of-scope + note: Porch runtime banner text, phase-machinery structural. + + # --- catch-all: single-file process instructions only --- + - match: "/.*/" + disposition: out-of-scope + catch_all: true + note: > + Single-occurrence, file-local process instruction — owned implicitly by + its file. T12 forbids this entry from absorbing any text that appears on + 2+ files, so new cross-surface duplication cannot hide here. diff --git a/codev/resources/scar-rules.yaml b/codev/resources/scar-rules.yaml new file mode 100644 index 000000000..18e49c12a --- /dev/null +++ b/codev/resources/scar-rules.yaml @@ -0,0 +1,119 @@ +# Scar-rule registry (Spec 1252, M5 / decision D3). +# +# A scar rule is a prohibition written in response to a specific incident where +# an agent destroyed work or bypassed a human decision. The eight rules below +# were ratified by the architect (2026-07-28), wordings compressed per D3 to +# one sentence (two max). Scar rules are EXEMPT from the single-owner rule: +# they appear verbatim on every surface listed in `must_appear_on` — the +# canonical wording converges, the number of copies does not shrink. +# +# ENFORCEMENT (scar-rules.test.ts / T6): +# - each rule's `canonical` string must appear byte-identically in every +# file listed under `must_appear_on`; +# - deleting a rule from this registry fails the build (the test pins the +# count at 8 and the ids); +# - rewording a copy on any surface fails the build (byte comparison). +# Changing a canonical wording is possible ONLY by editing this registry and +# every listed surface in the same commit — a loud, reviewable act. +# +# `must_appear_on` reflects where each rule actually applies today. Rules 3, 7 +# and 8 previously lived only in a user-global CLAUDE.md (not a repo surface); +# D3's ratification promotes them to the repo's always-on surfaces. + +scar_rules: + - id: git-add-explicit + canonical: "Never `git add -A` / `--all` / `.` — stage each file explicitly by path." + must_appear_on: + - CLAUDE.md + - AGENTS.md + - codev/resources/arch-critical.md + - codev-skeleton/templates/CLAUDE.md + - codev-skeleton/templates/AGENTS.md + - codev-skeleton/protocols/air/prompts/implement.md + - codev-skeleton/protocols/aspir/prompts/implement.md + - codev-skeleton/protocols/aspir/prompts/plan.md + - codev-skeleton/protocols/aspir/prompts/review.md + - codev-skeleton/protocols/aspir/prompts/specify.md + - codev-skeleton/protocols/bugfix/prompts/fix.md + - codev-skeleton/protocols/maintain/builder-prompt.md + - codev-skeleton/protocols/maintain/protocol.md + - codev-skeleton/protocols/maintain/prompts/maintain.md + - codev-skeleton/protocols/pir/prompts/implement.md + - codev-skeleton/protocols/pir/prompts/plan.md + - codev-skeleton/protocols/spir/prompts/implement.md + - codev-skeleton/protocols/spir/prompts/plan.md + - codev-skeleton/protocols/spir/prompts/review.md + - codev-skeleton/protocols/spir/prompts/specify.md + + - id: never-destroy-worktrees + canonical: "Never destroy builder worktrees (`git worktree remove`, `git branch -D` on builder branches, `afx cleanup` + respawn). Use `afx spawn --resume`; if it fails, ask the human — what is expendable is never your call." + must_appear_on: + - CLAUDE.md + - AGENTS.md + + - id: no-destructive-git + canonical: "Never run `git reset --hard`, `git checkout -- .`, `git clean -fd`, or `git stash` without explicit human permission — they destroy uncommitted work." + must_appear_on: + - CLAUDE.md + - AGENTS.md + + - id: human-gates + canonical: "Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization." + must_appear_on: + - CLAUDE.md + - AGENTS.md + - .claude/skills/porch/SKILL.md + - .codex/skills/porch/SKILL.md + - codev-skeleton/.claude/skills/porch/SKILL.md + - codev-skeleton/.codex/skills/porch/SKILL.md + - codev-skeleton/protocols/air/builder-prompt.md + - codev-skeleton/protocols/aspir/builder-prompt.md + - codev-skeleton/protocols/bugfix/builder-prompt.md + - codev-skeleton/protocols/experiment/builder-prompt.md + - codev-skeleton/protocols/maintain/builder-prompt.md + - codev-skeleton/protocols/pir/builder-prompt.md + - codev-skeleton/protocols/research/builder-prompt.md + - codev-skeleton/protocols/spir/builder-prompt.md + + - id: no-hand-edit-status + canonical: "Never hand-edit `status.yaml` — only porch commands modify project state." + must_appear_on: + - CLAUDE.md + - AGENTS.md + - codev/resources/arch-critical.md + - .claude/skills/porch/SKILL.md + - .codex/skills/porch/SKILL.md + - codev-skeleton/.claude/skills/porch/SKILL.md + - codev-skeleton/.codex/skills/porch/SKILL.md + - codev-skeleton/roles/builder.md + - codev-skeleton/protocols/air/builder-prompt.md + - codev-skeleton/protocols/aspir/builder-prompt.md + - codev-skeleton/protocols/bugfix/builder-prompt.md + - codev-skeleton/protocols/experiment/builder-prompt.md + - codev-skeleton/protocols/maintain/builder-prompt.md + - codev-skeleton/protocols/pir/builder-prompt.md + - codev-skeleton/protocols/research/builder-prompt.md + - codev-skeleton/protocols/spike/builder-prompt.md + - codev-skeleton/protocols/spir/builder-prompt.md + - codev-skeleton/porch/prompts/implement.md + - codev-skeleton/protocols/spir/prompts/implement.md + - codev-skeleton/protocols/aspir/prompts/implement.md + + - id: afx-from-root + canonical: "Run `afx` commands only from the main workspace root, never from inside a builder worktree — spawning from a worktree nests builders and breaks the workspace." + must_appear_on: + - CLAUDE.md + - AGENTS.md + - codev-skeleton/roles/architect.md + + - id: shellper-verified-orphan + canonical: "Never kill a shellper process without verifying it is an orphan (match each PID to its workspace via Tower) — an 'extra' shellper may be a live architect session." + must_appear_on: + - CLAUDE.md + - AGENTS.md + + - id: tower-restart-permission + canonical: "Never restart or stop Tower without explicit human permission — it kills every running builder session." + must_appear_on: + - CLAUDE.md + - AGENTS.md diff --git a/codev/reviews/1252-prompt-architecture-single-own.md b/codev/reviews/1252-prompt-architecture-single-own.md new file mode 100644 index 000000000..835a3ef78 --- /dev/null +++ b/codev/reviews/1252-prompt-architecture-single-own.md @@ -0,0 +1,152 @@ +# Review 1252: Prompt Architecture — Single-Owner Rule for Instruction Content + +## Outcome: harvested, not merged + +The full implementation (8 phases, unanimous CMAP approval at each phase's +final iteration, PR #1278) reached the pr gate and was **deliberately not +merged**. Waleed's charter-level call at the gate: the structural machinery +(shadow-tree deletion, scar registry + CI enforcement, ownership map, +dedup partials) is not worth carrying for *this* surface, because a successor +project will first shrink the surface radically (blog-principles judgment +rewrite; >50% reduction target; frontier-models-only assumption) and +enforcement should be rebuilt fit-for-purpose around the post-shrink surface. +This was a risk/reward re-scope, not a quality verdict — the audit and +measurement work from this project directly shaped the successor's charter. + +**What landed on main (this harvest PR):** + +- **The 17-file drift reconciliation** — the one live bug. `codev/`'s shadow + copies synced to the skeleton content, restoring the served SPIR/ASPIR + builder prompts' `Multi-PR Mechanics` and `Verify Phase` sections and the + `"Entering verify phase."` notification; architect rulings E1 + (`max_iterations: 3`, decided on the B2 evidence that review rounds run + 1–2) and E2 (check `cwd`s moved to main's `.codev/config.json` + `porch.checks`; the forked protocol.json files synced) applied. Spec-746 + pure-addition baselines re-derived for the synced files (a frozen-file + baseline breaks on any legitimate edit — see Lessons). +- **The knowledge artifacts**: `1252-shadow-tree-audit.md` (the 77-row + classification with rulings), `1252-word-baseline.md` / + `1252-word-after-phase7.md` (M6/N1 record), `1252-behavior-baseline.md` + (M12a — B1 51.88% REQUEST_CHANGES over 160 verdicts, with the B5 snapshot), + the measurement tooling (`scripts/measure-prompt-surface.sh`, + `packages/codev/src/lib/prompt-behavior-metrics.ts` + CLI + its + determinism test), this review, and the builder thread + (`codev/state/spir-1252_thread.md`). + +**What stayed on the branch** (`builder/spir-1252`, PR #1278 closed unmerged, +preserved for reference — do not delete): shadow-tree deletion + equivalence +proofs, scar registry + line-exact T6 enforcement, ownership map + T12 +completeness machinery, dedup partials + served-surface guard, CLAUDE.md +restructure, all skeleton edits, and their ~15 test suites. **The scar-registry +concept and the eight ratified rule wordings move into the successor charter** +— they are deferred, not discarded. + +## Summary of the full implementation (for the record) + +Issue #1252 asked for a single-owner rule with an inventory before +restructuring. Measurement reshaped the problem: the largest duplication axis +was a 77-file shadow tree under `codev/protocols|roles|consult-types` that +outranked the installed skeleton in the resolver and had drifted in 17 files — +including the served SPIR builder prompt, missing its entire `Verify Phase` +section. The project filed to fix prompt drift was itself spawned with a +drifted prompt, and the existing detector (#1210) had been reporting the +problem to `codev doctor`, unread, the whole time. + +The eight phases (all on the reference branch): drift CI gate + baselines; +77-row local-unique audit with TS1–TS4 terminal states and 4 architect-ruled +escalations; the 17-file reconciliation; shadow-tree deletion with +three-layer equivalence proof (resolver tier, byte-identical assembly across +nine protocols, spawn wrapper — which had instructed builders to read a +deleted role path, a live #1011-class bug); eight compressed scar rules with +line-exact enforcement; a machine-readable ownership map whose completeness +contract makes new cross-surface duplication fail CI; dedup via shared +partials (served prompts are per-agent delivery — a prose reference would +delete content from agents' context); and governance sync. + +**N1, honestly: 21,856 → 20,324 served always-on words = −7.0%** against an +aspirational ≥20%. The repair *added* ~207 served words the prompts were +always supposed to have; D3's promotion of three user-global scar rules added +~120; the remaining surface is single-owned prose whose largest block +(protocol.md, 3,703 words) was protocol semantics — a spec Non-goal. That +decomposition is exactly why the successor pivots to shrinking the surface +itself before rebuilding enforcement. + +## Architecture Updates + +The harvest changes no architecture: it syncs shadow-copy *content* to what +the skeleton already ships and lands record-keeping artifacts. The +resolver, the shadow tree's existence, and all governance docs remain as on +main. (The branch's arch-doc rewrites — C6 retirement, single-owner +invariant, glossary corrections — apply to a world where the deletion merged; +they stay with the branch and inform the successor.) + +One architectural *fact* the audit established that main's docs do not yet +state: `copyProtocols`/`copyRoles` in `scaffold.ts` are vestigial (uncalled by +init/adopt/update), so fresh adopters have no shadow tree — this repo's was a +historical artifact. Recorded here for the successor rather than edited into +arch.md out-of-band. + +## Lessons Learned Updates + +Not routed into the shared lessons docs (those edits stayed with the branch); +recorded here for the successor and for MAINTAIN to promote as it sees fit: + +- **A detector that reports without failing is a detector nobody reads.** + #1210 saw this drift for months; Spec 746's comments described it + ("PRE-EXISTING and not Phase 1's responsibility") before stepping around + it. Detection was never the gap — consequence was. +- **Frozen-file baselines are drift bombs.** Spec 746's pure-addition + baselines froze then-drifted files; the legitimate reconciliation broke + them twice (branch and harvest). Derive baselines from current content + minus the asserted insertion instead of freezing snapshots. +- **The corpus is live — a baseline can measure itself.** This project's own + review verdicts contaminated its behavioural baseline (160 → 163) and its + thread file contributed a scar-mining hit; self-exclusion + (`SELF_PROJECT_DIR` / `SELF_FILE_PREFIXES`) had to be built in. +- **"The data exists" ≠ "the metric resolves."** B2 as first specified + ("rounds to unanimous approve") could never resolve: 0 of 48 terminal plan + phases end unanimously — porch advances on rebuttal. +- **Served surfaces dedup by include, not by reference** — each agent sees + only its own prompt; and the measurement must count expanded words or the + metric rewards moving text between files. +- **Sweep-scope failures dominated review iterations**: fixing the flagged + instance instead of the class, grepping for a rule's wording instead of the + act's, repointing a path while preserving the fetch instruction. +- **Gate-rejection counts are not minable** from committed history (no + `rejected` state exists; `requested_at` is overwritten) — a porch + gate-event append-log would fix this (MAINTAIN candidate). + +## Deviations from the Plan + +The implementation deviations (metrics-script location, B2 redefinition, +escalation-deadline correction, reference→include model, T13(b) +rescheduling) are recorded in the phase rebuttals on the branch. The terminal +deviation is this outcome itself: plan phases 4–8's deliverables were built, +reviewed, and then deliberately left unmerged by the pr-gate decision. + +## Flaky Tests + +None skipped, in either the branch suite (3,744 green at close) or the +harvest suite. + +## Verify Phase + +The original verify plan (T13(b) spawn probe + M12b behavioural comparison +with rollback triggers) applied to the unmerged machinery and does not run. +The behavioural baseline remains valid as the **pre-successor** measurement: +the successor project should treat `1252-behavior-baseline.md` (B1 51.88%, +n=160, self-excluded) as its "before" and re-run +`packages/codev/scripts/measure-prompt-behavior.ts` after its rewrite lands. + +## Follow-ups + +- **Successor project** (charter held by Waleed): radical surface shrink + (blog-principles judgment rewrite, >50% target, frontier-models-only), + then fit-for-purpose enforcement; **carries forward the scar-registry + concept and the eight D3-ratified rule wordings**, the ownership-map + design, and this project's audit + baselines. +- #1276 (multi-model tiering) and #1277 (controlled A/B eval) — filed during + Phase 8; both now feed the successor rather than this branch. +- Reference branch: `builder/spir-1252` (PR #1278, closed unmerged) — the + complete machinery with its review history, preserved until cleanup is + ordered. diff --git a/codev/roles/architect.md b/codev/roles/architect.md deleted file mode 100644 index aa07e6fbd..000000000 --- a/codev/roles/architect.md +++ /dev/null @@ -1,345 +0,0 @@ -# Role: Architect - -The Architect is the **project manager and gatekeeper** who decides what to build, spawns builders, approves gates, and ensures integration quality. - -> **Quick Reference**: See `codev/resources/workflow-reference.md` for stage diagrams and common commands. - -## Key Concept: Spawning Builders - -Builders work autonomously in isolated git worktrees. The Architect: -1. **Decides** what to build -2. **Spawns** builders via `afx spawn` -3. **Approves** gates (spec-approval, plan-approval) when in strict mode -4. **Reviews** PRs for integration concerns - -### Two Builder Modes - -| Mode | Command | Use When | -|------|---------|----------| -| **Strict** (default) | `afx spawn XXXX --protocol spir` | Porch orchestrates - runs autonomously to completion | -| **Soft** | `afx spawn XXXX --protocol spir --soft` | AI follows protocol - you verify compliance | - -**Strict mode** (default): Porch orchestrates the builder with automated gates, 3-way consultations, and enforced phase transitions. More likely to complete autonomously without intervention. - -**Soft mode**: Builder reads and follows the protocol document, but you monitor progress and verify the AI is adhering to the protocol correctly. Use when you want more hands-on oversight. - -### Pre-Spawn Checklist - -**Before every `afx spawn`, complete these steps:** - -1. **`git status`** — Ensure worktree is clean (no uncommitted changes) -2. **Commit if needed** — Builders branch from HEAD; uncommitted specs/plans are invisible -3. **`afx spawn N --protocol `** — `--protocol` is **REQUIRED** (spir, bugfix, tick, etc.) - -The spawn command will refuse if the worktree is dirty (override with `--force`, but your builder won't see uncommitted files). - -## Key Tools - -### Agent Farm CLI (`afx`) - -```bash -afx spawn 1 --protocol spir # Strict mode (default) - porch-driven -afx spawn 1 --protocol spir -t "feature" # Strict mode with title (no spec yet) -afx spawn 1 --resume # Resume existing porch state -afx spawn 1 --protocol spir --soft # Soft mode - protocol-guided -afx spawn --task "fix the bug" # Ad-hoc task builder (soft mode) -afx spawn --worktree # Worktree with no initial prompt -afx status # Check all builders -afx cleanup -p 0001 # Remove completed builder -afx workspace start/stop # Workspace management -afx send 0001 "message" # Short message to builder -``` - -> **Note:** `--protocol` is REQUIRED for all numbered spawns. Only `--task`, `--shell`, and `--worktree` spawns skip it. - -**Note:** `afx`, `consult`, `porch`, and `codev` are global commands. They work from any directory. - -### Porch CLI (for strict mode) - -```bash -porch status 0001 # Check project state -porch approve 0001 spec-approval # Approve a gate -porch pending # List pending gates -``` - -### Consult Tool (for integration reviews) - -```bash -# Single-model review (medium risk) -consult -m claude --type integration pr 35 - -# 3-way parallel review (high risk) -consult -m gemini --type integration pr 35 & -consult -m codex --type integration pr 35 & -consult -m claude --type integration pr 35 & -wait -``` - -## Responsibilities - -1. **Decide what to build** - Identify features, prioritize work -2. **Track projects** - Use GitHub Issues as the project registry -3. **Spawn builders** - Choose soft or strict mode based on needs -4. **Approve gates** - (Strict mode) Review specs and plans, approve to continue -5. **Monitor progress** - Track builder status, unblock when stuck -6. **Integration review** - Review PRs for architectural fit -7. **Manage releases** - Group projects into releases - -## Workflow - -### 1. Starting a New Feature - -```bash -# 1. Create a GitHub Issue for the feature -# 2. Ensure worktree is clean: git status → commit if needed -# 3. Spawn the builder (--protocol is REQUIRED) - -# Default: Strict mode (porch-driven with gates) -afx spawn 42 --protocol spir - -# With project title (if no spec exists yet) -afx spawn 42 --protocol spir -t "user-authentication" - -# Or: Soft mode (builder follows protocol independently) -afx spawn 42 --protocol spir --soft - -# For bugfixes -afx spawn 42 --protocol bugfix -``` - -### 2. Approving Gates (Strict Mode Only) - -The builder stops at gates requiring approval: - -**spec-approval** - After builder writes the spec -```bash -# Review the spec in the builder's worktree -cat .builders/spir-0042-feature-name/codev/specs/0042-feature-name.md - -# Approve if satisfactory (run from builder's worktree context) -(cd .builders/spir-0042-feature-name && porch approve 0042 spec-approval --a-human-explicitly-approved-this) - -# IMPORTANT: Always message the builder after approving a gate -afx send 0042 "Spec approved. Continue to plan phase." -``` - -**plan-approval** - After builder writes the plan -```bash -# Review the plan -cat .builders/spir-0042-feature-name/codev/plans/0042-feature-name.md - -# Approve if satisfactory (run from builder's worktree context) -(cd .builders/spir-0042-feature-name && porch approve 0042 plan-approval --a-human-explicitly-approved-this) - -# IMPORTANT: Always message the builder after approving a gate -afx send 0042 "Plan approved. Continue to implement phase." -``` - -### 3. Monitoring Progress - -```bash -afx status # Overview of all builders -porch status 0042 # Detailed state for one project (strict mode) -``` - -### 4. Integration Review (Risk-Based Triage) - -When the builder creates a PR, **assess risk first** before deciding review depth. - -> **Full reference**: See `codev/resources/risk-triage.md` for subsystem mappings and examples. - -#### Step 1: Assess Risk - -```bash -gh pr diff --stat # See lines changed and files touched -gh pr view --json files | jq '.files[].path' # See which subsystems -``` - -#### Step 2: Triage - -| Risk | Criteria | Action | -|------|----------|--------| -| **Low** | <100 lines, 1-3 files, isolated (docs, tests, cosmetic, bugfixes) | Read PR, summarize root cause + fix, tell builder to merge | -| **Medium** | 100-500 lines, 4-10 files, touches shared code (features, commands) | Single-model review: `consult -m claude --type integration pr N` | -| **High** | >500 lines, >10 files, core subsystems (porch, Tower, protocols, security) | Full 3-way CMAP (see below) | - -**Precedence: highest factor wins.** If any single factor (lines, files, subsystem, or cross-cutting scope) is high-risk, treat the whole PR as high-risk. - -**Typical mappings:** -- **Low**: Most bugfixes, ASPIR features, documentation, UI tweaks -- **Medium**: SPIR features, new commands, refactors touching 3+ files -- **High**: Protocol changes, porch state machine, Tower architecture, security model - -#### Presenting the decision to the human (PRFT) - -When you bring a fix to the human for a decision — a merge word, a `pr` gate, a dev-approval — present it **unprompted** in PRFT form, whatever the risk tier: - -- **Problem** — the user-visible symptom, in a sentence or two. -- **Root Cause** — the verified mechanism. Verify it yourself; a builder's summary is evidence, not ground truth. -- **Fix** — what changed and why it's safe. -- **Testing** — the evidence: suites run, live verification, CI state. - -Keep each part tight and lead with it — don't bury the decision under process narration. The human should be able to say yes or no from your message alone, without opening the diff. - -#### Step 3: Execute Review - -**Low risk** — no external models needed: -```bash -# Read the PR yourself, then approve -gh pr comment 83 --body "## Architect Review - -Low-risk change. [Summary of what changed and why.] - ---- -Architect review" - -afx send 0042 "PR approved, please merge" -``` - -**Medium risk** — single-model review: -```bash -consult -m claude --type integration pr 83 - -# Post findings as PR comment -gh pr comment 83 --body "## Architect Integration Review -... -Architect integration review" - -afx send 0042 "PR approved, please merge" -``` - -**High risk** — full 3-way CMAP: -```bash -consult -m gemini --type integration pr 83 & -consult -m codex --type integration pr 83 & -consult -m claude --type integration pr 83 & -wait - -# Post findings as PR comment -gh pr comment 83 --body "## Architect Integration Review -... -Architect integration review" - -afx send 0042 "PR approved, please merge" -``` - -### 5. Cleanup - -After builder merges and work is integrated: - -```bash -# 1. Close the GitHub Issue -gh issue close 42 - -# 2. Clean up the builder worktree -afx cleanup -p 0042 -``` - -**Always close the GitHub Issue when the PR merges.** This is the architect's responsibility — builders don't close issues. - -## Critical Rules - -### NEVER Do These: -1. **DO NOT merge PRs yourself** - Let builders merge their own PRs -2. **DO NOT commit directly to main** - All changes go through builder PRs -3. **DO NOT use `afx send` for long messages** - Use GitHub PR comments instead -4. **DO NOT run `afx` commands from inside a builder worktree** - All `afx` commands must be run from the repository root on `main`. Spawning from a worktree nests builders inside it, breaking everything. - -### ALWAYS Do These: -1. **Create GitHub Issues first** - Track projects as issues before spawning -2. **Review artifacts before approving gates** - (Strict mode) Read the spec/plan carefully -3. **Use PR comments for feedback** - Not terminal send-keys -4. **Let builders own their work** - Guide, don't take over -5. **Stay on `main` at the repo root** - All architect operations happen from the main workspace - -## Project Tracking - -**GitHub Issues are the canonical source of truth for project tracking.** - -```bash -# See what needs work -gh issue list --label "priority:high" - -# View a specific project -gh issue view 42 -``` - -Update status as projects progress: -- `conceived` → `specified` → `planned` → `implementing` → `committed` → `integrated` - -## Working with Area Labels - -**Operational recipes:** - -```bash -# Confirm the current label vocabulary (use before any label op to catch drift) -gh label list --search area/ - -# Group: tally open issues by area -gh issue list --state open --limit 500 --json number,title,labels --jq \ - 'group_by([.labels[].name | select(startswith("area/"))]) | .[] | "\(.[0].labels[] | select(.name | startswith("area/")).name): \(length)"' - -# Edit: change area on a single issue -gh issue edit --remove-label area/old --add-label area/new - -# Audit: find open issues with no area label -gh issue list --state open --limit 500 --json number,title,labels \ - --jq '.[] | select([.labels[].name] | any(startswith("area/")) | not) | "#\(.number) \(.title)"' - -# Bulk-move: relabel all open `area/` issues to `area/` -for n in $(gh issue list --state open --limit 500 --label area/old --json number --jq '.[].number'); do - gh issue edit "$n" --remove-label area/old --add-label area/new -done -``` - -## Handling Blocked Builders - -When a builder reports blocked: - -1. Check their status: `afx status` or `porch status ` -2. Read their output in the terminal: `http://localhost:` -3. Provide guidance via short `afx send` message -4. Or answer their question directly if they asked one - -## Release Management - -The Architect manages releases - deployable units grouping related projects. - -``` -planning → active → released → archived -``` - -- Only **one release** should be `active` at a time -- Projects should be assigned to a release before `implementing` -- All projects must be `integrated` before release is marked `released` - -## UX Verification (Critical) - -Before approving implementations with UX requirements: - -1. **Read the spec's Goals section** -2. **Manually test** the actual user experience -3. Verify each UX requirement is met - -**Auto-reject if:** -- Spec says "async" but implementation is synchronous -- Spec says "immediate" but user waits 30+ seconds -- Spec has flow diagram that doesn't match reality - -## Quick Reference - -| Task | Command | -|------|---------| -| Start feature (strict, default) | `afx spawn --protocol spir` | -| Start feature (soft) | `afx spawn --protocol spir --soft` | -| Start bugfix | `afx spawn --protocol bugfix` | -| Check all builders | `afx status` | -| Check one project | `porch status ` | -| Approve spec | `porch approve spec-approval` | -| Approve plan | `porch approve plan-approval` | -| See pending gates | `porch pending` | -| Assess PR risk | `gh pr diff --stat N` | -| Integration review (medium) | `consult -m claude --type integration pr N` | -| Integration review (high) | 3-way CMAP (see Section 4) | -| Message builder | `afx send "short message"` | -| Cleanup builder | `afx cleanup -p ` | diff --git a/codev/roles/builder.md b/codev/roles/builder.md deleted file mode 100644 index be5d7cbf5..000000000 --- a/codev/roles/builder.md +++ /dev/null @@ -1,232 +0,0 @@ -# Role: Builder - -A Builder is an implementation agent that works on a single project in an isolated git worktree. - -## Two Operating Modes - -Builders run in one of two modes, determined by how they were spawned: - -| Mode | Command | Behavior | -|------|---------|----------| -| **Strict** (default) | `afx spawn XXXX` | Porch orchestrates - runs autonomously to completion | -| **Soft** | `afx spawn XXXX --soft` | AI follows protocol - architect verifies compliance | - -## Strict Mode (Default) - -Spawned with: `afx spawn XXXX` - -In strict mode, porch orchestrates your work and drives the protocol to completion autonomously. Your job is simple: **run porch until the project completes**. - -### The Core Loop - -```bash -# 1. Check your current state -porch status - -# 2. Run the protocol loop -porch run - -# 3. If porch hits a gate, STOP and wait for human approval -# 4. After gate approval, run porch again -# 5. Repeat until project is complete -``` - -Porch handles: -- Spawning Claude to create artifacts (spec, plan, code) -- Running 3-way consultations (Gemini, Codex, Claude) -- Iterating based on feedback -- Enforcing phase transitions - -### Gates: When to STOP - -Porch has two human approval gates: - -| Gate | When | What to do | -|------|------|------------| -| `spec-approval` | After spec is written | **STOP** and wait | -| `plan-approval` | After plan is written | **STOP** and wait | - -When porch outputs: -``` -GATE: spec-approval -Human approval required. STOP and wait. -``` - -You must: -1. Output a clear message: "Spec ready for approval. Waiting for human." -2. **STOP working** -3. Wait for the human to run `porch approve XXXX spec-approval` -4. After approval, run `porch run` again - -### What You DON'T Do in Strict Mode - -- **Don't manually follow SPIR steps** - Porch handles this -- **Don't run consult directly** - Porch runs 3-way reviews -- **Don't edit status.yaml phase/iteration** - Only porch modifies state -- **Don't call porch approve** - Only humans approve gates -- **Don't skip gates** - Always stop and wait for approval - -## Soft Mode - -Spawned with: `afx spawn XXXX --soft` or `afx spawn --task "..."` - -In soft mode, you follow the protocol document yourself. The architect monitors your work and verifies you're adhering to the protocol correctly. - -### Startup Sequence - -```bash -# Read the spec and/or plan -cat codev/specs/XXXX-*.md -cat codev/plans/XXXX-*.md - -# (The full protocol text is inlined in your spawn prompt under the -# "## Protocol Reference (full text)" heading; no need to fetch it.) - -# Start implementing -``` - -### The SPIR Protocol (Specify → Plan → Implement → Review (→ Verify)) - -1. **Specify**: Read or create the spec at `codev/specs/XXXX-name.md` -2. **Plan**: Read or create the plan at `codev/plans/XXXX-name.md` -3. **Implement**: Write code following the plan phases -4. **Review**: Write lessons learned and create PR -5. **Verify** (optional): After PR merge, verify the feature works in the integrated codebase - -### Consultations - -Run 3-way consultations at checkpoints: -```bash -# After writing spec -consult -m gemini --protocol spir --type spec & -consult -m codex --protocol spir --type spec & -consult -m claude --protocol spir --type spec & -wait - -# After writing plan -consult -m gemini --protocol spir --type plan & -consult -m codex --protocol spir --type plan & -consult -m claude --protocol spir --type plan & -wait - -# After implementation -consult -m gemini --protocol spir --type pr & -consult -m codex --protocol spir --type pr & -consult -m claude --protocol spir --type pr & -wait -``` - -## Deliverables - -- Spec at `codev/specs/XXXX-name.md` -- Plan at `codev/plans/XXXX-name.md` -- Review at `codev/reviews/XXXX-name.md` -- Implementation code with tests -- PR ready for architect review - -## Communication - -### With the Architect - -If you're blocked or need help: -```bash -afx send architect "Question about the spec..." -``` - -### Checking Status - -```bash -porch status # (strict mode) Your project status -afx status # All builders -``` - -## Thread file - -You maintain a free-text markdown log at `codev/state/_thread.md` (relative to your worktree). This is the cohort's collective situational-awareness surface — architects and sibling builders can read it via plain file I/O. - -**Path resolution**: `` is the basename of your worktree path. Resolve it once with `basename "$(pwd)"`. Example: if your worktree is `.builders/spir-823/`, the path is `codev/state/spir-823_thread.md`. - -**Directory creation**: `codev/state/` likely doesn't exist when you start (it's greenfield). Your first write creates it — the Write tool's `mkdir -p` semantics handle this transparently. No need to pre-create the directory. - -**What to write**: phase transitions, decisions, blockers, anything worth recording for the cohort. Trust your own judgement about what's useful. There is no required schema, no required sections, no timestamp format. The thread is yours. - -**When to write**: at phase boundaries and at any other moment you think a future reader would want to know what happened. Don't over-engineer cadence — append when there's something to say. - -**Discovery**: -- **In-flight** (while you're active): your thread lives in your worktree at `.builders//codev/state/_thread.md` (from the main workspace root). Architects read it with `cat .builders//codev/state/_thread.md`; they discover threads with `ls .builders/*/codev/state/*.md`. -- **Sibling builders**: read each other's threads via `cat ..//codev/state/_thread.md` from your own worktree (the parent `.builders/` directory is shared between all builders in the workspace). -- **Post-merge**: after your PR merges, your thread lands in `codev/state/` on `main` (parallel to `codev/reviews/`) and becomes part of the historical review record. - -**Commit/retention rule**: **the default disposition is COMMIT.** Stage and commit your thread file as part of your PR. The rare exception — when your thread turned out to be noise rather than useful narrative — is an explicit decision to strip it before PR (via gitignore for the PR or by not staging the file). Silently leaving the thread uncommitted by accident is a bug, not an exercise of the exception. The cohort's situational-awareness goal depends on threads surviving to `main`. - -**Scope reminder**: this is for the cohort's situational awareness, not porch's tracking. Porch does not read this file. There are no hooks, no validation, no enforcement. - -## Notifications - -**ALWAYS notify the architect** via `afx send` at these key moments: - -| When | What to send | -|------|-------------| -| **Gate reached** | `afx send architect "Project XXXX: ready for approval"` | -| **PR ready** | `afx send architect "PR #N ready for review"` | -| **PR merged** | `afx send architect "Project XXXX complete. PR merged. Entering verify phase."` | -| **Blocked/stuck** | `afx send architect "Blocked on X — need guidance"` | -| **Escalation needed** | `afx send architect "Issue too complex — recommend escalating to SPIR"` | - -The architect may be working on other tasks and won't know you need attention unless you send a message. **Don't assume they're watching** — always notify explicitly. - -## When You're Blocked - -If you encounter issues you can't resolve: - -1. **Output a clear blocker message** describing the problem and options -2. **Use `afx send architect "..."` to notify the Architect** -3. **Wait for guidance** before proceeding - -Example: -``` -## BLOCKED: Spec 0077 -Can't find the auth helper mentioned in spec. Options: -1. Create a new auth helper -2. Use a third-party library -3. Spec needs clarification -Waiting for Architect guidance. -``` - -## Multi-PR Workflow - -Builders may submit multiple sequential PRs within a single worktree session. The worktree persists across PRs -- it is not cleaned up automatically after merge. This allows builders to do follow-up work (e.g., addressing review feedback in a second PR, or splitting large features across checkpoint PRs). - -- **Worktree cleanup is architect-driven** -- the architect decides when to run `afx cleanup`, not the builder -- If a builder session is interrupted, use `afx spawn XXXX --resume` to reconnect to the existing worktree - -## Worktree isolation: filesystem path discipline - -Your worktree (`.builders//`) is **nested inside the main checkout**, and at the -branch base the two trees are **byte-identical**. This creates a silent failure mode: - -- The `Write`/`Edit` tools require **absolute** paths. If you synthesize one rooted - at the canonical repo root instead of your worktree, you drop the `.builders//` - segment and write into the **main checkout** — a real, writable directory. The - write *succeeds silently* and pollutes `main`; you only notice later when a - `git add` in your worktree fails with a pathspec error. -- Wrong-rooted **reads** also succeed silently (identical trees), so nothing - corrects the mistake until that first failed write. - -Rules: -- **Absolute paths for Write/Edit must be rooted at your worktree.** A deterministic - PreToolUse guard now blocks out-of-worktree writes (allowing only temp dirs and - `~/.claude`); if you see that denial, re-root the path under your worktree. -- **Bash `cwd` is your worktree — prefer relative paths there.** A relative path - cannot be anchored to the wrong root, which closes the Bash write surface - (`>`, `cp`, `tee`, `sed -i`) the Write/Edit guard does not cover. - -## Constraints - -- **Stay in scope** - Only implement what's in the spec -- **Merge your own PRs** - After architect approves -- **Keep worktree clean** - No untracked files, no debug code -- **(Strict mode)** Run porch, don't bypass it -- **(Strict mode)** Stop at gates - Human approval is required -- **(Strict mode)** NEVER edit status.yaml directly -- **(Strict mode)** NEVER call porch approve diff --git a/codev/roles/consultant.md b/codev/roles/consultant.md deleted file mode 100644 index bc8e2b6d0..000000000 --- a/codev/roles/consultant.md +++ /dev/null @@ -1,33 +0,0 @@ -# Role: Consultant - -You are a consultant providing a second perspective to support decision-making. - -## Responsibilities - -1. **Understand context** - Grasp the problem and constraints being presented -2. **Verify before flagging** - Check actual project files (package.json, configs) before claiming something is wrong or missing. Framework conventions change between major versions. -3. **Offer insights** - Provide alternatives or considerations that may have been missed -4. **Be constructive** - Help improve the solution, don't just critique -5. **Be direct** - Give honest, clear feedback without excessive hedging - -## You Are NOT - -- An adversary or gatekeeper -- A rubber stamp that just agrees -- A source of generic advice that ignores actual project context - -## Relationship to Other Roles - -| Role | Focus | -|------|-------| -| Architect | Orchestrates, decomposes, integrates | -| Builder | Implements in isolation | -| Consultant | Provides perspective, supports decisions | - -You think alongside the other agents, helping them see blind spots. You have filesystem access — use it to verify your claims against the actual codebase. - -## File Access Rules - -- **ALWAYS read files directly from disk** when reviewing specs, plans, or code. File paths are provided in the query — open and read them. -- **NEVER rely on `git diff` or `git log -p` as your primary review source.** Diffs are lossy, get truncated, and miss uncommitted work. Read the actual files instead. -- If you need to understand what changed, read the full file first, then optionally use `git diff` as a secondary reference. diff --git a/codev/specs/1252-prompt-architecture-single-own.md b/codev/specs/1252-prompt-architecture-single-own.md new file mode 100644 index 000000000..535f488ba --- /dev/null +++ b/codev/specs/1252-prompt-architecture-single-own.md @@ -0,0 +1,1181 @@ +--- +approved: 2026-07-27 +validated: [gemini, codex, claude] +--- + +# Spec 1252: Prompt Architecture — Single-Owner Rule for Instruction Content + +## Metadata + +- **Issue**: #1252 +- **Protocol**: SPIR +- **Area**: `area/cross-cutting` +- **Status**: approved (spec-approval gate, 2026-07-27; amended with architect + decisions D1–D5 and the T13(b) verify-phase ruling) +- **Author**: builder spir-1252 + +--- + +## Terminology + +Defined once, used consistently throughout: + +- **Skeleton** — `codev-skeleton/`, the framework template that ships in the + `@cluesmith/codev` package and is served as tier 4 by the resolver. +- **Shadow copy** — a project-local file under `codev/` (tier 2) or `.codev/` + (tier 1) that has a same-named counterpart in the skeleton. Because tiers 1–2 + win, the shadow copy is what actually gets served. +- **Shadow tree** — the set of shadow copies under `codev/protocols/` and + `codev/roles/` in *this* repository. "Shadow tree" never refers to the + skeleton itself. +- **Drifted** — a shadow copy whose content differs from its skeleton + counterpart. Distinct from **local-only**, a file under `codev/` with *no* + skeleton counterpart (legitimate; must be preserved). +- **Scar rule** — a prohibition written in response to a specific incident in + which an agent destroyed work or bypassed a human decision. + +--- + +## Clarifying Questions Asked + +No spec existed and issue #1252 carries no `Baked Decisions` section, so no +architect decisions are pinned. Rather than block, I resolved the framing +question — *how big is the problem and where does it concentrate?* — by +measuring the repository directly. All figures below are reproducible via +**Test Scenarios**. + +Two questions remain genuinely architect-owned and are escalated in +**Open Questions** (Critical). Per Codex's review, the spec's required end state +no longer depends on their answers. + +--- + +## Problem Statement + +Codev's shipped instruction surface is large, and the same rules are restated +across many files. Three costs follow: **drift** (an edit lands in one copy, +others go stale), **token cost** (duplicated rules ride into every prompt), and +**ambiguity** (an agent meets two wordings of one rule and cannot tell which is +authoritative). + +The issue estimated "~45,000 words" and "4–6 surfaces" per rule. Measurement +shows a larger surface, a worse per-rule duplication factor, and one duplication +axis the issue does not name — which is already causing a live failure. + +### The headline finding: the `codev/` shadow tree + +`codev/protocols/` and `codev-skeleton/protocols/` both exist. **63 `.md` files +(73 including `.json`) are present in both trees**, totalling 45,183 words of +markdown; `codev/roles/` adds 3 more, for **76 shadow copies overall**. + +The four-tier resolver (`packages/codev/src/lib/skeleton.ts:63`, +`resolveCodevFile`) prefers `.codev/` → `codev/` → cache → skeleton. **Tier 2 +wins**, so this repository runs the shadow copies while adopters run the +skeleton. The two have forked: **17 shadow copies have drifted** — 16 under +`protocols/` (11 `.md`, 5 `.json`) and 1 under `roles/`. + +Separately and legitimately, three **local-only** entries have no skeleton +counterpart and must survive any cleanup: `codev/protocols/release/`, and +`codev/protocols/maintain/templates/{audit-report.md,lessons-learned.md}`. + +#### The 16 drifted protocol files + +``` +air/protocol.json aspir/templates/spec.md spike/protocol.md +air/protocol.md bugfix/builder-prompt.md spir/builder-prompt.md +aspir/builder-prompt.md bugfix/protocol.json spir/protocol.json +aspir/protocol.json experiment/protocol.md spir/protocol.md +aspir/templates/plan.md protocol-schema.json spir/templates/plan.md + spir/templates/spec.md +``` + +Plus `codev/roles/architect.md`. + +#### Proof: the drift already broke this builder + +`codev/protocols/spir/builder-prompt.md` (636 words — *served* here) is missing +two whole sections that `codev-skeleton/protocols/spir/builder-prompt.md` +(824 words — *shipped*) contains: + +- `### Multi-PR Mechanics (when the architect requests sequential PRs)` +- `## Verify Phase` + +The spawn prompt for this very project therefore contains **no verify-phase +instructions**. Adopters get them; the Codev repository does not. The +notification string drifted too: local says `"Ready for cleanup."`, skeleton +says `"Entering verify phase."`. + +`codev/protocols/spir/protocol.md` differs by **138 diff lines**. Both files +were last modified by the same merge commit (`d49f5f47`, 2026-06-13) — forked +once, then left to rot. + +The project filed to fix prompt drift was spawned with a drifted prompt. + +### Why the shadow tree exists — and why adopters are safe + +`packages/codev/src/lib/scaffold.ts` exports `copyProtocols` (line 480) and +`copyRoles` (line 425), which copy the skeleton into `codev/protocols/` and +`codev/roles/`. **Neither is called by `init`, `adopt`, or `update`** — a +repo-wide search finds callers only in `scaffold.test.ts` (and none at all for +`copyProtocols`). They are **vestigial code**. + +Two consequences: + +1. **Fresh adopters do not get a shadow tree.** They resolve protocols from the + skeleton at tier 4, exactly as `arch-critical.md` states. This repository's + shadow tree is a **historical artifact** from when scaffolding did copy. +2. **Deleting our shadow tree would make Codev match its own adopters** — the + dogfooding argument — and the two dead functions should go with it, before + someone rewires them and manufactures the problem for everyone. + +This corrects Assumption A1 of iteration 1, which speculated that the trees were +unintentional forks without establishing why. + +### Existing infrastructure this spec builds on (#1210) + +**Iteration 1 wrongly claimed "no test asserts that `codev/protocols/` matches +`codev-skeleton/protocols/`."** Claude's review caught this. +`packages/codev/src/lib/protocol-drift-audit.ts` (#1210) already implements +shadow-drift detection, with a test suite at +`packages/codev/src/__tests__/protocol-drift-audit.test.ts`: + +```ts +FRAMEWORK_DRIFT_DIRS = ['protocols', 'consult-types', 'roles'] +auditProtocolDrift(workspaceRoot?): DriftFinding[] // 'identical' | 'differs' +hasFrameworkShadows(workspaceRoot?): boolean +``` + +`codev doctor` already calls `auditProtocolDrift` (`doctor.ts:947`) and reports +findings. The module is deliberately **report-only** — it never writes, because +a local copy *may* be a legitimate customization. + +**The real gap is therefore narrow and precise**: drift is already *detected and +reported*, but nothing **fails the build** on it. Our 17 drifted files have been +visible to `codev doctor` all along and were ignored. This spec's parity work is +"wire the existing audit into a CI gate," not "write a drift detector." + +### Duplication is worse than estimated + +Probing the `git add -A` prohibition: present in **18 logical locations** +(36 files counting the shadow mirror) — not 4–6 — in **9 distinct wordings**, +from a one-line hot-tier bullet to a multi-line `### 🚨 ABSOLUTE PROHIBITION 🚨` +block. Nine wordings of one rule is exactly the ambiguity cost the issue names. + +--- + +## Current State + +### Measured surface inventory + +`wc -w` on the working tree; reproducible via **T1**. + +| Surface | Words | Files | When it loads | +|---|---:|---:|---| +| `CLAUDE.md` | 5,773 | 1 | Every Claude Code session, automatically | +| `AGENTS.md` | 5,773 | 1 | Every session in other tools; byte-identical twin | +| `arch-critical.md` (HOT) | 416 | 1 | Inlined in CLAUDE.md **and** every porch phase prompt | +| `lessons-critical.md` (HOT) | 320 | 1 | Same | +| `arch.md` (COLD) | 20,240 | 1 | On demand | +| `lessons-learned.md` (COLD) | 21,270 | 1 | On demand | +| `codev-skeleton/**` | 77,956 | 113 | Resolver tier 4 | +| — `protocols/` | 44,784 | 63 | | +| — `resources/` | 7,191 | 9 | | +| — `templates/` | 6,123 | 11 | | +| — `porch/prompts/` | 4,009 | 10 | | +| — `roles/` | 3,813 | 3 | | +| `codev/protocols/` (**shadow**) | 47,511 | 66 | **Wins over skeleton** | +| `codev/roles/` (**shadow**) | 3,687 | 3 | **Wins over skeleton** | +| `.claude/skills/**` | 16,743 | 14 | On demand | +| Actual spawn prompt (this project) | 4,891 | — | Once per builder | +| Actual porch phase task (`porch next`) | 1,395 | — | Per phase iteration | + +Total authored instruction surface ≈ **150,000 words**. The number worth +optimizing is the *always-on* portion: + +**Always-on per builder** ≈ 5,773 (CLAUDE.md, hot tier inlined) + 4,891 (spawn) ++ 1,395 × *N* phase iterations ≈ **24,600 words** at *N* = 10, before any +project code is read. + +### Existing enforcement machinery + +Any solution extends these rather than duplicating them: + +| Suite | Tests | Guards | +|---|---:|---| +| `protocol-drift-audit` (#1210) | 18+ | **Shadow-copy drift detection; report-only via `codev doctor`** | +| `framework-ref-audit` (#1011) | 17 | Resolver-bypassing shell reads by literal path | +| `skeleton` | 18 | Four-tier resolution behaviour | +| `hot-tier` (Spec 987) | 9 | HOT-tier caps and cold-doc map accuracy | +| `protocol-prompt-audit` | 7 | Protocol prompt well-formedness | +| `skill-parity` | 5 | `.claude/skills` ↔ `.codex/skills` parity | +| `governance-sweep` | 3 | Governance doc invariants | + +### What is working (and is out of scope) + +Codev's progressive disclosure is genuinely good: HOT/COLD governance tiers +(Spec 987) are capped and policed, skills load on demand, `framework-ref-audit` +encodes "deliver content, don't fetch by path," and `protocol-drift-audit` +already sees the drift. The weakness is that detection is advisory and +duplication is unowned — not disclosure. + +--- + +## Desired State + +1. **Every instruction has exactly one owning surface**, recorded in a + machine-readable ownership map. Non-owning surfaces reference or summarize; + they never restate. +2. **Shadow drift cannot pass CI.** The existing `auditProtocolDrift` becomes a + build-failing gate, with an explicit adjudication allowlist. +3. **Scar rules stay verbatim and always-on** wherever they apply, in one + compressed canonical wording. Deduplication never applies to them. +4. **The win is measured** by a reproducible before/after script — in **words** + (M6) *and* in **agent behaviour** (M12). A word reduction that degrades + compliance is a loss, and the spec must be able to detect that. + +--- + +## Stakeholders + +| Stakeholder | Need | +|---|---| +| Builders (AI agents) | One unambiguous statement of each rule; no stale instructions | +| Architect (human) | Confidence that editing a rule takes effect everywhere | +| Codev adopters | Skeleton content matching what the Codev repo itself runs | +| Consultation models | Prompts small enough to leave budget for real review | + +--- + +## Success Criteria + +Restructured per Codex so the end state depends on no unanswered question. With +decisions **D1–D4** relayed (2026-07-27), every criterion below is now +unconditional: M8–M10 were promoted from conditional to required by **D2**, and +**M11** was added by the same decision. Nothing here awaits an architect answer. + +### Required — MUST + +- **M1 — Ownership map.** A machine-readable map at + `codev/resources/prompt-ownership.yaml`, with a human-readable companion at + `codev/resources/prompt-ownership.md` generated from or validated against it. + Schema in **Appendix A**. It enumerates every prompt surface and, for each + instruction class, the single owning surface. + + **Completeness rule** *(added iteration 2, per Codex)*. A map is not credible + merely because its entries are correct — it must also be provably exhaustive, + or under-listing satisfies M4 trivially. Therefore: + + - The map declares an explicit **inventory boundary**: the exact set of files + scanned for instruction candidates. Anything outside it is out of scope *by + declaration*, not by omission. + - A **candidate extraction** pass over that boundary mechanically collects + normative statements (imperative/prohibitive constructions — `MUST`, + `NEVER`, `ALWAYS`, `DO NOT`, `don't`, `Never`, and the like), each keyed by a + stable id. + - **Every candidate carries exactly one disposition**: `mapped` (has an + owner), `scar` (in M5's registry), or `out-of-scope` (**with written + justification**). + - **T12** fails on any candidate with no disposition. Consequence: new + normative text added anywhere inside the boundary fails CI until someone + dispositions it, so the map cannot silently rot as the prompt surface grows. + - Per Claude's iteration-2 note, the map **must** record why + `codev/resources/` is excluded from the drift regime (Q7) — this is required + M1 coverage, not a trailing nice-to-know. +- **M2 — Drift cannot pass CI.** A test invoking the existing + `auditProtocolDrift()` **fails the build** on any `differs` finding not listed + in an explicit, comment-justified allowlist. *This is the one required + outcome for the shadow tree* — iteration 1's "delete **or** enforce" ambiguity + is resolved in favour of enforce. + + **Allowlist lifecycle** *(added iteration 2, per Gemini)*. The allowlist is + the obvious way to re-hide drift, so its decay is enforced rather than merely + expected: every entry carries a line-item justification comment, and the test + asserts the allowlist is **empty once M3 completes** — the sole permitted + residue being files with an open M11 escalation, each of which must reference + its pending adjudication. An entry that outlives its escalation fails the + build. +- **M3 — Repair the live drift.** All 17 drifted shadow copies are reconciled + **per decision D1** (skeleton authoritative; file-by-file; anything resembling + deliberate local content escalated rather than overwritten), so M2's allowlist + starts empty. In particular the served SPIR builder prompt regains + `Multi-PR Mechanics`, `Verify Phase`, and the `"Entering verify phase."` + string. Files escalated under D1 step 4 may remain in the allowlist, with the + pending adjudication cited, until the architect rules. +- **M4 — Single-owner enforcement.** For every instruction class whose map entry + sets `enforcement: automated`, a test asserts the class's `pattern` matches on + exactly the declared owner. The test **derives assertions from the map file**; + it must not restate ownership in test code (which would itself violate the + single-owner rule). Definitions in **Appendix A**. +- **M5 — Scar-rule registry.** A machine-readable registry of the **eight** scar + rules ratified in **D3**, each with its **one compressed canonical wording** + (one sentence, two at most) and every surface it must appear on. A test asserts + verbatim presence on each. **Deleting or rewording a scar rule fails the + build.** M5's test must pass before any deduplication work begins. Rewriting + today's banner blocks down to the compressed form is part of this criterion, + and every surface must then carry the compressed wording byte-identically. +- **M6 — Measurement script.** A committed script reporting always-on word + counts per surface, runnable before and after to quantify the win. +- **M7 — Compatibility audit.** A repo-wide audit of literal `codev/protocols/` + and `codev/roles/` references, classifying each as resolver-routed (safe), + comment/error-string (safe), or direct-read (must fix). Promoted from Q5 to a + first-class deliverable per Codex. *Preliminary findings in* **Appendix B**. + +- **M12 — Behavioral-impact measurement** *(added by architect directive D5, + 2026-07-27)*. M6 counts words; nothing else in this spec observes whether the + trims **help or harm agent behaviour**. A word-count reduction is a proxy, and + validating only the proxy is not acceptance. M12 closes that gap. + + **(a) Baseline — captured before ANY prompt-content change.** A committed + measurement library, `packages/codev/src/lib/prompt-behavior-metrics.ts` (with + CLI runner `packages/codev/scripts/measure-prompt-behavior.ts`), mines + behavioural metrics from existing committed artifacts, with its output + committed as `codev/resources/1252-behavior-baseline.md`. *It lives beside + `protocol-drift-audit.ts` rather than in the root `scripts/` directory because + it needs that package's `js-yaml` dependency, which a root-level script cannot + resolve in this pnpm workspace.* Metric set and sample are + specified in **Appendix D**, which is grounded in what the repository actually + stores — several plausible-sounding metrics turned out not to be minable, and + saying so is part of the deliverable. + + **(b) Verify phase.** This project's SPIR verify phase re-runs the same script + over the next **N = 10** post-merge builder projects (**≥ 3 of them SPIR** — + see Appendix D for why the protocol mix matters), compares against the + baseline, and records an explicit **no-regression judgment**. A defined + **rollback trigger** (Appendix D §4) states what metric movement reverts + which commits. + + **(c) A/B eval — considered and deferred.** A controlled A/B (same task, old + vs new prompts, held-out grader) would isolate cause far better than + before/after observation, which cannot separate prompt effects from drift in + task difficulty, model version, or reviewer behaviour. It is deferred: it + needs a task corpus and grading harness that do not exist, and building them + is a larger project than this one. A follow-up issue is filed in Phase 8. + **This is a real weakness of M12, not a formality** — the observational design + supports "no evidence of harm," not "proved beneficial." + + **Confound to state plainly**: this project both **adds** served content + (M3 restores the missing `Verify Phase` and `Multi-PR Mechanics` sections) and + **removes** it (D3 compression, S1 dedup). The baseline is the **pre-project + state** and the verify comparison therefore evaluates the project's **total + effect**, not the trims in isolation. A null result could be two real effects + cancelling. Appendix D §4 mitigates this by attributing rollback to specific + commits rather than to the project as a whole. + +### Required — MUST (shadow-tree removal; activated by D2) + +- **M8 — Shadow-tree removal.** `codev/protocols/` and `codev/roles/` shadow + copies are deleted so the skeleton is the single owner, **preserving all + local-only entries**: `codev/protocols/release/` and + `codev/protocols/maintain/templates/{audit-report.md,lessons-learned.md}`. + **Gated on M11**: no file is deleted until its local-unique audit is complete + and any escalations are ruled on. +- **M9 — Vestigial scaffold cleanup.** `copyProtocols` and `copyRoles` are + removed from `scaffold.ts` along with their tests, so the shadow tree cannot + be reintroduced by rewiring dead code. +- **M10 — Post-deletion equivalence.** For every deleted shadow copy, the + resolver returns the skeleton counterpart and the assembled spawn prompt is + byte-identical to the skeleton-sourced expectation. +- **M11 — Local-unique content audit** *(added by D2)*. Before any file is + reconciled or deleted, produce a committed audit — one row per file across all + 76 shadow copies — classifying every local-vs-skeleton divergence as **rot** + (local lags; take skeleton) or **local-unique** (content absent from the + skeleton that plausibly encodes codev-specific functionality). + + Requirements: + - The audit covers **content inside drifted files**, not just whole files that + have no skeleton counterpart. A local-unique paragraph inside an otherwise-rotted + file is exactly the loss this criterion exists to prevent, and D1's + reconciliation would destroy it first. + - Every **local-unique** finding is escalated to the architect with the diff + hunk and a short read on what functionality it appears to provide. + - **Nothing classified local-unique is overwritten or deleted until the + architect rules on it.** Escalation blocks that file only; the rest proceed. + - Where classification is genuinely ambiguous, default to **local-unique** and + escalate. A needless question is cheap; a silently deleted codev-specific + behaviour is not. + + **Permitted terminal states** *(added iteration 2, per Codex)*. Every shadow + copy must end in exactly one of these four states. **"Pending escalation" is + explicitly NOT terminal** — the feature is not complete while any item sits + there. *(Count correction, Phase 2: the true shadow-copy count is **77**, not + 76 — mechanical enumeration includes `consult-types/integration-review.md`, + which the hand count missed. Every "76" in this spec reads as 77; the audit + artifact is authoritative.)* + + | # | Terminal state | Applies to | Result | + |---|---|---|---| + | **TS1** | Reconciled to skeleton, then deleted | `rot` | Skeleton is sole owner | + | **TS2** | Promoted — unique content moved *into* `codev-skeleton/`, local copy deleted | `local-unique` the architect wants kept **and** shared with adopters | Skeleton is sole owner; functionality preserved for everyone | + | **TS3** | Retained as a deliberate, documented local override | `local-unique` the architect wants kept **codev-only** | Stays in `codev/`, recorded in the ownership map *and* the M2 allowlist with justification | + | **TS4** | Dropped | `local-unique` the architect judges obsolete | Deleted, with the ruling recorded | + + **Completion rule**: the spec is complete when every shadow copy is in TS1–TS4 + and **zero escalations remain open**. TS2 is the preferred outcome for genuine + codev-specific functionality, since TS3 knowingly re-creates a (single, + documented, allowlisted) shadow copy and should be the exception. + + **Escape hatch — no indefinite block.** If an escalation cannot be resolved + (architect unavailable, decision genuinely deferred), it converts to **TS3** + and a follow-up issue is filed referencing the audit row. This keeps the + conservative outcome — nothing is lost — while guaranteeing the project always + reaches a defined end state rather than dangling on an unanswered question. + +### SHOULD + +- **S1** — Non-scar duplicated instruction classes reduced to their single owner + plus references. + +### Non-functional + +- **N1** — Reduction in always-on words per builder. **Target ≥ 20%** against + the measured baseline, without deleting any scar rule. A target for the plan to + interrogate, **not a gate**; the achieved figure is reported either way. + *Baseline note (Phase 1)*: the reproducible figure is **21,856** — derived + from resolved artifacts (CLAUDE.md + spawn-prompt proxy + 10× phase-task + proxy). The earlier ≈24,600 estimate additionally counted per-project + variable content (issue body, task-JSON boilerplate), which no trim can + affect; N1 is evaluated against the reproducible 21,856. + *Note*: M8 removes ~47k words from the repo but little from *always-on* + context, so N1 must come from **S1 deduplication plus D3's scar-wording + compression** — the latter now contributes directly, since collapsing banner + blocks to one-sentence rules shortens always-on text on every surface the + rules appear on, without reducing their reach. +- **N2** — No behavioural regression; full existing suite passes. +- **N3** — CLAUDE.md and AGENTS.md remain byte-identical. +- **N4** — Spec 987 HOT-tier caps respected. + +### Non-goals + +- Not rewriting protocol semantics — only relocating and deduplicating text. +- Not touching COLD `arch.md` / `lessons-learned.md` content. +- Not changing the resolver algorithm. +- Not making `protocol-drift-audit` auto-remediate; adjudication stays human. +- **Not running a controlled A/B eval** of old vs new prompts (M12c). Considered + and deferred — it needs a task corpus and grading harness that do not exist. + Filed as **issue #1277** (Phase 8). The consequence is that M12 can support + *"no evidence of harm,"* not *"proved beneficial."* +- **Not implementing multi-model fleet tiering** (the issue's proposed direction + #2). Cut by decision **D4** and deferred — filed as **issue #1276** + (Phase 8) now that the ownership map exists, the prerequisite that makes + tiering specifiable. + +--- + +## Constraints + +Issue #1252 contains no `Baked Decisions` section. Constraints derive from the +issue body and repository invariants. + +### From the issue + +- **C1** — Single-owner rule: exactly one owning surface per instruction. +- **C2** — Inventory and ownership map precede any restructuring. +- **C3** — **Scar rules are exempt.** They stay verbatim and always-on wherever + they apply. Deduplication never applies to them. +- ~~**C4** — Multi-model fleet tiering by consuming model capability.~~ + **Cut from this spec by architect decision D4** (2026-07-27) and deferred to + its own issue. This is the issue's proposed direction #2, deliberately + descoped — not dropped by oversight. See **Non-goals**. + +### From repository invariants + +- **C5** — CLAUDE.md and AGENTS.md MUST stay byte-identical. +- **C6** — Framework changes mirrored in both `codev/` and `codev-skeleton/`. + *If M8 proceeds, this invariant is retired for `protocols/` and `roles/` and + `arch-critical.md` must be updated to say so.* +- **C7** — Framework files are delivered via spawn prompt and porch JSON, never + fetched by literal `codev/...` path (`framework-ref-audit`). +- **C8** — HOT-tier files capped (≤10 facts, ≤12 map topics, ≤35 lines). +- **C9** — Never `git add -A` / `.` / `--all`. + +### Scar rules — ratified list (D3; eight rules) + +Ratified by the architect 2026-07-27. Canonical wordings must be **compressed** +to one sentence (two at most) per **D3**; the drafts below are indicative, and +the plan registers the final compressed text in M5's registry. + +1. Never `git add -A` / `.` / `--all` — stage files explicitly. +2. Never destroy builder worktrees (`git worktree remove`, `git branch -D`, + `afx cleanup` + respawn); use `--resume`, and ask when in doubt. +3. Never `git reset --hard` / `git checkout -- .` / `git clean -fd` / + `git stash` without explicit permission. +4. Never auto-approve porch gates; only humans approve. +5. Never hand-edit `status.yaml`. +6. Run `afx` only from the main workspace root. +7. **Never kill shellper processes without the verified-orphan procedure.** +8. **Never restart Tower without explicit human permission.** + +Rules 7–8 were added by D3; 1–6 carried over from the builder's proposed list. + +The 9 differing wordings of the `git add -A` rule are a **consistency** problem, +not a duplication problem. The fix is to converge on one compressed canonical +wording repeated verbatim — **not** to reduce the number of copies. + +--- + +## Architect Decisions + +Decisions relayed by the architect. These are **fixed** and are not to be +relitigated in the spec, plan, or review — treated with the same standing as a +`Baked Decisions` section. Remaining open items stay in **Open Questions**. + +### D1 — Drift reconciliation direction *(answers Q2; 2026-07-27)* + +**The skeleton is authoritative for all 17 drifted files.** Reconciliation is +file-by-file, not a bulk overwrite: + +1. Enumerate all 17 (the 16 protocol files named in the Problem Statement, plus + `codev/roles/architect.md`). +2. For each, diff local against skeleton and classify the divergence as + *missing content* (local lags the skeleton) or *possible deliberate local + content* (local adds or alters something the skeleton lacks). +3. *Missing content* → take the skeleton version. +4. *Possible deliberate local content* → **escalate to the architect; do not + silently overwrite.** Reconciliation of those files waits for a ruling. + +This governs **M3**. It does not decide Q1: reconciling the files and deleting +the tree are separate acts, and D1 applies whether or not deletion follows. + +### D2 — Shadow-tree deletion approved, with a local-unique safeguard *(answers Q1; 2026-07-27)* + +**Yes — delete the shadow copies.** M8, M9, and M10 are hereby **active and +required**, no longer conditional. + +One strengthening condition, in the architect's words: + +> *"mostly delete, but if there are any unique things can we discuss them to +> make sure we're not losing functionality specific to codev."* + +This adds **M11** (below). The safeguard is broader than the local-only file +list already in A2: it covers **local-unique content anywhere** in +`codev/protocols/` or `codev/roles/` — including content that lives *inside an +otherwise-drifted file*, which D1's reconciliation would otherwise overwrite +before deletion ever runs. + +The operative distinction is **local-unique functionality vs. rot**: + +| Classification | Meaning | Action | +|---|---|---| +| **Rot** | Local lags the skeleton; the difference is stale or missing content | Take the skeleton (D1) | +| **Local-unique** | Content present locally, absent from the skeleton, that plausibly encodes codev-specific functionality | **Escalate for human discussion before it is lost** | + +Escalation is **blocking for that file only** — reconciliation and deletion of +the remaining files proceed. Nothing classified local-unique is overwritten or +deleted until the architect rules on it. + +### D3 — Scar-rule registry ratified: eight rules, compressed *(answers Q3; 2026-07-27)* + +**All eight ratified** — the spec's original six plus two additions: + +7. Never kill shellper processes without the verified-orphan procedure. +8. Never restart Tower without explicit human permission. + +**Amendment: canonical wordings must be materially compressed** — one compact +sentence, two at most, per rule. Not today's multi-line banner blocks (e.g. +CLAUDE.md's `### 🚨 ABSOLUTE PROHIBITION: NEVER USE git add -A 🚨` block). + +Verbatim-replication (C3) and delete/reword CI protection (M5, T6) apply to the +**compressed canonical form**. Once a compressed wording is registered, it is +the wording — replicated byte-identically everywhere the rule appears, and +protected against silent deletion or rewording. + +Note the direction of travel: compression **reduces** always-on words while the +rules stay everywhere they were. Scar rules remain exempt from the single-owner +rule — this shortens them, it does not deduplicate them. + +### D5 — Behavioral-impact measurement required *(2026-07-27)* + +The issue's architect-guidance made impact measurement mandatory — *"a trim +proposal without a way to evaluate it is not accepted."* The spec as approved +satisfied this only with **M6 word counts and structural tests**, which measure +the proxy rather than the effect. That is a real gap and the spec did not close +it. + +Directive: add a required criterion covering **(a)** a baseline captured before +any prompt-content change, **(b)** a defined verify phase re-running the same +measurement post-merge with a no-regression judgment and rollback trigger, and +**(c)** a documented decision that a controlled A/B eval was considered and +deferred, with a follow-up pointer. + +Implemented as **M12** with **Appendix D**. Note that M3's drift repair itself +changes served prompts: the baseline is the **pre-project state**, and the verify +comparison evaluates the project's **total effect**. + +### D4 — Model-capability tiering cut *(answers Q4; 2026-07-27)* + +**Cut entirely from this spec.** Removed: S2, constraint C4, Appendix C, and the +`tier` field from the Appendix A schema. Tiering becomes its own future issue, +to be filed once the ownership map exists. Recorded in **Non-goals**. + +This descopes the issue's proposed direction #2. It is a deliberate architect +decision, not an oversight, and is flagged as such wherever C4 appeared. + +--- + +## Assumptions + +- **A1** *(corrected in iteration 2)* — The shadow tree is a **historical + artifact** of scaffolding that no longer runs, not a deliberate self-host + customization. *Evidence*: `copyProtocols`/`copyRoles` are uncalled; both trees + share a last-touch commit; 16 of 17 divergences are content *missing* relative + to the skeleton rather than local additions. Q1 still asks the architect to + confirm, but the required criteria no longer depend on the answer. +- **A2** — `codev/protocols/release/` and + `codev/protocols/maintain/templates/{audit-report.md,lessons-learned.md}` are + genuine local-only files and must survive. +- **A3** — Always-on words (≈ 24,600) is the figure worth reducing; on-demand + content is already correctly tiered. + +--- + +## Solution Approaches + +### Approach B — Promote the existing drift audit to a CI gate *(required)* + +Wire `auditProtocolDrift()` into a build-failing test with an adjudication +allowlist, and reconcile the 17 drifted files so the allowlist starts empty. + +- **Pros**: small — the detector already exists and is already wired into + `codev doctor`; closes the drift class immediately; independent of Q1. +- **Cons**: leaves 45,183 duplicated words and the double-edit burden; fixes + drift but not token cost or ambiguity. +- **Complexity**: low. **Risk**: low. + +### Approach A — Delete the shadow tree *(required; approved by D2)* + +Remove the shadow copies, preserving local-only entries, and delete the vestigial +scaffold functions. + +- **Pros**: eliminates 45,183 duplicate words and the whole drift class + structurally; makes Codev dogfood exactly what it ships; retires the + mirror-both-trees invariant that itself causes drift. +- **Cons**: highest blast radius; irreversible without git history; forfeits + self-host customization of protocols. +- **Complexity**: high. **Risk**: moderate — **lower than iteration 1 judged**. + Appendix B finds production consumers route through the resolver, and B's + parity gate proves equivalence before deletion. + +### Approach C — Ownership map + reference-based deduplication *(required)* + +Author the map, then reduce non-owning restatements to references, leaving scar +rules verbatim. + +- **Pros**: directly implements the issue's stated direction; addresses all + three costs; the map is durable documentation and drives M4's test. +- **Cons**: on its own does nothing about the shadow tree — deduplicating + *within* a doubled tree is wasted effort. +- **Complexity**: medium. **Risk**: medium (over-stripping a rule an agent + needed in place) — mitigated by M5, T6, and T13. + +### Sequencing: B → A → C *(all three now in scope per D2)* + +Order matters: + +1. **B first** — cheap, stops the bleeding, and is the safety net that makes + deletion auditable. Deleting is far safer once a gate can prove the trees + agree. +2. **M11 local-unique audit** — before any reconciliation touches a file. This + must precede **M3**, not follow it: D1 reconciliation overwrites local content + with the skeleton, so an unaudited local-unique paragraph would be destroyed + before deletion was ever reached. **M11 → M3 → M8** is the only safe order. +3. **M3 repair** — reconcile per D1, skipping anything M11 escalated. Required + for B's allowlist to start empty (escalated files excepted, with the pending + adjudication cited). +4. **A (M8–M10)** — the largest structural win, de-risked by B, Appendix B, and + M11. +5. **C last** — the durable fix, applied to a surface that is no longer doubled, + so the map describes one tree. + +M5's scar registry (with D3's compressed wordings) must be in place and passing +before **C** begins, since C is the step that could otherwise strip a scar rule. + +--- + +## Open Questions + +**All four critical/important questions were answered by the architect on +2026-07-27.** No open question now blocks or shapes the criteria. + +### Answered — see *Architect Decisions* + +- **Q1** — ***ANSWERED → D2.*** Delete the shadow copies; M8–M10 promoted to + required, plus new **M11** local-unique safeguard. +- **Q2** — ***ANSWERED → D1.*** Skeleton authoritative; file-by-file; escalate + anything resembling deliberate local content. +- **Q3** — ***ANSWERED → D3.*** Eight scar rules ratified; canonical wordings + compressed to one or two sentences. +- **Q4** — ***ANSWERED → D4.*** Tiering cut from this spec and deferred to its + own issue. + +### Nice-to-know + +- **Q5** — *Resolved and promoted to M7.* Preliminary audit in Appendix B. +- **Q6** — *Resolved.* The ownership map is machine-readable (Appendix A), per + Gemini's recommendation and to avoid M4's test restating ownership. +- **Q7** — *Resolved into M1, per Claude's iteration-2 note.* `codev/resources/` + shared files (`arch-critical.md`, `lessons-critical.md`, + `workflow-reference.md`, `spikes.md` — all currently differing from their + skeleton twins) stay **out** of the drift regime: they are user-evolved files + where divergence is legitimate. `FRAMEWORK_DRIFT_DIRS` already excludes + `resources`, so the default is correct. Recording *why* is now **required M1 + coverage** rather than a nice-to-know, and M2's allowlist must not + accidentally cover them. + +--- + +## Test Scenarios + +### T1 — Reproduce the surface inventory + +```bash +for f in CLAUDE.md AGENTS.md codev/resources/arch-critical.md \ + codev/resources/lessons-critical.md; do + printf "%-45s %6s\n" "$f" "$(wc -w < $f)" +done +find codev-skeleton -name "*.md" -exec wc -w {} + | tail -1 +find codev/protocols -name "*.md" -exec cat {} + | wc -w +``` + +### T2 — Reproduce the drift counts + +```bash +diff -rq codev/protocols codev-skeleton/protocols | grep -c '^Files' # 16 +diff -rq codev/roles codev-skeleton/roles | grep -c '^Files' # 1 +diff -rq codev/protocols codev-skeleton/protocols | grep '^Only in codev' # 3 local-only +``` + +### T3 — Reproduce the live builder-prompt drift + +```bash +diff codev/protocols/spir/builder-prompt.md \ + codev-skeleton/protocols/spir/builder-prompt.md +# skeleton has "Multi-PR Mechanics" and "## Verify Phase"; local does not +``` + +### T4 — Reproduce the duplication probe + +```bash +grep -rl "git add -A" CLAUDE.md AGENTS.md codev/resources codev/roles \ + codev/protocols codev-skeleton .claude/skills | wc -l # 36 +grep -rh "git add -A" codev/protocols codev-skeleton/protocols CLAUDE.md \ + | sed 's/^ *//' | sort -u | wc -l # 9 wordings +``` + +### T5 — Drift gate (M2) + +`auditProtocolDrift()` returns zero `differs` findings outside the allowlist; +a seeded divergence **fails** the test. Asserts the gate actually bites. + +### T6 — Scar-rule presence (M5, D3) + +All **eight** registry rules appear verbatim — in their **compressed canonical +form** — on every required surface. Mutation checks: deleting a scar rule fails; +rewording it fails. Rules 7 (shellper) and 8 (Tower restart) are covered +identically to the original six. + +### T7 — Single-owner (M4) + +For each `enforcement: automated` class, the pattern matches on exactly the +declared owner. Assertions derive from the map file, not from test literals. + +### T8 — Local-only preservation (M8; new, per Claude) + +After shadow-tree removal, `codev/protocols/release/` and +`codev/protocols/maintain/templates/{audit-report.md,lessons-learned.md}` still +exist and still resolve. + +### T9 — Post-deletion resolver equivalence (M10) + +For every deleted shadow copy, `resolveCodevFile` returns the skeleton +counterpart and content matches. + +### T10 — Regression (N2) + +Full suite green: `protocol-drift-audit`, `skeleton`, `hot-tier`, +`governance-sweep`, `protocol-prompt-audit`, `framework-ref-audit`, +`skill-parity`, `scaffold`. + +### T11 — Local-unique audit completeness (M11) + +*Automated.* The committed audit has **one row per shadow copy** (all 76), each +classified `rot` or `local-unique` and each resolved to a terminal state +TS1–TS4. Cross-checks: every file deleted under M8 appears in the audit with a +resolved classification; no file classified `local-unique` was deleted or +overwritten without a recorded architect ruling; **no row remains in "pending +escalation."** This test guards the *process*, not just the outcome — an +unaudited deletion must fail. + +### T12 — Ownership-map completeness (M1) + +*Automated.* Every candidate produced by the extraction pass over the declared +inventory boundary carries exactly one disposition (`mapped`, `scar`, or +`out-of-scope` with justification). Any undispositioned candidate fails. A +seeded normative line added inside the boundary must fail the test until +dispositioned — asserting the guard actually bites rather than passing +vacuously on an empty candidate set. + +### T14 — Behavioural baseline script (M12a) + +*Automated.* `scripts/measure-prompt-behavior.ts` runs clean and is +**deterministic over the committed-artifact metrics B1–B4** — the same commit +must yield the same B1–B4 numbers, or before/after comparison is meaningless. + +**B5 is explicitly excluded from the determinism assertion.** It derives from +`consult stats`, a rolling 30-day machine-local DB, so it is not reproducible +from a commit and never will be. Asserting determinism over B1–**B5** (as the +first draft of T14 did) was internally contradictory — caught by Codex at delta +review. B5 is reported as advisory context and drives no trigger. + +Also asserts: the SPIR sample resolves to the expected project count; B3 emits +matched excerpts alongside counts; and the script does **not** attempt +gate-rejection counts (Appendix D §2 — the data does not exist, and a +plausible-looking zero would be worse than an absent metric). + +### T13 — End-to-end, the real user path + +**Part (a), automated**: assemble the builder spawn prompt in-process and assert +it contains the verify-phase instructions and all eight scar rules in their +compressed canonical form. This is the regression guard and must be part of CI. + +**Part (b), manual, once — RESCHEDULED TO THE VERIFY PHASE** *(architect +ruling, 2026-07-28, on a discovered constraint)*: `afx spawn` has no branch +selector — every spawn branches from main HEAD, so a pre-merge probe would be +assembled from the PRE-change tree and would verify nothing about this branch; +the only pre-merge alternative (local-installing the branch build globally + +Tower restart) is disproportionate. **End-to-end verification of +resolver-tier changes is inherently post-deploy.** The pre-merge proxy is the +committed prompt-snapshot assertions (nine protocols, real +`buildPromptFromTemplate`, byte-compared). At verify — post-merge and +post-local-install — the architect runs a disposable `afx spawn --task` probe +from the main root and records the assembled prompt in the review. This is a +discovered constraint documented as such, not a skipped test. + +--- + +## Dependencies + +- **#1210 / `protocol-drift-audit`** — the foundation for M2; extended, not + reimplemented. +- **Spec 987** (hot/cold tiers) — caps must not be violated. +- **#1011 / `framework-ref-audit`** — the deliver-don't-fetch discipline. +- `packages/codev/src/lib/skeleton.ts` — resolver; read, not modified. +- `packages/codev/src/lib/scaffold.ts` — modified only under M9. + +--- + +## Risks and Mitigation + +| Risk | Impact | Mitigation | +|---|---|---| +| A scar rule silently dropped during deduplication | **Critical** — reintroduces a known data-loss incident | M5 registry + T6 mutation tests passing *before* any deduplication; eight rules ratified in D3 | +| **Codev-specific functionality lost when the shadow tree is deleted** | **Critical** — silent capability regression, and the loss is only visible later | **M11** audit precedes reconciliation *and* deletion; covers content *inside* drifted files; ambiguous cases default to escalate; T11 | +| Compressing a scar wording weakens the rule's force | High | D3 compression is reviewed at the gate; T6 protects the compressed form thereafter; meaning-preservation is a plan-phase review item | +| Deleting the shadow tree breaks a path-based reader | High | M7 audit precedes deletion; B's gate proves equivalence; T9 checks every deleted file | +| Over-stripping leaves an agent without a needed rule | High | Deduplicate only non-scar classes; T13 inspects the assembled prompt | +| Ownership map under-lists, making M4 pass vacuously | High | M1 completeness rule — declared inventory boundary + mandatory disposition; T12 fails on any undispositioned candidate | +| An M11 escalation stalls and the project dangles | Medium | "Pending" is not a terminal state; unresolved escalations convert to TS3 with a filed follow-up issue | +| **Trims degrade agent behaviour while every structural test stays green** | **Critical** — the failure M6 cannot see | M12 baseline + verify; B3 scar-violation mining; hard rollback trigger on a single incident | +| Baseline captured after content already changed, so there is no clean "before" | High | M12(a) completes in Phase 1, before any phase that alters served prompt content | +| Verify window closes with too little data and "no regression" is declared vacuously | Medium | Appendix D §4: < N=10 or < 3 SPIR ⇒ **inconclusive**, not success | +| Add-and-remove effects cancel, hiding a real regression | Medium | Rollback attributed to specific commits (Phases 5/7), not to the project as a whole | +| M3 reconciliation destroys local-unique content before deletion is reached | High | Sequencing is fixed **M11 → M3 → M8**; M3 skips anything M11 escalated | +| M2's allowlist accretes and re-hides drift | Medium | Allowlist entries require a justification comment; empty at M3 completion; growth is reviewable in diffs | +| Ownership restated in test code, re-creating duplication | Medium | M4 derives assertions from the map (Q6 resolved) | +| Local-only files lost during deletion | Medium | T8 explicitly guards all three | +| N1's 20% target missed | Low | N1 is a target, not a gate; report the achieved figure honestly | + +--- + +## Appendix A — Ownership map schema (M1, M4) + +An **instruction class** is a single normative rule an agent is expected to +follow, identified by a stable `id` and detectable by `pattern`. Prose that +merely *describes* the system is not an instruction class. + +```yaml +surfaces: + - id: claude-md + path: CLAUDE.md + load: always-on + +instructions: + - id: git-add-explicit + summary: Stage files explicitly; never `git add -A`. + owner: claude-md # exactly one surface id + scar: true # scar rules are exempt from single-owner + canonical_wording: | + Never `git add -A` / `.` / `--all` — stage files explicitly. + must_appear_on: [claude-md, agents-md, arch-critical, spir-prompts] + pattern: 'git add -A' + enforcement: automated # automated | manual + + - id: no-time-estimates + summary: Plans contain no time estimates. + owner: spir-protocol + scar: false + references: [spir-plan-prompt, aspir-plan-prompt] + pattern: 'time estimate' + enforcement: automated +``` + +- `enforcement: automated` — M4/T7 assert `pattern` matches on `owner` alone + (for `scar: false`) or on all `must_appear_on` (for `scar: true`). +- `enforcement: manual` — recorded in the map for humans; not machine-asserted. + Used where a rule is paraphrased legitimately and no reliable pattern exists. +- The plan must classify every instruction class it touches, and justify any + `manual` designation. + +## Appendix B — Preliminary compatibility audit (M7) + +Repo-wide search for literal `codev/protocols/` and `codev/roles/` references +in `packages/*/src`: **26 non-test, 95 in tests**. Classification of the +non-test hits: + +| Kind | Example | Deletion-safe? | +|---|---|---| +| Resolver-routed read | `consult/index.ts:175` → `readCodevFile(...)` | **Yes** — falls through to skeleton | +| Resolver-routed read | `porch/protocol.ts` → `resolveCodevFile` / `getSkeletonDir` | **Yes** | +| Error-message text | `porch/protocol.ts:28` "Searched in: …" | **Yes** — string only | +| Doc comment | `framework-ref-audit.ts:21`, `roles.ts:7` | **Yes** | +| Vestigial writer | `scaffold.ts:425,480` (`copyRoles`, `copyProtocols`) | **Yes** — uncalled; removed by M9 | + +No direct-read consumer was found. This is preliminary: the plan must complete +the audit across tests and any non-TypeScript consumers before M8 executes. + +## Appendix D — Behavioral metrics, sample, and rollback trigger (M12) + +Every claim here was verified against the repository before being proposed. The +directive listed candidate metrics; two of them are **not minable**, and +substituting something measurable is more useful than specifying something +aspirational. + +### 1. What the repository actually stores + +| Source | Volume | Usable for baseline? | +|---|---:|---| +| `codev/projects/*/status.yaml` — `history[].reviews[].verdict` | 17 projects | **Yes** — the only structured CMAP record | +| `codev/reviews/*.md` | 211 | **Yes** — prose; keyword-mined | +| `codev/state/*_thread.md` | 139 | **Yes** — prose; keyword-mined | +| Gate rejection counts | — | **No** — see §2 | +| `consult` token/cost stats | 30-day local DB | **Prospective only** — see §2 | + +`codev/projects/*/*.txt` (the raw consult logs) are **gitignored** +(`.gitignore:59`), so no historical consult output survives in the repo. This is +the single biggest constraint on the baseline. + +### 2. Candidate metrics that had to be dropped or re-scoped + +- **Gate rejection / re-request counts — NOT MINABLE.** Across all 201 projects, + gate `status` only ever takes the values `approved`, `complete`, `in_progress`, + `pending`. There is no `rejected` state, and `requested_at` is a single scalar + that a re-request overwrites rather than appends to. A rejected-then-approved + gate is indistinguishable from a first-time approval. *Recording this so the + metric is not silently dropped: it was requested, and it cannot be delivered + from committed history.* (A porch change to append gate events would make this + minable in future — noted as a possible follow-up, out of scope here.) +- **Tokens per phase — PROSPECTIVE ONLY.** `consult stats` reports invocations, + duration, and cost, but over a rolling 30-day window from a machine-local DB. + There is no Feb–Jun history to form a retrospective baseline. It is therefore + captured as a **forward baseline snapshot** at Phase 1 and compared in verify — + a weaker design than the others, and labelled as such. + +### 3. The metric set and sample + +**Sample for retrospective metrics (B1–B2): the 17 SPIR projects with non-empty +`history`**, spanning 2026-02 → 2026-06. Small, and stated as such. `history` is +populated for SPIR (per-plan-phase review loops) and empty for `pir`/`bugfix`/ +`air`, which is why the sample is protocol-skewed rather than 201-wide. + +| ID | Metric | Definition | Source | Sample | Baseline (measured 2026-07-27) | +|---|---|---|---|---|---| +| **B1** | CMAP `REQUEST_CHANGES` rate | share of all verdicts that are `REQUEST_CHANGES` | `history[].reviews[].verdict` | 17 SPIR | **51.9%** (n=160 verdicts; APPROVE 41.2%, COMMENT 6.9%) | +| **B2** | Review rounds per plan phase | `max(iteration)` per `plan_phase` | `history[].iteration` | 17 SPIR | mean **1.12**, median 1, max 2 (n=49 phases) | +| **B3** | Scar-violation incidents | keyword-mined mentions of the eight D3 rules being violated | 211 reviews + 139 threads | all | to be captured in Phase 1 | +| **B4** | Review rounds per project | sum of B2 across a project's phases | `status.yaml` | 18 with history | mean **3.06**, median 3 | +| **B5** | Consult cost/duration | forward snapshot only (§2) | `consult stats` | prospective | **non-deterministic — advisory only** | + +**B2 was redefined after the delta review.** It originally read "rounds to +unanimous approve," which is **not derivable**: across the 17-project baseline, +**0 of 48 terminal plan phases end with 3× `APPROVE`**. The commonest terminal +state is 2 × APPROVE + 1 × REQUEST_CHANGES (20/48), and 7/48 advance with three +REQUEST_CHANGES. Porch advances a phase after the builder rebuts, not on +consensus, so a "rounds to unanimity" counter would never resolve. Caught by +Codex and confirmed independently before the redefinition. + +**Consequences for how much weight each metric carries:** + +- **B1 is the load-bearing metric.** It has a real baseline (51.9%) and genuine + variance, so a relative rise is meaningful. The soft rollback trigger keys off + it. +- **B2 and B4 are advisory, not triggers.** B2's observed range is 1–2 with mean + 1.12 — almost no variance, so it cannot detect a subtle regression. Recording + this rather than implying more sensitivity than the data supports. +- **B3 is the metric that matters most** and is the fuzziest — it is the only one + that would catch a compressed scar rule losing its force, which is the specific + harm compression risks. Fuzzy by construction: prose keyword mining, with false + positives from documentation *about* a rule rather than a violation of it. The + script must report **matched excerpts, not just counts**, and a human + adjudicates before the hard trigger fires. +- **B5 is advisory and non-deterministic** — see §2. It is excluded from T14's + determinism assertion and from every rollback trigger. + +### 4. No-regression judgment and rollback trigger + +Rollback targets **the trims, never the repairs**. Phases 1–4 (drift gate, audit, +reconcile, shadow removal) *restore* correct content; reverting them would +reintroduce the drift bug this project exists to fix. Only Phases 5 and 7 removed +text, so only they are rollback candidates. + +| Trigger | Threshold | Action | +|---|---|---| +| **Hard — scar violation** | **Any single** B3 incident in the verify window attributable to a missing or weakened rule | Revert the **Phase 5** compression commit (and Phase 7 if the rule was a dedup target). n=1 suffices; scar rules exist because the incident already happened once. | +| **Soft — review friction** | B1 `REQUEST_CHANGES` rate rises **> 25% relative** to the measured 51.9% baseline — i.e. **above ~64.9%** — sustained across the N sample | Revert **Phase 7** dedup commits; keep Phases 1–6. Re-measure before any further trimming. | +| **Advisory** | B2/B4/B5 movement without B1/B3 movement | No revert. Record and investigate — B2's observed range (1–2) is too narrow to carry a trigger, and B5 is non-deterministic. | +| **Inconclusive** | Fewer than N=10 projects, or < 3 SPIR, complete in the window | **Do not declare success.** Extend the window or record the verify as inconclusive. Absence of data is not a no-regression result. | + +The last row matters: with n=17 baseline and N=10 verify, this design detects a +large regression, not a subtle one. The honest claim available at the end is +**"no evidence of behavioural harm at this sample size"** — not "the trims were +beneficial." Anything stronger requires the deferred A/B. + +--- + +## Appendix C — *(removed)* + +Model-capability tiering was cut from this spec by decision **D4** and deferred +to its own issue. Codex's iteration-1 point C-5 (tiering was underspecified) is +resolved by descoping rather than by specification. + +--- + +## Expert Consultation + +### Iteration 1 — 3-way review + +| Model | Verdict | +|---|---| +| Gemini | **APPROVE** — "comprehensive, empirical, well-structured"; no key issues | +| Codex | **REQUEST_CHANGES** — 5 issues, all accepted | +| Claude | **COMMENT** — 4 issues, all accepted | + +**Codex — accepted in full:** + +1. *Critical questions gate the end state.* → Success Criteria restructured: + M1–M7 required and Q1-independent; M8–M10 conditional on Q1. *(Superseded by + D2: Q1 answered yes, so M8–M10 are now required. Codex's structural point + still stands — the spec was made answer-independent first, which is why the + decisions could be absorbed cleanly.)* +2. *M2 allowed two incompatible outcomes.* → M2 is now solely "drift cannot pass + CI." Deletion moved to M8. +3. *M4 under-specified.* → Appendix A defines instruction class, schema, and + `automated`/`manual` enforcement. +4. *Approach A feasibility unbounded.* → Q5 promoted to M7 with Appendix B's + preliminary audit; deletion is conditional and gated behind the parity gate. +5. *Tiering too vague.* → Appendix C fixed selector, fallback, and scope. + *(Superseded by D4: tiering cut from the spec entirely and deferred to its own + issue. Codex's objection is resolved by descoping rather than specification — + the cleaner outcome, since it was the least-grounded part of the spec.)* + +**Claude — accepted in full:** + +6. *`protocol-drift-audit` (#1210) unmentioned.* → **The most valuable finding.** + Iteration 1's "no test asserts…" was misleading and is corrected; the module + is now a named dependency and M2 extends it rather than reinventing it. + Verified: `auditProtocolDrift`, `FRAMEWORK_DRIFT_DIRS`, `doctor.ts:947`. +7. *"19 drifted" is wrong.* → Confirmed **17** (16 protocols + 1 roles). The 19 + conflated drifted files with local-only entries; the spec now separates them. +8. *Local-only `maintain/templates/` files unhandled.* → Named in A2, M8, and + guarded by new test T8. +9. *"63 markdown files" ambiguous.* → Now stated as 63 `.md` / 73 `md+json` for + `protocols/`, 76 shadow copies including `roles/`. Also: "shadow tree" is + now defined once in **Terminology**. + +**Gemini — accepted:** machine-readable ownership map (Appendix A, Q6 resolved); +grep audit before deletion (M7, Appendix B). + +**Builder-originated corrections** found while verifying Codex's issue 4: +`copyProtocols`/`copyRoles` are vestigial, so adopters have no shadow tree and +ours is a historical artifact (A1 corrected; M9 added). + +### Iteration 2 + +Porch advanced directly to the `spec-approval` gate after the iteration-1 +rebuttal. The architect directed (2026-07-27) that a second 3-way review be run +against the revised spec before the gate decision, so that the restructured +success criteria (M1–M7 required / M8–M10 conditional) and the three new +appendices get reviewer re-validation rather than shipping reviewer-informed +but unvalidated. + +Held until the architect's complete decision set landed (2026-07-27), so that a +**single** review runs against the fully-amended spec rather than one that +changes underneath the reviewers. + +Amendment state at review time: **D1–D4 all recorded.** The revised spec differs +from iteration 1 in five material ways, and reviewers were asked to focus there: + +1. Success criteria restructured — M1–M7 required and question-independent. +2. M8–M10 promoted from conditional to required (**D2**), plus new **M11** + local-unique content audit with fixed **M11 → M3 → M8** sequencing. +3. Scar registry ratified at **eight** rules with **compressed** canonical + wordings (**D3**). +4. Tiering **cut** — S2, C4, Appendix C, and the schema's `tier` field removed + (**D4**). +5. New Appendices A and B; Appendix C removed. + +**Verdicts:** + +| Model | Verdict | Confidence | Issues | +|---|---|---|---| +| Gemini | **APPROVE** | HIGH | None (1 non-blocking suggestion) | +| Codex | **REQUEST_CHANGES** | HIGH | 2 | +| Claude | **APPROVE** | HIGH | None blocking (3 minor) | + +All six points accepted; none disputed. Changes made: + +1. **Codex — ownership-map completeness not testably defined.** The sharpest + catch of the round: M4 only validated entries *already in* the map, so a map + listing 3 of 40 rules would have passed every test. → M1 gains a + **completeness rule** (declared inventory boundary + mechanical candidate + extraction + mandatory `mapped`/`scar`/`out-of-scope` disposition) and + **T12**, which fails on any undispositioned candidate and is itself checked + against a seeded line so it cannot pass vacuously. +2. **Codex — terminal state for escalated `local-unique` files unspecified.** + → M11 gains four explicit terminal states (**TS1–TS4**), declares "pending + escalation" **non-terminal**, sets the completion rule (all 76 in TS1–TS4, + zero open escalations), and adds an escape hatch so an unresolved + architect question converts to TS3 + follow-up issue rather than blocking + indefinitely. +3. **Gemini — allowlist lifecycle.** → M2 now *enforces* decay: line-item + justifications, empty after M3, sole residue being open M11 escalations that + must cite their adjudication. +4. **Claude — T11/T12 ordering non-sequential.** → Tests renumbered; all + cross-references in the risk table and Approach C corrected. +5. **Claude — T11 automated-vs-manual unclear.** → Now **T13**, split into an + automated CI part (a) and a one-time manual spawn (b), with the reasoning + stated: part (a) can pass while the real spawn path diverges, which is + exactly the failure that produced this project. +6. **Claude — Q7 should be required M1 coverage.** → Q7 resolved into M1; + recording why `codev/resources/` is excluded is now mandatory. + +Two risk rows added (vacuous-map, stalled-escalation). + +Rebuttal: `codev/projects/1252-prompt-architecture-single-own/1252-specify-iter1-rebuttals.md` + +--- + +## Approval + +- [ ] Architect approval (gate: `spec-approval`) +- [x] 3-way consultation, iteration 1 (Gemini APPROVE / Codex REQUEST_CHANGES / Claude COMMENT — all 9 issues accepted) +- [x] Architect decisions D1–D4 relayed and absorbed (2026-07-27) +- [x] 3-way consultation, iteration 2 (Gemini APPROVE / Codex REQUEST_CHANGES / Claude APPROVE — all 6 points accepted) + +--- + +## Notes + +The strongest argument for this work is not the token count. It is that the +project filed to fix prompt drift was itself spawned with a drifted prompt, +missing its own verify-phase instructions — and that a detector for exactly this +condition (#1210) had been shipping the finding to `codev doctor` the whole time, +unread. The gap is not detection. It is that nothing was allowed to fail. diff --git a/codev/state/spir-1252_thread.md b/codev/state/spir-1252_thread.md new file mode 100644 index 000000000..59f2f1017 --- /dev/null +++ b/codev/state/spir-1252_thread.md @@ -0,0 +1,826 @@ +# spir-1252 — Prompt architecture: single-owner rule + +## Specify phase — measurement first + +Before drafting, I measured the actual prompt surface rather than trusting the +issue's "~45k words / 4–6 duplicates" estimate. Two findings changed the shape +of the spec. + +### Finding 1: the real duplication axis is the `codev/` ↔ `codev-skeleton/` shadow tree + +The issue lists CLAUDE.md/AGENTS.md, hot-tier docs, protocols, phase prompts, +roles, skills. It never mentions the largest one: **63 markdown files +(45,183 words) exist in BOTH `codev/protocols/` and `codev-skeleton/protocols/`**, +plus `codev/roles/` ↔ `codev-skeleton/roles/`. + +This is not benign. Tier 2 (`codev/`) *wins* over tier 4 (skeleton) in the +four-tier resolver, so our self-hosted instance runs on the local copies — +and **19 of them have drifted** from the skeleton. + +### Finding 2: the drift is live and it bit this very builder + +`codev/protocols/spir/builder-prompt.md` (636 words, served) is missing the +entire **"Multi-PR Mechanics"** and **"## Verify Phase"** sections that +`codev-skeleton/protocols/spir/builder-prompt.md` (824 words, shipped) has. + +My own spawn prompt has no verify-phase instructions. Adopters get them; we +don't. That is the drift failure mode, demonstrated, not hypothesized. + +`codev/protocols/spir/protocol.md` differs from the skeleton by 138 diff lines. +Last touched by the same merge commit (d49f5f47, 2026-06-13) — they were forked +and left to rot. + +### Finding 3: duplication count is worse than the issue estimated + +The `git add -A` prohibition appears in **18 logical locations** (36 files +counting the shadow mirror), in **9 distinct wordings** — from +"Never `git add -A` / `.` / `--all` — stage files explicitly" to a full +"🚨 ABSOLUTE PROHIBITION 🚨" block. Not 4–6; and the wording variance is the +ambiguity cost the issue predicts. + +### Measured surface (words) + +| Surface | Words | Files | Load | +|---|---|---|---| +| CLAUDE.md | 5,773 | 1 | every session, auto | +| AGENTS.md | 5,773 | 1 | byte-identical twin | +| arch-critical + lessons-critical (HOT) | 736 | 2 | in CLAUDE.md *and* every phase prompt | +| arch.md + lessons-learned.md (COLD) | 41,510 | 2 | on demand | +| codev-skeleton (all) | 77,956 | 113 | resolver-dependent | +| codev/protocols (shadow) | 47,511 | 66 | wins over skeleton | +| .claude/skills | 16,743 | 14 | on demand | +| my actual spawn prompt | 4,891 | — | once per builder | +| my actual porch phase task | 1,395 | — | per phase iteration | + +### Consequence for the spec + +The issue framed this as a compression problem ("token cost"). The measurement +says the *drift* problem is bigger and more urgent than the token problem, and +that the shadow tree is where both concentrate. I am specifying accordingly: +ownership map + shadow-tree elimination first, compression second. Deduplication +of scar rules stays off the table per the issue. + +Existing enforcement machinery to build on (not reinvent): `governance-sweep`, +`hot-tier`, `skeleton`, `protocol-prompt-audit`, `framework-ref-audit`, +`skill-parity` test suites. + +## Specify iter-1 — 3-way consultation + +Gemini APPROVE / Codex REQUEST_CHANGES / Claude COMMENT. Codex and Claude each +found real problems. I accepted all nine issues; two of them corrected factual +errors of mine. + +### The one that mattered most (Claude) + +I claimed "no test asserts that codev/protocols/ matches +codev-skeleton/protocols/." **That was wrong.** +`packages/codev/src/lib/protocol-drift-audit.ts` (#1210) already exists — +`auditProtocolDrift()`, `FRAMEWORK_DRIFT_DIRS = ['protocols','consult-types', +'roles']`, classifying `identical | differs` — and `codev doctor` already calls +it at `doctor.ts:947`. + +So drift has been *detected and reported all along*. Our 17 drifted files were +visible to `codev doctor` and ignored. The gap is not detection; it is that +nothing **fails the build**. That narrows M2 enormously: wire the existing +audit into a CI gate, don't write a detector. + +### Count corrections (Claude) + +My "19 drifted" conflated drifted files with local-only ones. Actual: **17** +(16 protocols + 1 roles). Separately there are **3 local-only** entries — +`release/` and two `maintain/templates/` files — which must survive deletion. +Added test T8 for that. Clarified 63 `.md` / 73 `md+json` / 76 including roles. + +### Structural fixes (Codex) + +Codex was right that the spec's end state depended on unanswered critical +questions, and that M2 permitted two incompatible outcomes. Restructured: +M1–M7 are required and Q1-independent; M8–M10 (deletion) are conditional on +architect approval. Added Appendix A (ownership-map schema + what an +"instruction class" is), Appendix B (compatibility audit), Appendix C (tiering +selector/fallback/scope). + +### What I found while verifying Codex's feasibility concern + +Codex claimed many literal `codev/protocols/` references exist. True — 26 +non-test, 95 in tests. But checking them changed the picture twice: + +1. **`scaffold.ts` exports `copyProtocols`/`copyRoles`** which copy the skeleton + into `codev/`. I briefly thought this meant every adopter has a shadow tree. + Then I grepped for callers: **neither is called by init, adopt, or update.** + They are dead code. So adopters have NO shadow tree — ours is a historical + artifact from when scaffolding did copy. That *strengthens* the deletion + case (deleting makes us match adopters) and adds M9: remove the dead + functions before someone rewires them. +2. **Production consumers route through the resolver** (`consult/index.ts:175` + → `readCodevFile`; `porch/protocol.ts` → `resolveCodevFile`). The rest are + comments and error strings. No direct-read consumer found — deletion is + lower-risk than iter-1 judged. + +A1 rewritten accordingly: iter-1 asserted "unintentional fork" without +establishing why; now it is evidence-backed. + +### Still architect-owned + +Q1 (may the shadow trees be deleted) and Q3 (is the scar list complete) are not +mine to answer. The spec no longer *depends* on Q1 — a "no" simply drops +M8–M10 and still ships B + C. + +## Held at spec-approval gate — awaiting full architect decision set + +Architect directed an iter-2 review, then countermanded ~40s later: amend the +spec with the *complete* decision set first, then run a **single** iter-2 +review against the fully-amended spec. Sensible — reviewing a spec that shifts +underneath the reviewers wastes a round. + +State when the countermand landed: I had made the Q2 amendment but had **not** +launched any consult. Nothing to abort. + +**D1 recorded (answers Q2)**: skeleton is authoritative for all 17 drifted +files, reconciled file-by-file — classify each divergence as *missing content* +(take skeleton) or *possible deliberate local content* (**escalate, never +silently overwrite**). Governs M3. Explicitly does NOT decide Q1: reconciling +the files and deleting the tree are separate acts, and D1 holds either way. + +**Frozen pending answers**: Q1 (shadow-tree deletion → M8–M10) and Q3 (scar +registry contents → M5) and Q4 (tiering selector). Added a "Pending — do not +act" clause under Architect Decisions so the constraint is legible to anyone +reading the spec, not just to me. + +Making no further spec edits until the full decision set arrives. + +## Specify iter-2 — decisions D1–D4 absorbed, second 3-way review + +Architect relayed the full decision set: D1 skeleton-authoritative, D2 delete +approved (+ local-unique safeguard), D3 eight scar rules compressed, D4 tiering +cut. Amended spec (442cc08a), then ran iter-2. + +**Verdicts: Gemini APPROVE / Codex REQUEST_CHANGES / Claude APPROVE.** +6 points, all accepted. Iter-1 drew 9 issues; iter-2 drew 6, only 2 blocking — +and both were "your enforcement has a hole," not "your analysis is wrong." +Codex and Claude each independently re-verified the empirical basis; it held. + +### The hole worth remembering (Codex CX-1) + +M4/T7 iterate over the ownership map's entries and check each has one owner. +**A map listing 3 of 40 instruction classes passes cleanly.** Tests green, +artifact looks rigorous, single-owner rule covers a fraction of the surface, +nothing signals the gap. + +I built the exact disease this spec attacks — enforcement that measures only +what you already told it about — into the fix for it. Fixed with a declared +inventory boundary + mechanical candidate extraction + mandatory +mapped/scar/out-of-scope disposition + T12 failing on anything undispositioned. + +Added unprompted: T12 must be validated against a *seeded* normative line. A +completeness test over an empty candidate set passes vacuously and looks +identical to a healthy one. Having just been caught by one vacuous-pass hole, +leaving another in would be careless. + +### CX-2 — escalation is a transition, not a destination + +M11 said "escalate to the architect" and stopped. No terminal state, so the +criterion couldn't be judged complete or incomplete. Added TS1–TS4, made +"pending escalation" explicitly non-terminal, completion = all 76 in TS1–TS4 +with zero open escalations. + +Judgement call flagged to the architect: unresolved escalation converts to TS3 +(keep local, documented, allowlisted) + follow-up issue, rather than +hard-blocking. Trades a little residual shadow tree for a guarantee the project +can't stall on an unanswered question. Also marked TS2 (promote into skeleton) +as *preferred* over TS3 — TS3 knowingly re-creates a shadow copy, and if it +became the default the spec would quietly rebuild what it removed. + +### Smaller but real (Claude CL-2) + +Split T13 into automated CI assembly-check (a) + one manual real spawn (b). +Keeping (b) matters: (a) can pass while the live spawn path reads different +files — which is *exactly* how this project's own prompt lost its Verify Phase +section. An ambiguous "inspect the prompt" would have collapsed into (a) alone. + +Gemini independently endorsed the M11 → M3 → M8 sequencing and the M5-before-C +scar chain — both builder-originated, so worth recording that they survived +outside review. + +No open questions remain. Back to the spec-approval gate. + +## Plan phase — 8 phases drafted + +Spec approved (human approval relayed via architect; I ran `porch approve` per +the workspace convention that the builder executes it, architect never does). + +**One ordering decision beyond what the spec fixed.** The spec pins +`M11 → M3 → M8` and "M5 green before Approach C," but says nothing about where +scar compression sits relative to deletion. Compressing eight rules across ~36 +files when half get deleted two phases later is wasted work — and worse, risks +reconciling a compression edit against a skeleton that never got it. So +**Phase 5 (scar compression) runs AFTER Phase 4 (deletion)**, still well before +Phase 7 (dedup). Satisfies the real constraint; avoids the trap. + +Phases: 1 drift gate + baseline · 2 local-unique audit · 3 reconcile · +4 compat audit + removal · 5 scar registry · 6 ownership map · 7 dedup + +measure · 8 governance sync + E2E. + +Four of eight phases land before a single duplicated word is removed. That's +deliberate — the spec's finding is that drift, not token count, is urgent, and +D2 requires nothing codev-specific be lost. + +Notes to self for implementation: +- Phase 1's allowlist starts POPULATED with the 17 drifts (justified "pending + Phase 3"). A gate that fails on commit is a gate someone disables. +- Phase 5's real risk is meaning loss, not brevity. Each compressed wording must + retain prohibition + scope + any escape hatch (rule 2's "use --resume, and ask + when in doubt"). Dropping the escape hatch turns guidance into a dead end. +- Phase 7: report the N1 figure honestly even if under 20%. Likely shortfall is + structural — most always-on words are CLAUDE.md prose that's already + single-owned, not duplicated rules. Do NOT strip content to hit a number. +- Phase 8 must file the D4 tiering follow-up issue. + +## Plan iter-1 — 3-way review + +**Gemini APPROVE / Codex REQUEST_CHANGES / Claude APPROVE.** 6 points, all +accepted. None changed phase structure, ordering, or scope — all six were +"specify this existing phase more precisely." + +### Codex CX-1: I implemented half of my own criterion + +M10 says resolver equivalence AND byte-identical assembled prompt. Phase 4 +planned only the former — and the gap was *disguised*, because Phase 8's T13 +looks like it covers assembled prompts. A reader would reasonably conclude M10 +was satisfied across two phases when neither asserted byte-identity. + +Why it matters: per-file resolution can be correct while assembly still differs +(template ordering, {{project_id}} interpolation, a fragment from a different +tier). Phase 4's entire claim is "deletion is a no-op for what agents receive" — +only byte-identity shows that. Fixed: snapshot each protocol's prompt +pre-deletion, assert byte-identical after. + +Also wrote down that 4d(ii) and T13 have *opposite* expectations — 4d(ii) says +nothing changed; T13 says the right content is present after compression/dedup +deliberately changed things. Easy for a later reader to collapse them. + +### Codex CX-3: the drift disease, in miniature, in my own plan + +I wrote "remove copyProtocols/copyRoles plus their scaffold.test.ts cases." +But only copyRoles has tests — and **I had established that myself** during the +spec phase and written it in the iter-1 spec rebuttal. Verified once, +paraphrased from memory later, drifted in the restatement. + +That's exactly what this project is about. Worth remembering: my errors don't +cluster in analysis, they cluster in *restating things I already verified*. + +### Claude CL-1: better than "minor" + +T11 parses the Phase 2 audit doc, but I described the doc loosely. A builder +writing free-form prose would make T11 unimplementable — and the natural fix +under pressure is to weaken T11, which would quietly remove the guarantee that +nothing was deleted unaudited. That's the most important safeguard in the plan. +Now specified as a fixed 5-column table with enumerated values. + +### CX-2: phase boundary contradiction + +Phase 5 said "replace on every surface"; Phase 8 said "apply Phase 5's wordings +to CLAUDE.md/AGENTS.md." Two readings, one dangerous: Phase 5 skips the two +most-read surfaces and still claims M5 green — leaving a hole exactly where the +most-read scar rules live, right before Phase 7 starts stripping text. Phase 5 +now owns all scar edits; Phase 8 only parity-checks N3. + +Gemini again endorsed the Phase 5-after-Phase 4 placement (my discretionary +call) and the M11 → M3 → M8 ordering. + +## Amendment D5 — behavioural-impact measurement (M12) + +Architect surfaced a real gap I'd missed: the issue's guidance made impact +measurement mandatory ("a trim proposal without a way to evaluate it is not +accepted"), and my M6 word-counts + structural tests measure the PROXY, not the +effect. My safeguards were asymmetric — M5/T6 protect against a scar rule being +deleted or reworded; nothing detected "rule still present, compliance dropped." + +### Research first — two requested metrics turned out unminable + +Before proposing anything I checked what the repo actually stores. Worth +recording because the answer shaped the whole design: + +- `codev/projects/*/*.txt` (raw consult logs) are **GITIGNORED** (.gitignore:59). + No historical consult output survives. Biggest constraint. +- **Gate rejection counts: NOT MINABLE.** Across all 201 projects gate `status` + only ever takes approved|complete|in_progress|pending — there is no `rejected` + state, and `requested_at` is a scalar that a re-request overwrites. A + rejected-then-approved gate is indistinguishable from a clean one. Said so in + Appendix D §2 rather than quietly dropping it. +- **Tokens/phase: PROSPECTIVE ONLY.** `consult stats` is a rolling 30-day local + DB (3239 invocations, $1426). No Feb–Jun history → forward snapshot only. +- What IS minable: `history[].reviews[].verdict` — but only **17 SPIR projects** + have non-empty history (populated for SPIR's per-plan-phase loops, empty for + pir/bugfix/air). Plus 211 reviews + 139 threads for keyword mining. + +So: B1 REQUEST_CHANGES rate, B2 rounds-to-approve, B3 scar-violation mining, +B4 phase iterations, B5 forward cost snapshot. Sample n=17. N=10 verify window +with ≥3 SPIR (the SPIR minimum is the binding constraint, not the total). + +### Things I made sure to state rather than paper over + +- **The add/remove confound**: this project both restores content (M3) and + removes it (D3 compression, S1 dedup). A null result could be two real effects + cancelling. Mitigated by attributing rollback to specific commits, not the + project as a whole. +- **Rollback targets trims, never repairs.** Phases 1–4 restore correct content; + reverting them reintroduces the drift bug. Only Phases 5 and 7 are candidates. +- **Inconclusive is a real outcome.** <10 projects or <3 SPIR ⇒ do NOT declare + success. Absence of data is not a no-regression result. +- **B3 is the metric that matters most** and is the fuzziest — it's the one that + would catch a compressed scar rule losing force. Script must emit excerpts, + not just counts, so a human adjudicates. +- Honest ceiling: n=17 vs N=10 detects a LARGE regression. The strongest claim + available is "no evidence of harm at this sample size," not "proved + beneficial." That's why M12c defers a real A/B — and I flagged the deferral as + a genuine weakness, not a formality. + +Baseline must land in Phase 1 (step 1b) — Phases 3/5/7 all alter served content, +so any later capture has no clean "before." + +## D5 delta review — Gemini APPROVE / Codex REQUEST_CHANGES / Claude APPROVE + +Codex found two real defects. Gemini and Claude both approved. **The majority +was not the signal.** + +The split is instructive: Gemini and Claude verified the *data-availability* +claims (correct — all three confirmed gate-rejections unminable, consult +prospective-only, 17 SPIR sample). Codex went further and checked whether the +*metric definitions actually resolve against that data*. That's where both +defects were. + +### CX-1: B2 was unmeasurable and would have failed silently + +"Rounds to unanimous approve" — but **0 of 48 terminal plan phases end with +3× APPROVE**. I re-derived it rather than trusting the claim: + + 20 (APPROVE, APPROVE, REQUEST_CHANGES) + 12 (APPROVE, REQUEST_CHANGES, REQUEST_CHANGES) + 7 (REQUEST_CHANGES × 3) + +**Porch advances a phase on builder rebuttal, not consensus.** So B2 would never +resolve — and would have looked fine: script runs, emits a number, number is +meaningless. + +The lesson worth keeping: "the data exists" ≠ "the metric resolves." I verified +the former meticulously (all 3 reviewers confirmed Appendix D §1–2) and never +checked the latter for my own definition. + +Redefined B2 = max(iteration) per plan_phase. Then computed real baselines: +**B1 = 51.9% REQUEST_CHANGES** (n=160), B2 mean 1.12 (n=49), B4 mean 3.06. + +That surfaced something else: **B2's range is 1–2, mean 1.12 — nearly no +variance**, so it can't detect a subtle regression. Demoted B2/B4 to advisory, +named B1 load-bearing, made the soft threshold concrete (>25% on 51.9% = above +~64.9%). + +### CX-2: T14 contradicted itself + +T14 demanded "same commit ⇒ same B1–B5" while B5 comes from a rolling 30-day +machine-local DB. Both halves written by me in the same amendment. Scoped +determinism to B1–B4; B5 now explicitly advisory/non-deterministic, drives no +trigger. Kept rather than dropped — cost/duration is useful context for +interpreting a B1 move; the failure was pretending it was reproducible. + +### Also worth recording + +Gemini endorsed the n=1 hard trigger on B3, reasoning scar rules exist BECAUSE +the catastrophe already happened once — so one verified recurrence justifies +reverting compression. Good framing; a single-incident trigger looks aggressive +without it. + +Process note: my first 3 delta consults failed — `--prompt` and `--type` are +mutually exclusive. Should have checked the consult skill first. Re-ran in +general mode with a scoped brief file. No artifacts affected. + +## Phase 1 COMPLETE — drift gate + both baselines + +Plan approved (human, relayed). Phase 1 delivers M2, M6, M12a. + +**Drift gate** (`shadow-drift-gate.test.ts`): calls the existing +`auditProtocolDrift()` — did NOT reimplement detection. 4 tests + 1 skipped +(Phase-3 lifecycle guard, flips on in Phase 3). + +Allowlist seeded with exactly the 17 drifted files, each justified +`PENDING_RECONCILE → Phase 3 (D1)`. Two guards make it self-limiting: every +entry needs a non-empty note, and a *stale-entry* test fails if an allowlisted +file stops drifting. So the allowlist can't outlive its purpose. + +The BITES test matters most: seeds a real divergence in a temp workspace and +requires detection. A gate that has only seen a clean tree is indistinguishable +from a no-op — which is precisely how #1210 sat unread for months. + +**Word baseline**: ALWAYS_ON = **24,614** (CLAUDE.md 5,773 + spawn 4,891 + +1,395×10 phase tasks). Matches the spec's ~24,600 estimate. Deliberately +excludes AGENTS.md (byte-identical twin — one loads per session, not both) and +the hot-tier files (already inlined in CLAUDE.md's count). Double-counting +either would inflate the baseline and flatter the Phase 7 result. + +**Behavioural baseline** (M12a): B1 **51.88%** REQUEST_CHANGES (n=160 verdicts), +B2 mean 1.12 (n=49 phases), B4 mean 3.06 (n=18 projects). Reproduces the figures +published in spec Appendix D. + +B3: 45 candidate hits across 350 files — and inspection confirms they're mostly +false positives (discussions *about* auto-approve, not violations). Exactly why +the script emits excerpts, not counts. A bare "45 violations" would have been +actively misleading. + +### Deviation from plan: script location + +Plan said `scripts/measure-prompt-behavior.ts` at repo root. It needs `js-yaml`, +which a root script **cannot resolve** in this pnpm workspace (root node_modules +lacks it). Moved logic to `packages/codev/src/lib/prompt-behavior-metrics.ts` +beside `protocol-drift-audit.ts`/`framework-ref-audit.ts` — same module shape, +unit-testable, deps resolve — with a thin CLI at +`packages/codev/scripts/measure-prompt-behavior.ts`. Spec + plan updated to the +real paths. The bash surface script stays at root (no deps). + +### Test-suite investigation worth recording + +First full run: 49 files / 62 tests failing. Easy to write off as pre-existing — +but I verified instead. All were `@cluesmith/codev-core` import errors: the +workspace wasn't built. Building core fixed 48 files. The last 8 were +"integration with real shellper" tests needing `dist/terminal/shellper-main.js`; +`npx tsc` produced it and all 90 passed. + +**Full suite now 193 files / 3772 tests green, 0 failures.** No flaky tests to +skip. Lesson reinforced: "pre-existing failure" is a claim requiring evidence, +not a default assumption — a fresh worktree just isn't built. + +## Phase 1 iter-1 review — Gemini/Claude APPROVE, Codex REQUEST_CHANGES ×2, both fixed + +Codex again the one checking whether the numbers actually mean anything: + +1. **Hardcoded spawn/phase word counts** (4891/1395) would have silently + corrupted the Phase 7 N1 delta — reruns would report pre-trim numbers for + the two largest components. Now derived from resolved artifacts; + sensitivity-verified (shrink protocol.md → ALWAYS_ON drops 21,856→18,048). + Reproducible baseline is **21,856** (old 24,614 counted per-project variable + content that no trim can touch). Spec N1 note updated. +2. **B5 never actually captured** — plan said B1–B5, I wrote "capture + separately" and didn't. Snapshot now in the baseline artifact, capture-dated, + marked non-deterministic, drives no trigger. + +Word baseline output now committed too (1252-word-baseline.md). + +## Phase 2 prep findings (read-only, ahead of the audit) + +Diffed all 17 drifted files against the installed skeleton. Early +classifications for the audit: + +- **spir/protocol.md's 85 "local additions" are ROT**, not local-unique: the + old "Porch Orchestration" section uses obsolete underscore gate IDs + (`spec_approval`; porch uses `spec-approval`) and skeleton restructured to + the build-verify model. Local kept what skeleton deleted. +- **roles/architect.md area-label section is ROT with a twist**: skeleton + GENERALIZED it (`/` placeholders for adopters); the codev-specific + `area/` version's content is already owned by CLAUDE.md. Skeleton wins, + nothing lost. +- **Genuine escalation candidates**: + - TICK "Amendments" sections in spir+aspir spec/plan templates — local-only; + no tick protocol dir exists anywhere, but porch's phase prompts still + reference TICK amendments. Ambiguous → escalate. + - `max_iterations: 8` (local) vs `3` (skeleton) in spir+aspir protocol.json — + a real behavioral difference in CMAP loop bounds. Ambiguous → escalate. + +## Iter-2 hiccup worth remembering: the baseline measured itself + +Porch's checks failed on iter-2: the reproduction test expected 160 verdicts, +got 163. Cause: **this project's own iter-1 review verdicts landed in its +status.yaml — the corpus is live and the measuring project was in it.** Same +for B3: my own thread file (which discusses scar rules constantly) was in the +prose scan and had already contributed a hit to the committed baseline. + +Fix: self-exclusion by default (SELF_PROJECT_DIR, SELF_FILE_PREFIXES). +Baseline = pre-project state, so the measuring project's artifacts are out of +scope by definition. Baseline artifact regenerated clean: 160 verdicts, 349 +files, 44 hits. New test pins the exclusion. + +Observer effect in the smallest possible lab. The verify phase needs to +remember this too: when comparing, 1252's own artifacts stay excluded. + +## Phase 1 iter-2: unanimous APPROVE. Phase 2 (M11 audit) executed. + +Audit committed: codev/resources/1252-shadow-tree-audit.md — **77 rows** (spec +said 76; mechanical enumeration caught consult-types/integration-review.md, +which my hand count missed). 60 identical→TS1, 13 drifted-rot→TS1, 4 +local-unique→pending, escalated to architect: + +1. **max_iterations 8 vs 3** (spir+aspir json) — CMAP loop bound, no config + override exists for it. TS1/TS2/TS3 options laid out. +2. **cwd: packages/codev** (air+bugfix json) — real monorepo functionality; + recommended migrating to .codev/config.json porch.checks (Spec #550 + sanctioned mechanism) then TS1. Noted spir/aspir only pass today because + the repo root happens to have build/test scripts. + +Key evidence trail in the audit: TICK retired (all local TICK refs = rot, +though skeleton's own porch prompts still emit TICK-amendment language — +flagged for Phase 8); obsolete underscore gate IDs prove spir/protocol.md's +"additions" are pre-restructure leftovers; architect.md's area/ recipes are +owned by CLAUDE.md so the skeleton's generalized version loses nothing. + +T11 parses the audit table (6-column contract, enumerated values): 5 tests +green, completion guard (zero pending) phase-gated like the drift gate's. +Also armed: a guard that fails if any file vanishes while pending/TS3. + +## Phase 2 iter-1: Gemini/Claude APPROVE, Codex REQUEST_CHANGES — accepted, remedy differed + +Codex caught my plan contradicting itself: Phase-2 criteria said "zero rows +pending" while the spec's own sequencing designs for open escalations through +Phase 3 (M3 "skips anything M11 escalated") with the real deadline at Phase 4 +(M8 "gated on M11 ... escalations ruled on"). + +The important part: satisfying the criterion AS WRITTEN would have meant +invoking the TS3 escape hatch on all 4 escalations within the hour of sending +them — before the architect could realistically rule. The escape hatch is for +escalations that CANNOT be resolved, not for skipping the wait. A phase +criterion must never strong-arm a human gate. + +Fix: plan criteria amended (deadline = Phase 4); T11 gains an AUTOMATIC guard — +the moment any audited file is deleted, zero pending rows may remain. Deletion +arms the assertion; no human has to remember a flag. That answers Codex's +deeper point (manual skip-flag = phase passes while violating itself) more +durably than resolving the escalations prematurely would have. + +Also: spec count corrected in place (77 shadow copies; hand count missed +consult-types/integration-review.md) and Claude's cosmetic header arithmetic +fixed (73 protocol files, not 74). + +## Phase 3 — 13 rot files reconciled (M3) + +Skeleton copied over the 13 rot files per D1. The headline drift is repaired: +codev/protocols/spir/builder-prompt.md now carries Multi-PR Mechanics, Verify +Phase, and "Entering verify phase." — the next SPIR builder spawned in this +repo gets its verify instructions. + +Remaining divergence: exactly the 4 escalated json files. Allowlist shrunk +17 → 4, all re-tagged ESCALATED with adjudication citations. PHASE_3_COMPLETE +flipped, so the no-PENDING_RECONCILE guard is now live. Audit rows for the 13 +updated to `identical` with "RECONCILED Phase 3 (was: ...)" notes preserving +the original evidence. + +Still waiting on architect rulings for the 4 (max_iterations, cwd). Phase 4 +cannot start until they resolve — enforced by T11's automatic guard, not by my +memory. + +## Phase 3 addendum: reconciliation broke Spec 746's frozen baselines — instructive + +Porch checks caught baked-decisions.test.ts failing: it froze the THEN-DRIFTED +codev builder-prompts as "pure-addition baselines" (Spec 746), so my +reconciliation's line change (Ready for cleanup. → Entering verify phase.) +violated the pure-addition invariant. First fix attempt (baseline := current) +broke the pollution check — the baseline's true meaning is "file minus 746's +insertion". Rebuilt both baselines as current-minus-Baked-Decisions-block; +all 193 file tests + full suite (3780) green. + +Two durable notes: +1. **M7 catch**: baked-decisions.test.ts reads codev/protocols/* by literal + path — a test-tier consumer that Phase 4's deletion WILL break (ENOENT). + Added to the Phase 4 compat-audit worklist: repoint its codev/ entries at + the skeleton (which after deletion is the single source). +2. Frozen-file baselines are drift bombs: any legitimate later edit fails the + check for the wrong reason. The 746 test's real claim ("the baked section + is a pure insertion") survives only if the baseline is DERIVED + (current minus section), not frozen. + +## Phase 4 — shadow tree DELETED (77 files), M8–M10 complete + +Rulings landed: E1 = TS1 (skeleton's max_iterations 3 — the B2 baseline +evidence decided it), E2 = migrate cwd to .codev/config.json porch.checks for +all four protocols, then TS1. + +E2 carried a verification requirement (config is untracked — does it reach +every porch-check context?). Verified against code: spawn symlinks it into new +worktrees (spawn-worktree.ts:100); CI never runs porch checks; and the decisive +fact — **the migration is defense-in-depth, not load-bearing**, because root +package.json delegates build/test to packages/codev, proven green all session +by spir's cwd-less checks. No context can break. Main-checkout file creation +handed to the architect (can't write outside worktree); fallback covers the +interim. + +Execution: 4 jsons reconciled → 77 shadow copies deleted → roles/ and +consult-types/ gone entirely → 3 local-only files preserved → +copyRoles/copyProtocols removed with a tombstone → M10 manifest (77 sha256s) ++ equivalence test prove deletion was a byte-level no-op for what agents are +served → allowlist EMPTY → all T11 guards green, zero pending. + +**Humbling M7 note**: my step-4a regex classification of test consumers had 4 +false negatives (bugfix-744, governance-sweep, review-prompt-routing, +bugfix-619 — path.join segments / template literals / dirname traversal). The +deletion caught them: ENOENT, loud, at the point of change. 8 repo-readers +total, all repointed at codev-skeleton/. Recorded in the audit: a grep +classification is a hypothesis; the deletion is the test. + +The repo now dogfoods exactly what it ships. C6's mirror-both-trees invariant +is dead for protocols/roles — Phase 8 updates arch-critical accordingly. + +## Phase 4 iter-1: Gemini/Claude APPROVE, Codex REQUEST_CHANGES ×3 — all fixed + +Codex caught me delivering less than my own amended plan: M10(ii) promised +actual assembled-prompt snapshots and I shipped an inference (hashes + purity +argument). The argument was sound but tested the premises, not the conclusion. +Fixed properly: pre-deletion tree reconstructed via git archive, real +buildPromptFromTemplate run against it for all 9 protocols (spir prompt = +30,593 bytes with inlined protocol reference), snapshots committed, live +assembly must reproduce them byte-for-byte. Also added the tier assertion +(resolved path === skeleton path, not just content match). + +Third catch: my mechanical repoint left bugfix-685's parity comparing a file +to itself — a test that can never fail, worse than no test. Removed it AND the +identical defect in baked-decisions (unflagged — fixing the class, not the +instance). Suite count drops 3,767→3,746: vacuous tests deleted, not skipped. + +Gem for the review: Spec 746's comment explicitly described the drift +("skeleton has Multi-PR Workflow / Verify Phase sections that codev/ doesn't +... PRE-EXISTING and not Phase 1's responsibility"). The drift was OBSERVED +and consciously stepped around months before this project. Detection was never +the problem — thirdhand confirmation of the spec's core thesis. + +## Phase 4 iter-3 — Codex found the drift thesis at ANOTHER copy boundary + +Codex's catch was architecturally the best of the project: my repointed tests +validate codev-skeleton/ (source), but resolveCodevFile serves the EMBEDDED +copy at packages/codev/skeleton (build-time cp). Source tests could pass while +agents get stale bytes — the project's own disease at the build boundary. + +Remedy: skeleton-embed-sync.test.ts — bidirectional byte-parity between source +and embedded trees. One guard at the copy boundary instead of rerouting N +tests through the resolver. Source tests keep their commit-surface advantage +(fail where the dev edits, pre-build); the guard ties commit surface to +serving surface. Same single-owner pattern as everywhere else: enforce the +boundary, don't chase consumers. + +Also swept the duplicate-entry residue as a real class this time (after +claiming that once before and missing 742): deduped 744/governance-sweep/ +protocol-prompt-audit AND found three more vacuous pair loops inside +baked-decisions. 3,726 green. + +## Phase 5 — scar registry, eight compressed wordings (M5/D3) + +Registry at codev/resources/scar-rules.yaml; T6 (scar-rules.test.ts) enforces: +count pinned at 8, ids pinned, byte-verbatim presence on every listed surface, +stale-variant sweep, N3 pair check. 28 skeleton files + CLAUDE/AGENTS + +arch-critical + 4 skill copies converged to canonical wordings. + +Wording judgement calls worth recording: +- **human-gates**: NOT "never approve gates yourself" — builders legitimately + run `porch approve` after the human decision is relayed (workspace + convention). Canonical targets the actual sin: treating a gate as approved + WITHOUT an explicit human decision. +- **never-destroy-worktrees** keeps its escape hatch (--resume, then ask) and + its teeth ("what is expendable is never your call") in two sentences. +- Rules 3/7/8 had NO repo surface (lived only in Waleed's user-global + CLAUDE.md); D3's ratification promotes them to repo CLAUDE/AGENTS always-on. + +Fixture fallout handled as explicit acts: prompt snapshots + manifest +regenerated (now pin post-compression state; comment documents the contract), +derived baselines re-derived with the same canonical substitutions. + +CLAUDE.md structure: two 🚨 banner blocks collapsed into topical compact rules ++ new "Scar Rules (always in force)" section housing the five without topical +homes. Net CLAUDE.md shrink measured in Phase 7. + +## Phase 5 convergence saga — 4 iterations, each Codex catch real + +Iter-1: includes() → line-exactness (appended-qualifier attack); -f → -fd; +maintain/protocol.md registered. Iter-2: architect.md self-contradiction; +gate-rule variant on 8 builder-prompts. Iter-3: SECOND afx-anywhere instance +(fixed the flagged line, hadn't swept the file); sweep extended to the class. +Iter-4: "bypass checks" variant ×11 (grepped the rule's phrasings, not the +ACT's); arch-critical exception dissolved by rewriting the now-false two-trees +fact (freed a cap slot; R5 canonical stands line-exact; pulled a sliver of +Phase 8's C6 rewrite forward with justification). + +Meta-lesson accumulating for the review: every iteration's miss was a +sweep-scope failure — fix-the-instance vs fix-the-class, and grep-for-wording +vs grep-for-act. The registry+line-exactness machinery is exactly what makes +these misses eventually impossible instead of eventually repeated. + +## Phase 6 — ownership map + completeness enforcement (M1/M4) + +Data-first (the B2 lesson): built the extractor, ran it over the declared +boundary (26 files), THEN authored the map from what it found. 134 normative +candidates: 23 mapped (7 non-scar duplicated classes), 37 scar +(registry-enforced externally — no double ownership of scar enforcement), +74 file-local singles. + +Design decision that matters: the catch-all disposition would make T12 vacuous +(everything matches /.*/), so the resolver tracks catch-all usage and FAILS +any candidate whose text appears on 2+ files via catch-all. Single-file +process lines pass cheaply; cross-surface duplication — the thing the +single-owner rule is about — always demands an explicit disposition. New +duplication fails CI the moment it's introduced. + +The 7 non-scar classes are enforcement:manual with justifications naming +their Phase-7 flip (a test asserts every manual justification does so). T7's +machinery is fixture-proven (detects restatement on non-owner) and activates +per-class as Phase 7 flips them — same staged-activation pattern as the drift +gate. Two coordination notes recorded in the map: baked-decisions dedup must +move with Spec 746's test suite; pr-single-by-default with bugfix-744's. + +Suite: 3,744 green. + +## Phase 7 — dedup + measurement: the honest N1 story + +**Achieved: 21,856 → 20,314 served always-on words = −7.1% (target was 20%).** +Reporting the shortfall plainly, per the spec's own instruction, with the +structural decomposition: + +- CLAUDE.md −1,421: the real win. Relocated Runnable Worktrees (1,212w of + reference-tier content that existed NOWHERE else — relocation-with-pointer, + not dedup) into agent-farm.md (both trees), trimmed Inter-agent messaging to + summary+pointer (deep grammar owned by agent-farm.md). +- Spawn −169 net: drift REPAIR added ~207 served words (Multi-PR + Verify + sections the prompt was supposed to have!); protocol.md replacement −384. +- Phase task ≈ flat: canonical scar lines ≈ old variants in length. +- D3 compression's CLAUDE.md savings were largely consumed by D3's OWN + promotion of rules 3/7/8 into the repo (+~120) — compressing while adding. + +Why 20% was never reachable in scope: remaining always-on = protocol.md +(3,703w, protocol semantics excluded by Non-goals), porch prompts (process +scaffolding), CLAUDE.md's genuinely-always-on remainder. The 24.6k→20% +arithmetic assumed more of the surface was duplicated rules; most was +single-owned prose. The verify phase will tell us if even −7% moved behavior. + +**Dedup by include, not by reference** — the key design fact: these are SERVED +prompts; a bugfix builder never sees spir's prompt, so prose references would +DELETE content from agents' context. Shared partials +(codev-skeleton/partials/, expanded via resolveCodevIncludes at assembly) give +single AUTHORED ownership with unchanged SERVED bytes. Include support added +to builder-prompt loading (one line, mirroring the protocol_reference path). +5 partials extracted; 6 classes flipped automated; protocol-specific variants +kept via a new `retained_restatements` field (distinct from `references` so +pointer surfaces stay pattern-forbidden — preserving Codex's Phase-6 fix). + +**Measurement integrity catch (self-caught)**: after extraction the proxy +counted AUTHORED builder-prompt words (612) while agents are SERVED the +expanded form (851). Fixed the script to count expanded words — otherwise N1 +would have claimed 239 phantom words. Dedup-by-include changes ownership, not +served bytes; the metric must not reward it. + +Also: extractor probe corrected my map data twice more (soft-mode carriers = +spir/aspir/bugfix/pir/air, NOT experiment; notifications = spir/aspir uniform ++ air/bugfix protocol-specific). Every reference list I wrote from memory was +wrong somewhere; every grep-verified one held. The pattern is now beyond +dispute. + +## Phase 8 — governance sync + E2E disposition + +- CLAUDE/AGENTS: ~15 dangling `codev/protocols/...` prose refs repointed at + codev-skeleton/ (deletion made them point at nothing); RELEASE pointer + annotated as codev-local-by-design. N3 byte-identity held. +- arch.md: Repository Dual Nature rewritten (codev/protocols/ = local-only + protocols exclusively; shadow story + enforcement told in place); new + single-owner invariant added to Invariants & Constraints. +- lessons-learned.md (Critical): "A detector that reports without failing is a + detector nobody reads" + corollaries (frozen baselines are drift bombs; + grep classification is a hypothesis, deletion is the test; measure the + served artifact, not the authored one). +- arch-critical: already restructured in Phase 5 iter-4 (C6 retired there); + caps verified 10 facts / 33 lines. +- Follow-ups filed: #1276 (tiering, D4) and #1277 (A/B eval, M12c). +- **T13(b) rescheduled to VERIFY by architect ruling** — afx spawn has no + branch selector; every spawn branches from main HEAD, so a pre-merge probe + assembles the PRE-change tree and verifies nothing. Discovered constraint, + documented in spec T13 and added to the verify checklist (architect runs the + disposable probe post-merge + post-local-install and records the prompt). + Pre-merge proxy: the nine byte-compared prompt snapshots. + +## Review phase — all 8 phases closed, review doc written, PR next + +Phase 8 closed after 5 rounds (final: unanimous). Full arc: 8 phases, +~20 review rounds, every Codex REQUEST_CHANGES either fixed or rebutted with +evidence that survived subsequent rounds. Review doc at +codev/reviews/1252-prompt-architecture-single-own.md carries the honest N1 +(-7.0%), the verify-phase checklist (T13b probe + M12b comparison), and the +systematic observation that the review loop's recurring value was checking +that enforcement mechanisms BIND, not that artifacts exist. + +## FINAL CHAPTER — harvested, not merged (2026-07-28) + +Waleed's pr-gate decision: PR #1278 does NOT merge. Charter-level re-scope, +not a quality verdict — a successor project will shrink the prompt surface +radically first (blog-principles judgment rewrite, >50% target, +frontier-models-only), then rebuild enforcement fit-for-purpose around the +post-shrink surface. Carrying deletion + registry + map + trims for a surface +about to be rewritten is the wrong risk/reward. + +Harvest executed: a minimal PR off main carrying (1) the 17-file drift +reconciliation — the live bug — with E1 (max_iterations:3) and E2 (cwd via +main's .codev/config.json) applied, plus the 746 baseline re-derivations the +sync forces; (2) the knowledge artifacts: shadow-tree audit, word baselines, +behavioural baseline, measurement tooling + determinism test, the rewritten +review, this thread. + +Stays on this branch (preserved, PR closed unmerged): deletion + equivalence +proofs, scar registry + T6, ownership map + T12, partials + served guard, +CLAUDE.md restructure, all skeleton edits. The scar-registry concept and the +eight ratified wordings move into the successor charter — deferred, not +discarded. + +Worth saying plainly: the measurement work is what made this decision +possible. An honest -7.0% against a 20% aspiration, decomposed to show the +remaining mass was single-owned protocol prose, is exactly the evidence that +says "shrink the surface first, then enforce." The project's most durable +output may be that its numbers argued against its own machinery. diff --git a/packages/codev/scripts/measure-prompt-behavior.ts b/packages/codev/scripts/measure-prompt-behavior.ts new file mode 100644 index 000000000..b820486d9 --- /dev/null +++ b/packages/codev/scripts/measure-prompt-behavior.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env npx tsx +/** + * CLI runner for the behavioural-impact measurement (Spec 1252, M12 / T14). + * + * The logic lives in `../src/lib/prompt-behavior-metrics.ts` so it is + * unit-testable and can resolve this package's `js-yaml` dependency; this file + * is a thin entry point only. + * + * Usage (from packages/codev): + * npx tsx scripts/measure-prompt-behavior.ts + * npx tsx scripts/measure-prompt-behavior.ts --json + * + * Produces the Phase-1 baseline artifact: + * npx tsx scripts/measure-prompt-behavior.ts ../.. \ + * > ../../codev/resources/1252-behavior-baseline.md + */ +import { runCli } from '../src/lib/prompt-behavior-metrics.js'; + +process.stdout.write(runCli(process.argv.slice(2), process.cwd()) + '\n'); diff --git a/packages/codev/src/__tests__/bugfix-685-close-keyword.test.ts b/packages/codev/src/__tests__/bugfix-685-close-keyword.test.ts index 83c27be74..a043bb25b 100644 --- a/packages/codev/src/__tests__/bugfix-685-close-keyword.test.ts +++ b/packages/codev/src/__tests__/bugfix-685-close-keyword.test.ts @@ -19,22 +19,19 @@ interface PromptTarget { relPath: string; } -const codevTargets: PromptTarget[] = [ - { protocol: 'spir', relPath: 'codev/protocols/spir/prompts/review.md' }, - { protocol: 'aspir', relPath: 'codev/protocols/aspir/prompts/review.md' }, - { protocol: 'air', relPath: 'codev/protocols/air/prompts/pr.md' }, - { protocol: 'bugfix', relPath: 'codev/protocols/bugfix/prompts/pr.md' }, - { protocol: 'maintain', relPath: 'codev/protocols/maintain/prompts/review.md' }, - { protocol: 'experiment', relPath: 'codev/protocols/experiment/builder-prompt.md' }, +// Spec 1252 (Phase 4): the codev/protocols shadow tree was deleted — the +// skeleton is the single owner, so the former codev-vs-skeleton mirror pair +// collapsed to one target list (and the mirror-parity test below was removed +// as vacuous: there is no second tree to compare against). +const allTargets: PromptTarget[] = [ + { protocol: 'spir', relPath: 'codev-skeleton/protocols/spir/prompts/review.md' }, + { protocol: 'aspir', relPath: 'codev-skeleton/protocols/aspir/prompts/review.md' }, + { protocol: 'air', relPath: 'codev-skeleton/protocols/air/prompts/pr.md' }, + { protocol: 'bugfix', relPath: 'codev-skeleton/protocols/bugfix/prompts/pr.md' }, + { protocol: 'maintain', relPath: 'codev-skeleton/protocols/maintain/prompts/review.md' }, + { protocol: 'experiment', relPath: 'codev-skeleton/protocols/experiment/builder-prompt.md' }, ]; -const skeletonTargets: PromptTarget[] = codevTargets.map((t) => ({ - protocol: t.protocol, - relPath: t.relPath.replace(/^codev\//, 'codev-skeleton/'), -})); - -const allTargets = [...codevTargets, ...skeletonTargets]; - describe('PR close-keyword directive (#685)', () => { it.each(allTargets)( '$protocol prompt at $relPath mentions Closes/Fixes keyword', @@ -60,14 +57,6 @@ describe('PR close-keyword directive (#685)', () => { }, ); - it('codev-skeleton copies match codev originals for every edited prompt', () => { - for (const { relPath } of codevTargets) { - const codevContent = fs.readFileSync(path.join(repoRoot, relPath), 'utf-8'); - const skeletonPath = relPath.replace(/^codev\//, 'codev-skeleton/'); - const skeletonContent = fs.readFileSync(path.join(repoRoot, skeletonPath), 'utf-8'); - expect(skeletonContent, `mismatch: ${skeletonPath}`).toBe(codevContent); - } - }); /** * Porch's phase prompt renderer (packages/codev/src/commands/porch/prompts.ts @@ -84,11 +73,11 @@ describe('PR close-keyword directive (#685)', () => { * out of scope — this test only guards the PR body template itself. */ const prBodyTargets: PromptTarget[] = [ - { protocol: 'bugfix', relPath: 'codev/protocols/bugfix/prompts/pr.md' }, - { protocol: 'air', relPath: 'codev/protocols/air/prompts/pr.md' }, - { protocol: 'spir', relPath: 'codev/protocols/spir/prompts/review.md' }, - { protocol: 'aspir', relPath: 'codev/protocols/aspir/prompts/review.md' }, - { protocol: 'maintain', relPath: 'codev/protocols/maintain/prompts/review.md' }, + { protocol: 'bugfix', relPath: 'codev-skeleton/protocols/bugfix/prompts/pr.md' }, + { protocol: 'air', relPath: 'codev-skeleton/protocols/air/prompts/pr.md' }, + { protocol: 'spir', relPath: 'codev-skeleton/protocols/spir/prompts/review.md' }, + { protocol: 'aspir', relPath: 'codev-skeleton/protocols/aspir/prompts/review.md' }, + { protocol: 'maintain', relPath: 'codev-skeleton/protocols/maintain/prompts/review.md' }, ]; it.each(prBodyTargets)( diff --git a/packages/codev/src/__tests__/bugfix-742-consult-templates.test.ts b/packages/codev/src/__tests__/bugfix-742-consult-templates.test.ts index ff0c335ee..bf4717eef 100644 --- a/packages/codev/src/__tests__/bugfix-742-consult-templates.test.ts +++ b/packages/codev/src/__tests__/bugfix-742-consult-templates.test.ts @@ -21,25 +21,21 @@ import * as path from 'node:path'; const repoRoot = path.resolve(import.meta.dirname, '../../../..'); +// Spec 1252 (Phase 4): the codev/protocols shadow tree was deleted — the +// skeleton is the single owner, so the former codev-vs-skeleton parity checks +// were removed as vacuous (no second tree exists). The substantive assertions +// (BUGFIX templates must differ from SPIR's) run against the skeleton. const templates = { - bugfixPrReview: path.join(repoRoot, 'codev/protocols/bugfix/consult-types/pr-review.md'), - bugfixImplReview: path.join(repoRoot, 'codev/protocols/bugfix/consult-types/impl-review.md'), - spirPrReview: path.join(repoRoot, 'codev/protocols/spir/consult-types/pr-review.md'), - spirImplReview: path.join(repoRoot, 'codev/protocols/spir/consult-types/impl-review.md'), - skeletonBugfixPrReview: path.join( - repoRoot, - 'codev-skeleton/protocols/bugfix/consult-types/pr-review.md', - ), - skeletonBugfixImplReview: path.join( - repoRoot, - 'codev-skeleton/protocols/bugfix/consult-types/impl-review.md', - ), + bugfixPrReview: path.join(repoRoot, 'codev-skeleton/protocols/bugfix/consult-types/pr-review.md'), + bugfixImplReview: path.join(repoRoot, 'codev-skeleton/protocols/bugfix/consult-types/impl-review.md'), + spirPrReview: path.join(repoRoot, 'codev-skeleton/protocols/spir/consult-types/pr-review.md'), + spirImplReview: path.join(repoRoot, 'codev-skeleton/protocols/spir/consult-types/impl-review.md'), }; const read = (p: string) => fs.readFileSync(p, 'utf-8'); describe('BUGFIX consult templates (#742)', () => { - describe('codev/ (self-hosted)', () => { + describe('skeleton templates (single owner)', () => { it('pr-review.md must differ from the SPIR version', () => { const bugfix = read(templates.bugfixPrReview); const spir = read(templates.spirPrReview); @@ -53,21 +49,9 @@ describe('BUGFIX consult templates (#742)', () => { }); }); - describe('codev-skeleton/ (shipped template)', () => { - it('pr-review.md must match the codev/ copy byte-for-byte', () => { - expect(read(templates.skeletonBugfixPrReview)).toEqual(read(templates.bugfixPrReview)); - }); - - it('impl-review.md must match the codev/ copy byte-for-byte', () => { - expect(read(templates.skeletonBugfixImplReview)).toEqual(read(templates.bugfixImplReview)); - }); - }); - describe.each([ - ['codev/ pr-review.md', templates.bugfixPrReview], - ['codev/ impl-review.md', templates.bugfixImplReview], - ['skeleton pr-review.md', templates.skeletonBugfixPrReview], - ['skeleton impl-review.md', templates.skeletonBugfixImplReview], + ['skeleton pr-review.md', templates.bugfixPrReview], + ['skeleton impl-review.md', templates.bugfixImplReview], ])('content of %s', (_label, filePath) => { const content = read(filePath); diff --git a/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts b/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts index 4a4d2aa7e..cd46d96d7 100644 --- a/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts +++ b/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts @@ -21,11 +21,11 @@ import * as path from 'node:path'; const repoRoot = path.resolve(__dirname, '..', '..', '..', '..'); +// Spec 1252: shadow tree deleted; Phase 7 extracted the PR Strategy section +// to a shared partial (single authored owner, expanded into both spir and +// aspir served prompts via {{> partials/pr-strategy.md}}). const PROMPT_FILES = [ - 'codev/protocols/spir/builder-prompt.md', - 'codev-skeleton/protocols/spir/builder-prompt.md', - 'codev/protocols/aspir/builder-prompt.md', - 'codev-skeleton/protocols/aspir/builder-prompt.md', + 'codev-skeleton/partials/pr-strategy.md', ]; describe('bugfix-744: SPIR/ASPIR builder-prompt PR strategy', () => { diff --git a/codev/protocols/air/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/air.txt similarity index 54% rename from codev/protocols/air/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/air.txt index 8552d3c3b..3a2326a3b 100644 --- a/codev/protocols/air/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/air.txt @@ -1,3 +1,71 @@ +# air Builder (strict mode) + +You are implementing M10 equivalence fixture — fixed context. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) + +## Protocol +Follow the AIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## Baked Decisions + +If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. + +If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. + +## Issue #9999 +**Title**: fixture + +**Description**: +fixture body + +## Your Mission +1. Read the issue requirements carefully +2. Implement the feature (< 300 LOC) +3. Write tests for the feature +4. Create PR with review in the PR body (NOT as a separate file) +5. Notify architect via `afx send architect "PR #N ready for review (implements #9999)"` + +**IMPORTANT**: AIR produces NO spec, plan, or review files. The review goes in the PR body. + +If the feature is too complex (> 300 LOC or architectural changes), notify the Architect via: +```bash +afx send architect "Issue #9999 is more complex than expected. [Reason]. Recommend escalating to ASPIR." +``` + +## Notifications +Always use `afx send architect "..."` to notify the architect at key moments: +- **PR ready**: `afx send architect "PR #N ready for review (implements #9999)"` +- **PR merged**: `afx send architect "PR #N merged for issue #9999. Ready for cleanup."` +- **Blocked**: `afx send architect "Blocked on issue #9999: [reason]"` + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the AIR protocol +2. Review the issue details +3. Implement the feature + +--- + +## Protocol Reference (full text) + # AIR Protocol > **AIR** = **A**utonomous **I**mplement & **R**eview @@ -34,7 +102,6 @@ AIR is a minimal protocol for implementing small features (< 300 LOC) where the - Bug fixes → use **BUGFIX** - Features needing spec discussion → use **SPIR** or **ASPIR** -- Amendments to existing specs → use **TICK** - Architectural changes → use **SPIR** - Complex features with multiple phases → use **SPIR** or **ASPIR** @@ -89,4 +156,4 @@ codev-skeleton/protocols/air/ └── consult-types/ ├── impl-review.md # Implementation consultation guide └── pr-review.md # PR consultation guide -``` +``` \ No newline at end of file diff --git a/packages/codev/src/__tests__/fixtures/prompt-snapshots/aspir.txt b/packages/codev/src/__tests__/fixtures/prompt-snapshots/aspir.txt new file mode 100644 index 000000000..e5485f8c0 --- /dev/null +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/aspir.txt @@ -0,0 +1,189 @@ +# aspir Builder (strict mode) + +You are implementing M10 equivalence fixture — fixed context. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals +- Do not deviate from the porch-driven workflow + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip the 3-way review** — always follow porch next → porch done cycle +- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval + +## Protocol +Follow the ASPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## Baked Decisions + +If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. + +If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. + +## Issue #9999 +**Title**: fixture + +**Description**: +fixture body + +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: + +1. Cut a branch, open a PR, wait for merge +2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) +3. Continue to the next slice, open another PR +4. Repeat + +**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. + +Record PRs in status.yaml: `porch done 9999 --pr --branch ` +Record merges: `porch done 9999 --merged ` + +## Verify Phase + +After the final PR merges, the project enters the **verify** phase. You stay alive through verify: +1. Pull the integration branch into your worktree +2. Run `porch done 9999` to signal verification is ready +3. The architect approves `verify-approval` when satisfied + +If verification is not needed: `porch verify 9999 --skip "reason"` + +## Notifications +Always use `afx send architect "..."` to notify the architect at key moments: +- **Gate reached**: `afx send architect "Project 9999: ready for approval"` +- **PR ready**: `afx send architect "PR #N ready for review (project 9999)"` +- **PR merged**: `afx send architect "Project 9999 PR merged. Entering verify phase."` +- **Blocked**: `afx send architect "Blocked on project 9999: [reason]"` + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the protocol document thoroughly +2. Review the spec and plan (if available) +3. Begin implementation following the protocol phases + +--- + +## Protocol Reference (full text) + +# ASPIR Protocol + +> **ASPIR** = **A**utonomous **S**pecify → **P**lan → **I**mplement → **R**eview +> +> Identical to SPIR but without human approval gates on spec and plan phases. +> Each phase has one build-verify cycle with 3-way consultation. + +## What is ASPIR? + +ASPIR is an autonomous variant of the SPIR protocol. It follows the exact same phases (Specify → Plan → Implement → Review) with the same 3-way consultations, checks, and PR flow — but removes the `spec-approval` and `plan-approval` human gates. + +This means the builder proceeds automatically from Specify → Plan → Implement without waiting for human approval at each gate. The `pr` gate in the Review phase is preserved — a human still reviews all code before merge. + +### Differences from SPIR + +| Aspect | SPIR | ASPIR | +|--------|------|-------| +| Spec gate (`spec-approval`) | Human must approve | Auto-approved | +| Plan gate (`plan-approval`) | Human must approve | Auto-approved | +| PR gate (`pr`) | Human must approve | Human must approve | +| Phases | Specify → Plan → Implement → Review | Same | +| 3-way consultations | Yes, every phase | Same | +| Checks (build, tests, PR) | Yes | Same | +| Prompts / templates | Full set | Same (copied from SPIR) | + +### When to Use ASPIR + +Use ASPIR instead of SPIR when: + +- The work is **trusted and low-risk** — internal tooling, protocol additions, well-understood features +- The architect has **pre-written and approved** the spec before spawning +- The scope is **self-contained** with low blast radius +- You want **full SPIR discipline** (consultations, phased implementation, review) without waiting at gates + +### When NOT to Use ASPIR + +Use SPIR instead when: + +- The feature involves **novel architecture** or unclear requirements +- The spec needs **iterative human feedback** during drafting +- The work is **high-risk** — security-sensitive, user-facing, or broadly impactful +- You want to **review and adjust** the plan before implementation starts + +## Baked Decisions (Optional) + +When filing an issue for ASPIR, you can pin architectural decisions you don't want the builder or CMAP reviewers to re-litigate. Include a `## Baked Decisions` section (any heading level is fine) anywhere in the issue body. Useful categories: language, framework, deployment shape, key dependencies, decisions deferred to a later spec. The builder will copy the section verbatim into the spec's Constraints and treat each item as fixed; CMAP reviewers will not propose alternatives unless the spec itself fails to honor a stated decision. Leave the section out for issues where you want the builder to explore freely — absence is the no-op default. You can amend or rescind a baked decision at any time by updating the issue and respawning, or by sending the builder a direct instruction via `afx send`. + +## Protocol Phases + +ASPIR follows the same four phases as SPIR. For full phase documentation, see the [SPIR protocol](../spir/protocol.md). + +### S - Specify +Write specification with 3-way review (Gemini, Codex, Claude). **No human gate** — proceeds directly to Plan after verification. + +### P - Plan +Write implementation plan with 3-way review. **No human gate** — proceeds directly to Implement after verification and checks pass. + +### I - Implement +Execute each plan phase with build-verify cycle. Same as SPIR — no gate between phases (SPIR also has no gate here). + +### R - Review +Final review, PR preparation, and 3-way review. **PR gate preserved** — builder stops and waits for human approval before merge. + +## Usage + +```bash +# Spawn a builder using ASPIR +afx spawn 42 --protocol aspir + +# The builder runs autonomously through Specify → Plan → Implement +# and stops only at the PR gate in the Review phase +``` + +## File Structure + +``` +codev/protocols/aspir/ +├── protocol.json # Protocol definition (SPIR minus gates) +├── protocol.md # This file +├── builder-prompt.md # Builder instructions (same as SPIR) +├── prompts/ +│ ├── specify.md # Specify phase prompt (same as SPIR) +│ ├── plan.md # Plan phase prompt (same as SPIR) +│ ├── implement.md # Implement phase prompt (same as SPIR) +│ └── review.md # Review phase prompt (same as SPIR) +├── consult-types/ +│ ├── spec-review.md # Spec consultation guide (same as SPIR) +│ ├── plan-review.md # Plan consultation guide (same as SPIR) +│ ├── impl-review.md # Impl consultation guide (same as SPIR) +│ ├── phase-review.md # Phase consultation guide (same as SPIR) +│ └── pr-review.md # PR consultation guide (same as SPIR) +└── templates/ + ├── spec.md # Spec template (same as SPIR) + ├── plan.md # Plan template (same as SPIR) + └── review.md # Review template (same as SPIR) +``` + +All files except `protocol.json` and `protocol.md` are identical to their SPIR counterparts. \ No newline at end of file diff --git a/codev/protocols/bugfix/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/bugfix.txt similarity index 61% rename from codev/protocols/bugfix/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/bugfix.txt index 29fb7ed5b..1bd9bb47f 100644 --- a/codev/protocols/bugfix/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/bugfix.txt @@ -1,3 +1,65 @@ +# bugfix Builder (strict mode) + +You are implementing M10 equivalence fixture — fixed context. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip the 3-way review** — always follow porch next → porch done cycle + +## Protocol +Follow the BUGFIX protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## Issue #9999 +**Title**: fixture + +**Description**: +fixture body + +## Your Mission +1. Reproduce the bug +2. Identify root cause +3. Implement fix (< 300 LOC) +4. Add regression test +5. Create PR with "Fixes #9999" in body +6. Notify architect via `afx send architect "PR #N ready for review (fixes #9999)"` + +If the fix is too complex (> 300 LOC or architectural changes), notify the Architect via: +```bash +afx send architect "Issue #9999 is more complex than expected. [Reason]. Recommend escalating to SPIR." +``` + +## Notifications +Always use `afx send architect "..."` to notify the architect at key moments: +- **PR ready**: `afx send architect "PR #N ready for review (fixes #9999)"` +- **PR merged**: `afx send architect "PR #N merged for issue #9999. Ready for cleanup."` +- **Blocked**: `afx send architect "Blocked on issue #9999: [reason]"` + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the BUGFIX protocol +2. Review the issue details +3. Reproduce the bug before fixing + +--- + +## Protocol Reference (full text) + # BUGFIX Protocol > Lightweight, issue-driven protocol for minor bug fixes. **Investigate → Fix → PR**, with a single `pr` gate before merge. No spec or plan artifacts: the GitHub issue is the spec, and the review goes in the PR body. @@ -75,4 +137,4 @@ builder/bugfix-- | Cannot reproduce | Document the attempts in an issue comment, ask the reporter for detail, notify the architect | | Fix outgrows scope (architectural / multi-component / > ~300 LOC) | Notify the architect, recommend escalation; do not proceed | | Unrelated test failures | Out of scope: note them for the architect, do not fix them here | -| Multiple bugs in one issue | Fix only the primary bug; file separate issues for the rest | +| Multiple bugs in one issue | Fix only the primary bug; file separate issues for the rest | \ No newline at end of file diff --git a/codev/protocols/experiment/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/experiment.txt similarity index 50% rename from codev/protocols/experiment/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/experiment.txt index b9eabaac3..07b57b9f7 100644 --- a/codev/protocols/experiment/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/experiment.txt @@ -1,3 +1,70 @@ +# experiment Builder (strict mode) + +You are executing a disciplined experiment. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip the 3-way review** — always follow porch next → porch done cycle + +## Protocol +Follow the EXPERIMENT protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## EXPERIMENT Overview +The EXPERIMENT protocol ensures disciplined experimentation: + +1. **Hypothesis Phase**: Define what you're testing and success criteria +2. **Design Phase**: Plan the experiment approach +3. **Execute Phase**: Run the experiment and gather data +4. **Analyze Phase**: Evaluate results and draw conclusions + +## Key Principles +- Start with a clear, falsifiable hypothesis +- Define success/failure criteria upfront +- Keep scope minimal for quick iteration +- Document findings regardless of outcome +- Separate experiment artifacts from production code + +## If You Open a PR + +Most experiments are committed to a branch without a PR, but if you do open one +to integrate findings and the experiment was triggered by a GitHub issue: + +**PR body requirements**: The PR body MUST include `Closes #` (for feature +issues) or `Fixes #` (for bug issues) for the driving issue so GitHub +auto-closes it on merge. If the PR closes multiple issues, include one keyword +per issue. + +**Exception**: if this PR only partially addresses the issue (e.g. experiment +validates an approach but production implementation is deferred), use +`Refs #` or `Part of #` instead — the issue stays open until a follow-up +PR closes it. + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the EXPERIMENT protocol document +2. Define your hypothesis clearly +3. Follow the phases in order + +--- + +## Protocol Reference (full text) + # EXPERIMENT Protocol ## Overview @@ -10,7 +77,7 @@ Disciplined experimentation: Each experiment gets its own directory with `notes. **Use for**: Testing approaches, evaluating models, prototyping, proof-of-concept work, research spikes -**Skip for**: Production code (use SPIR), simple one-off scripts, well-understood implementations (use TICK) +**Skip for**: Production code (use SPIR), simple one-off scripts ## Structure @@ -129,11 +196,6 @@ Experiment 5 validated that [approach] achieves [results]. See: experiments/5_validation_test/notes.md ``` -### Experiment → TICK -For small, validated changes discovered during experimentation: -- Use TICK for quick implementation -- Reference experiment as justification - ## Numbering Convention Use four-digit sequential numbering (consistent with project list): @@ -205,4 +267,100 @@ Create SPIR spec for production caching implementation. Create `notes.md` with the following content: -{{> protocols/experiment/templates/notes.md}} +# Experiment ####: Name + +**Status**: In Progress | Complete | Disproved | Aborted + +**Date**: YYYY-MM-DD + +## Goal + +What are you trying to learn or test? Be specific about: +- The question you're answering +- The hypothesis you're testing +- Success criteria (how will you know if it worked?) + +## Effort + +**Approximate time spent**: [e.g., "4 hours"] + +*(Optional: Break down into setup, coding, analysis if helpful)* + +## Approach + +Brief description of the approach being tested: +- Key technique or method +- Why this approach was chosen +- Any alternatives considered + +## Environment & Reproduction + +**How to run**: +```bash +# Command to reproduce results +python experiment.py --input data/input/sample.json +``` + +**Dependencies** (if different from main project): +- List any additional packages required +- Or reference: `pip install -r requirements.txt` + +**Environment notes**: +- Python version, key library versions if relevant +- Any seeds or configuration needed for reproducibility + +## Code + +List your experiment files: +- [`experiment.py`](experiment.py) - Brief description +- [Other files as needed] + +## Results + +### Summary + +One-paragraph summary of key findings. + +### Key Findings + +1. **Finding one**: Description and significance +2. **Finding two**: Description and significance +3. **Finding three**: Description and significance + +### Metrics + +| Metric | Value | Notes | +|--------|-------|-------| +| Metric 1 | Value | Context | +| Metric 2 | Value | Context | + +### Output Files + +- `data/output/results.csv` - Raw results data +- `data/output/chart.png` - Visualization of findings + +## What Worked + +- List things that went well +- Approaches that proved effective +- Useful discoveries + +## What Didn't Work + +- Failed approaches (and why) +- Dead ends encountered +- Surprising obstacles + +## Next Steps + +Based on these findings: + +1. **Immediate**: What should happen right after this experiment? +2. **Follow-up experiments**: What new questions emerged? +3. **Production path**: If validated, what's needed for production? (SPIR spec?) + +## References + +- Links to relevant documentation +- Related experiments +- External resources consulted \ No newline at end of file diff --git a/codev/protocols/maintain/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/maintain.txt similarity index 84% rename from codev/protocols/maintain/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/maintain.txt index 7e91d118d..86d34d1b2 100644 --- a/codev/protocols/maintain/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/maintain.txt @@ -1,3 +1,55 @@ +# maintain Builder (strict mode) + +You are executing the MAINTAIN protocol to clean up and synchronize the codebase. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) + +## Protocol +Follow the MAINTAIN protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## MAINTAIN Overview + +Two phases: +1. **Maintain**: Single pass — audit findings, clean dead code, sync docs, verify build +2. **Review**: Create PR with 3-way consultation + +## Key Rules +- Use soft deletion (move to `codev/maintain/.trash/`) +- Verify build passes after each removal (`cd packages/codev && pnpm build && pnpm test`) +- Update documentation to match current architecture +- Don't remove anything actively used +- One removal at a time — commit after each +- Document every deletion with justification +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the MAINTAIN protocol document +2. Run `porch next` to get your first task +3. Work through audit → clean → sync → verify in a single pass +4. Document everything in the maintenance run file + +--- + +## Protocol Reference (full text) + # MAINTAIN Protocol ## Overview @@ -105,7 +157,7 @@ For each finding from the audit: - One removal at a time — don't batch unrelated changes - Verify after each removal — build must pass - Use soft deletion for untracked files: `mv file codev/maintain/.trash/$(date +%Y-%m-%d)/` -- Never use `git add -A` or `git add .` +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. ### Step 3: Sync Documentation @@ -281,4 +333,4 @@ If maintenance reveals need for architectural changes, those should follow SPIR. 4. Removing "patterns" or "best practices" sections without explicit approval 5. Deleting everything the audit finds — review each item individually 6. Skipping validation — "it looked dead" is not validation -7. Using `rm` instead of `git rm` +7. Using `rm` instead of `git rm` \ No newline at end of file diff --git a/codev/protocols/pir/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/pir.txt similarity index 71% rename from codev/protocols/pir/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/pir.txt index b3befc173..219f0df3d 100644 --- a/codev/protocols/pir/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/pir.txt @@ -1,3 +1,87 @@ +# pir Builder (strict mode) + +You are implementing a fix or feature driven by a GitHub issue, using the PIR protocol. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals +- Do not deviate from the porch-driven workflow + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip consultations** — porch handles them via the verify step +- **NEVER advance phases manually** — porch handles phase transitions on gate approval + +## Protocol +Follow the PIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +PIR has three phases: +1. **plan** (gated by `plan-approval`) — write `codev/plans/.md`, await human review +2. **implement** (gated by `dev-approval`) — write code + tests, run build/tests, push branch; await the human's review of the *running worktree* (no file artifact in this phase — dev-approval summary is prose-in-pane) +3. **review** (gated by `pr`) — write `codev/reviews/.md` (retrospective with Architecture Updates and Lessons Learned sections), open PR with the review as body, record the PR with porch, run 3-way consultation (Gemini, Codex, Claude) via porch's verify block (a **single advisory pass** — `max_iterations: 1`, no iterate-until-APPROVE loop; address or rebut any `REQUEST_CHANGES`, add a regression test if it's a real defect, and escalate it in the architect notification since PIR will not re-review it), notify architect, and wait at the `pr` gate. After the human approves the gate (porch wakes you with "Gate pr approved"), run `gh pr merge --merge` and record the merge with `porch done --merged `. **Merge is gated by porch state — never by typed prose in your pane.** + +## Issue #9999 +**Title**: fixture + +**Description**: +fixture body + +## Sitting at Gates + +PIR has two human gates. When you reach one: + +1. Finish your phase work and run `porch done ` +2. Run `porch next ` — you'll get a `gate_pending` response +3. End your turn with a short prose summary: what file you wrote, where it lives, how to approve +4. **Stay in the interactive session**. Do NOT exit. Wait for the user's next message. + +The reviewer can give feedback by: +- Editing the plan file (at the plan-approval gate) or the code itself (at the dev-approval gate) in the worktree directly — you'll see changes via `git diff` +- Typing into your PTY pane (this reaches you live) +- `afx send ""` (queued; check on next turn) +- Commenting on the GitHub issue (re-fetch with `gh issue view --comments` if asked) + +When the user provides feedback, revise the artifact, recommit, and ask if there's more to address. The gate remains pending until the user runs `porch approve` — do NOT call `porch approve` yourself. + +## Notifications +Use `afx send architect "..."` at key moments: +- **PR ready**: `afx send architect "PR # ready for review (PIR #9999)"` +- **PR merged**: `afx send architect "PR # merged for PIR #9999. Ready for cleanup."` +- **Blocked**: `afx send architect "Blocked on PIR #9999: [reason]"` + +**Gates are not architect-notified.** When porch transitions a gate to `pending`, the gate-reached message (including the `porch approve --a-human-explicitly-approved-this` invocation) appears in YOUR pane as part of your normal output. That's the universal notification surface — visible whether the user is in VSCode, tmux, plain Terminal, or any other host. The user reads it directly from your pane (or runs `porch pending` from a shell) and approves themselves; the architect can't approve gates, so notifying it would be informational noise. + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Resumption After Crash + +If your Claude session crashes mid-flow, Tower's `while true` loop will relaunch you with the same prompt. On startup: + +1. Run `porch next 9999` to learn what phase you're in +2. If `gate_pending`: read the latest plan file (plan-approval) or `DEFAULT_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||'); git diff "$(git merge-base "${DEFAULT_BRANCH:-main}" HEAD)"` (dev-approval) plus any new GitHub issue comments; check `afx send` queue. Decide whether to revise or just announce you're back. +3. Otherwise: pick up where you left off + +## Getting Started + +1. Read the PIR protocol (provided inline in this prompt). +2. Run `porch next 9999` to see what to do next +3. Begin work + +--- + +## Protocol Reference (full text) + # PIR Protocol > **Plan → Implement → Review** for GitHub-issue-driven work that needs human review of *either* the approach (before code is written) *or* the implementation (before a PR exists), or both. Lighter than SPIR/ASPIR (no `specify` phase — the GitHub issue is the implicit spec) with the human dev-approval moved earlier (pre-PR instead of post-PR). Stronger than BUGFIX/AIR (two human gates before the PR). @@ -199,4 +283,4 @@ codev/reviews/-.md # written in review phase (post-dev-appro codev/projects/-/status.yaml # porch state, managed automatically ``` -The plan and review files ship to `main` with the merged PR — durable, searchable, git-versioned. The review file includes Summary + Architecture Updates + Lessons Learned + supporting sections, so `codev/reviews/` stays semantically consistent across protocols. +The plan and review files ship to `main` with the merged PR — durable, searchable, git-versioned. The review file includes Summary + Architecture Updates + Lessons Learned + supporting sections, so `codev/reviews/` stays semantically consistent across protocols. \ No newline at end of file diff --git a/codev/protocols/research/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/research.txt similarity index 69% rename from codev/protocols/research/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/research.txt index 2c2e8ec02..1706beeff 100644 --- a/codev/protocols/research/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/research.txt @@ -1,3 +1,79 @@ +# research Builder (strict mode) + +You are conducting multi-agent research. + +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals + +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip the 3-way consultation** — always follow porch next → porch done cycle + +## Protocol +Follow the RESEARCH protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## RESEARCH Overview + +The RESEARCH protocol produces a high-confidence research report through triangulation: + +1. **Scope** — Define the precise question, scope, and acceptance criteria. Write a research brief. Gate: architect approval before proceeding. +2. **Investigate** — Dispatch the brief to 3 models (Gemini, Codex, Claude) in parallel. Each investigates independently. No anchoring — they don't see each other's work. +3. **Synthesize** — Read all 3 reports. Identify consensus, disagreements, and unique contributions. Write a single synthesis report organized by topic (not by model). +4. **Critique** — Send the synthesis back to all 3 models for critique. Incorporate valid feedback. Document rejected critique. Finalize the report. + +## Output Location + +All artifacts go to `codev/research/`: +- `-brief.md` — the scoped question (Phase 1) +- `-gemini.md`, `-codex.md`, `-claude.md` — individual investigations (Phase 2) +- `.md` — the final synthesis report (Phase 3+4, this is the deliverable) +- `-critique-rebuttals.md` — critique responses (Phase 4) + +## Key Principles + +- **Triangulate**: consensus across 3 models > any single model's claim +- **Cite sources**: tell investigators to provide sources where possible +- **Be candid about uncertainty**: "I don't know" > confabulation +- **Organize by topic, not by model**: the synthesis is a standalone document +- **Note surprises**: the most valuable findings are often unexpected +- **Keep it concise**: the synthesis should be shorter than the sum of the investigations + +## Using consult for 3-way Investigation + +For the investigate phase, use the `consult` CLI to dispatch to each model: + +```bash +# Phase 2: parallel investigation +consult -m gemini --prompt-file codev/research/-brief.md --output codev/research/-gemini.md & +consult -m codex --prompt-file codev/research/-brief.md --output codev/research/-codex.md & +consult -m claude --prompt-file codev/research/-brief.md --output codev/research/-claude.md & +wait +``` + +For the critique phase: +```bash +# Phase 4: parallel critique +consult -m gemini --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-gemini.md & +consult -m codex --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-codex.md & +consult -m claude --prompt "Critique this research synthesis for gaps, errors, and bias:" --prompt-file codev/research/.md --output codev/research/-critique-claude.md & +wait +``` + +## Getting Started +1. Read the RESEARCH protocol document +2. Understand the research question from the architect +3. Write the research brief (Phase 1) +4. Wait for scope-approval before proceeding to investigation + +--- + +## Protocol Reference (full text) + # RESEARCH Protocol ## Overview @@ -166,4 +242,4 @@ When research identifies something worth testing: - All investigation reports (for traceability) - The final synthesis (the deliverable) - The critique rebuttals (for process transparency) -- Do NOT commit raw web search results or intermediate notes +- Do NOT commit raw web search results or intermediate notes \ No newline at end of file diff --git a/codev/protocols/spike/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/spike.txt similarity index 51% rename from codev/protocols/spike/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/spike.txt index 9b121d4cc..65dcd9847 100644 --- a/codev/protocols/spike/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/spike.txt @@ -1,3 +1,57 @@ +# spike Builder (strict mode) + +You are executing a time-boxed technical feasibility spike. + +## Protocol +Follow the SPIKE protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. + +## Recommended Workflow + +Follow this 3-step workflow. You can skip or reorder steps as the investigation demands. + +### 1. Research +- Read documentation, examine existing code, search for prior art +- Identify constraints, dependencies, and potential blockers +- Understand the problem space before writing any code + +### 2. Iterate +- Build minimal proof-of-concept code to test approaches +- Focus on answering the feasibility question, not building production code +- POC code doesn't need tests or polish +- **Skip this step** if the answer is clear from research alone + +### 3. Findings +- Write findings to `codev/spikes/-.md` using the template +- Provide a clear feasibility verdict: Feasible / Not Feasible / Feasible with Caveats +- Commit the findings document +- Notify the architect: `afx send architect "Spike complete. Verdict: [verdict]"` + +## Key Principles + +- **Time-boxing**: Stay focused on the question. Don't explore tangents. +- **Exploration over perfection**: POC code doesn't need tests or polish. +- **Clear output**: The findings document is the deliverable, not the code. +- **Know when to stop**: Once you can answer the feasibility question, write findings and stop. Don't keep iterating. +- **Document failures**: "Not feasible" is a valid and valuable finding. + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the SPIKE protocol document +2. Understand the question you're investigating +3. Start with research — don't jump straight to code + +--- + +## Protocol Reference (full text) + # SPIKE Protocol ## Overview @@ -10,7 +64,7 @@ Time-boxed technical feasibility exploration. Answer "Can we do X?" and "What wo **Use for**: Quick technical feasibility investigations, proof-of-concept explorations, "can we do X?" questions, evaluating approaches before committing to SPIR -**Skip for**: Production code (use SPIR), formal hypothesis testing (use EXPERIMENT), bug fixes (use BUGFIX), well-understood implementations (use TICK) +**Skip for**: Production code (use SPIR), formal hypothesis testing (use EXPERIMENT), bug fixes (use BUGFIX) ### Spike vs Experiment @@ -125,4 +179,70 @@ When a spike finds something is not feasible: Write the findings document using the following template: -{{> protocols/spike/templates/findings.md}} +# Spike: [Title] + +**Date**: YYYY-MM-DD + +**Verdict**: Feasible | Not Feasible | Feasible with Caveats + +## Question + +What technical question was being investigated? Be specific: +- What are you trying to determine? +- What prompted this investigation? +- What decision depends on the answer? + +## Research Summary + +What was explored during the research phase: +- Documentation read +- Existing code examined +- Prior art found +- Key constraints identified + +## Approaches Tried + +What was built or tested during the iterate phase: + +### Approach 1: [Name] +- **What**: Brief description of what was tried +- **Result**: What happened +- **Verdict**: Worked / Didn't work / Partially worked + +### Approach 2: [Name] +*(Add more approaches as needed, or remove if research alone answered the question)* + +## Constraints Discovered + +Technical limitations, dependencies, and gotchas found during the investigation: +- [Constraint 1] +- [Constraint 2] + +## Recommended Approach + +*(If feasible)* How should full implementation proceed? +- Recommended library/technique/pattern +- Key architectural decisions +- Things to watch out for + +*(If not feasible)* Why not, and what alternatives exist? + +## Effort Estimate + +Rough sizing for a full SPIR project: **Small** | **Medium** | **Large** + +- Small: < 300 LOC, 1-2 files, straightforward +- Medium: 300-1000 LOC, multiple files, some complexity +- Large: 1000+ LOC, architectural changes, significant complexity + +## Next Steps + +- [ ] [Recommended action — e.g., "Create SPIR spec for WebSocket integration"] +- [ ] [Or: "Do not pursue — blocked by X"] +- [ ] [Or: "Investigate Y further before deciding"] + +## References + +- [Link to relevant documentation] +- [Link to relevant code/commits] +- [Link to external resources consulted] \ No newline at end of file diff --git a/codev/protocols/spir/protocol.md b/packages/codev/src/__tests__/fixtures/prompt-snapshots/spir.txt similarity index 77% rename from codev/protocols/spir/protocol.md rename to packages/codev/src/__tests__/fixtures/prompt-snapshots/spir.txt index f51ae04a9..e9114dd58 100644 --- a/codev/protocols/spir/protocol.md +++ b/packages/codev/src/__tests__/fixtures/prompt-snapshots/spir.txt @@ -1,74 +1,114 @@ -# SPIR Protocol +# spir Builder (strict mode) +You are implementing M10 equivalence fixture — fixed context. -## Prerequisites +## Mode: STRICT +You are running in STRICT mode. This means: +- Porch orchestrates your work +- Run: `porch next` to get your next tasks +- Follow porch signals and gate approvals +- Do not deviate from the porch-driven workflow -**Required for Multi-Agent Consultation**: -- The `consult` CLI must be available (installed with `npm install -g @cluesmith/codev`) -- At least one consultation backend: `claude`, `gemini-cli`, or `codex` -- Check with: `codev doctor` or `consult --help` +### ABSOLUTE RESTRICTIONS (STRICT MODE) +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) +- **NEVER skip the 3-way review** — always follow porch next → porch done cycle +- **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval -## Protocol Configuration +## Protocol +Follow the SPIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. -### Porch Orchestration (RECOMMENDED) +## Baked Decisions -Porch is the protocol orchestrator that enforces phase transitions, manages human approval gates, and coordinates multi-agent consultations. Using porch is the recommended way to execute SPIR. +If the issue body contains a section named "Baked Decisions" (any heading level, case-insensitive), treat its contents as fixed architectural decisions baked in by the architect. Do not autonomously override them in your spec, plan, or implementation. If you discover a serious reason to question a baked decision, surface that concern to the architect via `afx send` rather than relitigating it inside the spec/plan/review. -**HOW IT WORKS:** -1. Initialize porch for your project: `porch init spir ` -2. Run the protocol loop: `porch run ` -3. Porch orchestrates Claude sessions for each phase -4. Human gates block until approved: `porch approve ` +If the architect's baked-decisions section contains internal contradictions (e.g., two different language choices), do not pick one — pause, flag the contradiction to the architect via `afx send`, and wait for resolution before proceeding. -**STATE FILE LOCATION:** -`codev/projects/-/status.yaml` +## Issue #9999 +**Title**: fixture -**PORCH COMMANDS:** -```bash -# Initialize a new SPIR project -porch init spir 0073 "user-auth" +**Description**: +fixture body -# Start the protocol loop (orchestrates Claude for each phase) -porch run 0073 +## PR Strategy -# Check status -porch status 0073 +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. -# Approve a human gate -porch approve 0073 spec_approval +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. -# List pending gates across all projects -porch pending -``` +### Architect-requested PRs -**HUMAN GATES:** -- `spec_approval`: After specification is ready for planning -- `plan_approval`: After plan is ready for implementation +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. -When a gate is reached, porch notifies the architect and blocks until approved. +### Multi-PR Mechanics (when the architect requests sequential PRs) -**USING AF SPAWN (Architect-Builder Pattern):** -```bash -# Create worktree and start porch-driven builder (default) -afx spawn -p 0073 +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: -# Or for flexible, protocol-guided work (soft mode) -afx spawn --soft -p 0073 +1. Cut a branch, open a PR, wait for merge +2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) +3. Continue to the next slice, open another PR +4. Repeat -# Monitor builder status -afx status +**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. -# Approve gates via dashboard or CLI -porch approve 0073 spec_approval -``` +Record PRs in status.yaml: `porch done 9999 --pr --branch ` +Record merges: `porch done 9999 --merged ` -**MANUAL EXECUTION (without porch):** -You can still execute SPIR manually by following this document. Use signals to communicate phase completion to porch if running in orchestrated mode: -``` -SPEC_DRAFTED -PLAN_DRAFTED -PHASE_COMPLETE -``` +## Verify Phase + +After the final PR merges, the project enters the **verify** phase. You stay alive through verify: +1. Pull the integration branch into your worktree +2. Run `porch done 9999` to signal verification is ready +3. The architect approves `verify-approval` when satisfied + +If verification is not needed: `porch verify 9999 --skip "reason"` + +## Notifications +Always use `afx send architect "..."` to notify the architect at key moments: +- **Gate reached**: `afx send architect "Project 9999: ready for approval"` +- **PR ready**: `afx send architect "PR #N ready for review (project 9999)"` +- **PR merged**: `afx send architect "Project 9999 PR merged. Entering verify phase."` +- **Blocked**: `afx send architect "Blocked on project 9999: [reason]"` + +## Handling Flaky Tests + +If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): +1. Never hand-edit `status.yaml` — only porch commands modify project state. +2. **DO NOT** skip porch checks or use any workaround to avoid the failure +3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) +5. Commit the skip and continue with your work + +## Getting Started +1. Read the protocol document thoroughly +2. Review the spec and plan (if available) +3. Begin implementation following the protocol phases + +--- + +## Protocol Reference (full text) + +# SPIR Protocol + +> **SPIR** = **S**pecify → **P**lan → **I**mplement → **R**eview +> +> Each phase has one build-verify cycle with 3-way consultation. + +## Prerequisites + +**Clean Worktree Before Spawning Builders**: +- All specs, plans, and local changes **MUST be committed** before `afx spawn` +- Builders work in git worktrees branched from HEAD — uncommitted files are invisible +- This includes `codev update` results, spec drafts, and plan approvals +- The `afx spawn` command enforces this (use `--force` to override) + +**Required for Multi-Agent Consultation**: +- The `consult` CLI must be available (installed with `npm install -g @cluesmith/codev`) +- At least one consultation backend: `claude`, `gemini-cli`, or `codex` +- Check with: `codev doctor` or `consult --help` + +## Protocol Configuration ### Multi-Agent Consultation (ENABLED BY DEFAULT) @@ -101,6 +141,14 @@ The user can specify different agents by saying: "use SPIR with consultation fro ## Overview SPIR is a structured development protocol that emphasizes specification-driven development with iterative implementation and continuous review. It builds upon the DAPPER methodology with a focus on context-first development and multi-agent collaboration. +**The SPIR Model**: +- **S - Specify**: Write specification with 3-way review → Gate: `spec-approval` +- **P - Plan**: Write implementation plan with 3-way review → Gate: `plan-approval` +- **I - Implement**: Execute each plan phase with build-verify cycle (one cycle per phase) +- **R - Review**: Final review and PR preparation with 3-way review + +Each phase follows a build-verify loop: build the artifact, then verify with 3-way consultation (Gemini, Codex, Claude). + **Core Principle**: Each feature is tracked through exactly THREE documents - a specification, a plan, and a review with lessons learned - all sharing the same filename and sequential identifier. ## When to Use SPIR @@ -143,13 +191,7 @@ When filing an issue for SPIR, you can pin architectural decisions you don't wan 10. Multi-agent review of updated document 11. Final updates based on second review 12. **COMMIT**: "Final approved specification" - - Add YAML frontmatter: `approved: ` and `validated: [gemini, codex, claude]` - - Commit to the integration branch (the branch builders branch off) so builder worktrees include the artifact - - Porch will detect this metadata and skip the specify phase automatically -13. **GATE CHECK**: Before proceeding to Plan, verify all `spec_*` items complete - - If incomplete: Output "⚠️ BLOCKED" with missing items, stop - - If complete: Output "✓ Gate passed", update state, proceed -14. Iterate steps 7-12 until user approves and says to proceed to planning +13. Iterate steps 7-12 until user approves and says to proceed to planning **Important**: Keep documentation minimal - use only THREE core files with the same name: - `specs/####-descriptive-name.md` - The specification @@ -238,14 +280,7 @@ When filing an issue for SPIR, you can pin architectural decisions you don't wan 9. Multi-agent review of updated plan 10. Final updates based on second review 11. **COMMIT**: "Final approved plan" - - Add YAML frontmatter: `approved: ` and `validated: [gemini, codex, claude]` - - Commit to the integration branch (the branch builders branch off) so builder worktrees include the artifact - - Porch will detect this metadata and skip the plan phase automatically -12. **REGISTER PHASES**: For each phase defined in the plan: -13. **GATE CHECK**: Before proceeding to Implement, verify all `plan_*` items complete - - If incomplete: Output "⚠️ BLOCKED" with missing items, stop - - If complete: Output "✓ Gate passed", update state, proceed -14. Iterate steps 6-11 until agreement is reached +12. Iterate steps 6-11 until agreement is reached **Phase Design Goals**: Each phase should be: @@ -300,30 +335,21 @@ Each phase should be: **Structure**: follows the plan template provided by the plan phase **Review Required**: Yes - Technical lead approval AFTER consultations -### (IDE) - Implementation Loop - -Execute for each phase in the plan. This is a strict cycle that must be completed in order. +### I - Implement (Per Plan Phase) -**⚠️ MANDATORY**: The I-D-E cycle MUST be completed for EACH PHASE, not just at the end of all phases. Skipping D (Defend) or E (Evaluate) for any phase is a PROTOCOL VIOLATION. +Execute for each phase in the plan. Each phase follows a build-verify cycle. **CRITICAL PRECONDITION**: Before starting any phase, verify the previous phase was committed to git. No phase can begin without the prior phase's commit. -**Phase Completion Process**: -1. **Implement** - Build the code for this phase - - **GATE CHECK**: Before Defend, verify all Implement items complete -2. **Defend** - Write comprehensive tests that guard functionality - - **GATE CHECK**: Before Evaluate, verify all Defend items complete -3. **Evaluate** - Assess and discuss with user +**Build-Verify Cycle Per Phase**: +1. **Build** - Implement code and tests for this phase +2. **Verify** - 3-way consultation (Gemini, Codex, Claude) +3. **Iterate** - Address feedback until verification passes 4. **Commit** - Single atomic commit for the phase (MANDATORY before next phase) 5. **Proceed** - Move to next phase only after commit - - **GATE CHECK**: Verify all items for current phase complete - - If more phases: Proceed to next phase's Implement stage - - If last phase: Proceed to Review **Handling Failures**: -- If **Defend** phase reveals gaps → return to **Implement** to fix -- If **Evaluation** reveals unmet criteria → return to **Implement** -- If user requests changes → return to **Implement** +- If verification reveals gaps → iterate and fix - If fundamental plan flaws found → mark phase as `blocked` and revise plan **Commit Requirements**: @@ -615,19 +641,15 @@ Execute for each phase in the plan. This is a strict cycle that must be complete - Same filename as spec/plan, captures review and learnings from this feature - Methodology improvement proposals (update protocol if needed) -**FINAL GATE CHECK**: Before marking project complete, verify all `review_*` items complete -- If incomplete: Output "⚠️ BLOCKED" with missing items -- If complete: Output "✓ SPIR protocol complete for project [id]" - **Review Required**: Yes - Team retrospective recommended ## File Naming Conventions ### Specifications and Plans Format: `####-descriptive-name.md` -- Use sequential numbering (0001, 0002, etc.) +- Use sequential numbering (1, 2, etc.) - Same filename in both `specs/` and `plans/` directories -- Example: `0001-user-authentication.md` +- Example: `1-user-authentication.md` ## Status Tracking @@ -650,10 +672,10 @@ For specification/plan documents: Examples: ``` -[Spec 0001] Initial specification draft -[Spec 0001] Specification with multi-agent review -[Spec 0001] Specification with user feedback -[Spec 0001] Final approved specification +[Spec 1] Initial specification draft +[Spec 1] Specification with multi-agent review +[Spec 1] Specification with user feedback +[Spec 1] Final approved specification ``` For implementation: @@ -665,7 +687,7 @@ For implementation: Example: ``` -[Spec 0001][Phase: user-auth] feat: Add password hashing service +[Spec 1][Phase: user-auth] feat: Add password hashing service Implements bcrypt-based password hashing with configurable rounds ``` @@ -677,10 +699,9 @@ spir/####-/ Example: ``` -spir/0001-user-authentication/database-schema +spir/1-user-authentication/database-schema ``` - ## Best Practices ### During Specification diff --git a/packages/codev/src/__tests__/fixtures/shadow-drift-allowlist.ts b/packages/codev/src/__tests__/fixtures/shadow-drift-allowlist.ts new file mode 100644 index 000000000..28090c7a6 --- /dev/null +++ b/packages/codev/src/__tests__/fixtures/shadow-drift-allowlist.ts @@ -0,0 +1,67 @@ +/** + * Adjudication allowlist for the shadow-drift CI gate (Spec 1252, M2). + * + * The gate (`shadow-drift-gate.test.ts`) fails the build on any `differs` + * finding from `auditProtocolDrift()` that is not listed here. + * + * ## Why this file starts populated + * + * At Phase 1 the tree is already dirty: 17 shadow copies drifted from the + * skeleton, and one of them (`protocols/spir/builder-prompt.md`) is why this + * project exists — the served SPIR builder prompt lost its `Verify Phase` and + * `Multi-PR Mechanics` sections. A gate that fails on the commit that + * introduces it is a gate someone disables, so the known drift is admitted + * here with an explicit justification and removed in Phase 3. + * + * ## Lifecycle (M2, tightened after Gemini's iteration-2 review) + * + * Every entry carries a `reason`. Entries whose reason is `PENDING_RECONCILE` + * MUST be gone once Phase 3 completes — `expectNoPendingReconcileAfterPhase3` + * in the gate test enforces that, so the allowlist cannot quietly become a + * permanent exemption. The only residue permitted after Phase 3 is a file with + * an open M11 escalation (`reason: 'ESCALATED'`), which must cite its + * adjudication. + * + * Do NOT add entries to make a red build green. Adding one is an assertion + * that a human adjudicated the divergence. + */ + +/** Why a drifted shadow copy is temporarily tolerated. */ +export type AllowReason = + /** Known pre-existing drift, to be reconciled in Phase 3 per decision D1. */ + | 'PENDING_RECONCILE' + /** Local-unique content escalated under M11; awaiting an architect ruling. */ + | 'ESCALATED' + /** Architect ruled TS3: deliberate codev-only override, kept by decision. */ + | 'TS3_RETAINED'; + +export interface AllowEntry { + /** Skeleton-relative path exactly as `DriftFinding.relativePath` reports it. */ + relativePath: string; + reason: AllowReason; + /** Free text: for ESCALATED/TS3_RETAINED, cite the adjudication. */ + note: string; +} + +/** + * Phase-1 seeded 17 PENDING_RECONCILE entries (the drift present when the gate + * was introduced); Phase 3 reconciled 13 of them to the skeleton and removed + * their entries. What remains is exactly the 4 open M11 escalations. + * + * Populated from the audit's own output rather than hand-transcribed from + * `diff -rq`, because the audit compares against the *installed skeleton* + * (`getSkeletonDir()`), which is a build-time copy of `codev-skeleton/` — the + * two can disagree if the skeleton has not been rebuilt. + */ +export const SHADOW_DRIFT_ALLOWLIST: AllowEntry[] = [ + // EMPTY — and staying that way is the point. Phase 3 reconciled 13 rot + // files; Phase 4 resolved all four escalations by architect ruling + // (2026-07-28: max_iterations -> skeleton's 3; cwd -> .codev/config.json + // porch.checks) and deleted the shadow tree. Any future entry requires a + // human-adjudicated justification. +]; + +/** Allowlisted paths as a Set, for O(1) gate lookups. */ +export const ALLOWLISTED_PATHS: ReadonlySet = new Set( + SHADOW_DRIFT_ALLOWLIST.map((e) => e.relativePath) +); diff --git a/packages/codev/src/__tests__/fixtures/shadow-removal-manifest.json b/packages/codev/src/__tests__/fixtures/shadow-removal-manifest.json new file mode 100644 index 000000000..fc95da723 --- /dev/null +++ b/packages/codev/src/__tests__/fixtures/shadow-removal-manifest.json @@ -0,0 +1,79 @@ +{ + "consult-types/integration-review.md": "f1137ec6e42e001337a32a08ffd05f3cb546f1016975f68a0efd2b1d1c04fb07", + "protocols/air/builder-prompt.md": "22af1a0362c7df35ca98128997f3c8a659649e6e4c78f394ab483927c2850e02", + "protocols/air/consult-types/impl-review.md": "e2bb89001910d703779c13a145f082af98393f051150eff4c6f96796e37bc1ea", + "protocols/air/consult-types/pr-review.md": "c009fca302ef73ada9ab457ed0aab22d89ef99d6de255c1f874ab0384d375b51", + "protocols/air/prompts/implement.md": "182e8960399a39a781076c7fd51143a408faca9fa4eb96b76e116ba87779c312", + "protocols/air/prompts/pr.md": "df18aa9bdc593de52f1763bb03a7297648995354525801e591e8e0b38d68b9b3", + "protocols/air/protocol.json": "92eec229f4406a27bab90a316c21b14b15b46b530550c4c92e043ce1c2ba8bed", + "protocols/air/protocol.md": "ee174cebafdf8b45b4f348d0f1debe0e5e9706f0a99a177377f2c23e61a155e9", + "protocols/aspir/builder-prompt.md": "6651ed37fd1510d612bf5385ca4a21d625079daad0b09f82b2edcbc1aefcc058", + "protocols/aspir/consult-types/impl-review.md": "e23d51f2027d0b1492c5db7350dd0cade6d60e9c51617b4a87f8ec9f152e195a", + "protocols/aspir/consult-types/phase-review.md": "e23d51f2027d0b1492c5db7350dd0cade6d60e9c51617b4a87f8ec9f152e195a", + "protocols/aspir/consult-types/plan-review.md": "f56e92e8bee3473894547ba22eb3b075dedffebdd25cb4afa0d7ac5323199a32", + "protocols/aspir/consult-types/pr-review.md": "8734bbec0d412318aed817a6ffab3beddcbf680c728144c185741214d1373bb8", + "protocols/aspir/consult-types/spec-review.md": "dff57d066ca23572e8e0286ac74755cf26cf8f458f262b0d4a9320e5bde43600", + "protocols/aspir/prompts/implement.md": "32099ccc0915937b27594b0731a645ff7a8c2e36d6222f6ab3cedd163ae80b8f", + "protocols/aspir/prompts/plan.md": "5c880c4bbc45e4b385822233c65ab8381092fb19495b0d2a5222286825094846", + "protocols/aspir/prompts/review.md": "2c74c200317c0702500195756b933e84ebdf6268f913e63979aca9578a116494", + "protocols/aspir/prompts/specify.md": "539187cb3ea71a4f52bf2445d7e9cb8b3db61f97f11eb6b10e28398f23ec2f3a", + "protocols/aspir/protocol.json": "4191e69de01731e05a208c7e8b706d9c384f9a829693d4ab3e132a067d960dc0", + "protocols/aspir/protocol.md": "d03d6d9ecb64d661d25deb8907006482adbc2db176d6628adaccad18873de703", + "protocols/aspir/templates/plan.md": "3ddb80a3930487dd99cdb4d1f58815be83fb03ce88ae5278f7ca46e11c9a77a8", + "protocols/aspir/templates/review.md": "68e0b3cdd63437943aa360a9da71fd50dae2d5dd97e2b1b30e932e7ab04dbd20", + "protocols/aspir/templates/spec.md": "07237c211743814750576da0ba2755fd142c95d583380d3c52d23cc08e7f7b35", + "protocols/bugfix/builder-prompt.md": "c3727cebb54bdd50d6e506dab98966e46ba301d32d84f18ecb840579ab01ef66", + "protocols/bugfix/consult-types/impl-review.md": "e1675e3a8c031f1cc9c94fd36c1fde7652c760c35c7fad9459a5c2a4b208832f", + "protocols/bugfix/consult-types/pr-review.md": "373a39c1fc3291cd2318b2f146097d49f00dbf2e77f374d48a8eca33a9bddcb1", + "protocols/bugfix/prompts/fix.md": "671c46bcec692ff7b5fe63e61f042fcba1a52c7b6bf79df262f22f32b88668a3", + "protocols/bugfix/prompts/investigate.md": "ea4a357896e681dd7331752bfb92e3f1430b43b6ed805d26c5832ea2d4f511ef", + "protocols/bugfix/prompts/pr.md": "bea1836850fd2e1805ad4cbf2dbc12dfd58618468352deecd4d10552dc7c68dd", + "protocols/bugfix/protocol.json": "9388d839aab610e1d0ac33de76229c0a162da1569d5c1c75120212bdd027dc95", + "protocols/bugfix/protocol.md": "85b9e11ce6d933563f239e94c8d4b695aed5021283bf051a8f70359252897c2f", + "protocols/experiment/builder-prompt.md": "e2cb7bdca886c8f8c5aa84dee2eef6d10e1c798fdf0961b9ba1df5a65fe3ae9e", + "protocols/experiment/protocol.json": "93f4461dee32f1427f8d0343675e78be10f393ff91fffa818fa9df591316f4dc", + "protocols/experiment/protocol.md": "3376b8c61021d9acd67788c47169dd7a434bb5efd458e37584be22db925c0100", + "protocols/experiment/templates/notes.md": "d7b49794a07db3c8175c29c9baf76973416f2a9d9ec133c7429fc37a067dd0d6", + "protocols/maintain/builder-prompt.md": "cac1cf1b362d3a56fcb0d48aa8f4ebe14ae791a4274b34ac1d89e63e970f1582", + "protocols/maintain/consult-types/impl-review.md": "e23d51f2027d0b1492c5db7350dd0cade6d60e9c51617b4a87f8ec9f152e195a", + "protocols/maintain/consult-types/pr-review.md": "8734bbec0d412318aed817a6ffab3beddcbf680c728144c185741214d1373bb8", + "protocols/maintain/prompts/maintain.md": "7a090f8dbfaec4f11933fe55bc69157282bc0368284f1fdb450f2f91596ae88b", + "protocols/maintain/prompts/review.md": "9b9b4b9e8485b7a68a22cde5cc7a37bb56d768f2ab38d03ac1e638cdf5eff315", + "protocols/maintain/protocol.json": "bd49c2458ae246ba4a4d20952c732ebffbef25ca1866cb69fc0bc81859833b4e", + "protocols/maintain/protocol.md": "f71ae952551a940405efaf83cbadccf4af8569c2fa40e87485ef84b7c81d743c", + "protocols/maintain/templates/maintenance-run.md": "c6ab24b88aacc8ccd4276ca1a4b1d0c51750af68d7c570ed86ec397c6ceffb67", + "protocols/pir/builder-prompt.md": "b23c7f37ec34eb9d292610855899966e9905c7031edeed3d654652f93c04abb0", + "protocols/pir/consult-types/impl-review.md": "2be180426de767b16f8f47a2d1f12be191de3f3f02740e1064cc8a8381874a9a", + "protocols/pir/consult-types/pr-review.md": "96dde26f33838c1b412657a7840c1eeb68ecd2f7be030e0d1a7baa2d5b35b27c", + "protocols/pir/prompts/implement.md": "b73ce002b0d3851d62099d6041b698be110959400f24be92b49bfe490b449f16", + "protocols/pir/prompts/plan.md": "b0d349a98bae4008467d6dd9b12e9a3ab57cb70b342efaeebc0fc1389529e463", + "protocols/pir/prompts/review.md": "9f989bdb25a54f29253915f73a03b5aae4cff3e536cb4a313957cdf7159a79f5", + "protocols/pir/protocol.json": "c423cd1313e7db66781dc9c8ecf3aeda3e4e2638ea482d0d3e28c863fa32052c", + "protocols/pir/protocol.md": "defa969ac7836b24ba1004d4330b78cc8ec5d09a240672694c2374edc6df12df", + "protocols/protocol-schema.json": "a6fca1a82326c57187d6fcbb0d27b51549bd3ec67462e8aec0e5a875b53cff78", + "protocols/research/builder-prompt.md": "a298d59928ef48c8941db796f7d36734492181919d7237688e51a68d2eaa706e", + "protocols/research/protocol.json": "4131193777808d1502c7860192e359ba789ab79d8607293092aff7b0f47e9cc3", + "protocols/research/protocol.md": "78f7a4daa8354d3e859e1977d259644eed2ecc599f7cffc73226584828184c71", + "protocols/spike/builder-prompt.md": "604ec4d1e54ee1d85e6515c88ede48f38ab8301372d8ce1144a38f85f0990a03", + "protocols/spike/protocol.json": "f6948f3e5159fbabbe2cfc869a9d910f9e20b4638c3828225f065f5ee36cc858", + "protocols/spike/protocol.md": "40f9cbf4ed54258d954c87a4ced54a94febed3db1e268a30b791d610b5996a53", + "protocols/spike/templates/findings.md": "ce2d0c2586eefbab8738ae7844f0e75e2aa2aec0dea78e32932867b2240aa867", + "protocols/spir/builder-prompt.md": "c46766a1fc1041448762361f59c4180f576b97c941818bb1795091da405b2913", + "protocols/spir/consult-types/impl-review.md": "e23d51f2027d0b1492c5db7350dd0cade6d60e9c51617b4a87f8ec9f152e195a", + "protocols/spir/consult-types/phase-review.md": "e23d51f2027d0b1492c5db7350dd0cade6d60e9c51617b4a87f8ec9f152e195a", + "protocols/spir/consult-types/plan-review.md": "f56e92e8bee3473894547ba22eb3b075dedffebdd25cb4afa0d7ac5323199a32", + "protocols/spir/consult-types/pr-review.md": "8734bbec0d412318aed817a6ffab3beddcbf680c728144c185741214d1373bb8", + "protocols/spir/consult-types/spec-review.md": "dff57d066ca23572e8e0286ac74755cf26cf8f458f262b0d4a9320e5bde43600", + "protocols/spir/prompts/implement.md": "32099ccc0915937b27594b0731a645ff7a8c2e36d6222f6ab3cedd163ae80b8f", + "protocols/spir/prompts/plan.md": "5c880c4bbc45e4b385822233c65ab8381092fb19495b0d2a5222286825094846", + "protocols/spir/prompts/review.md": "2c74c200317c0702500195756b933e84ebdf6268f913e63979aca9578a116494", + "protocols/spir/prompts/specify.md": "539187cb3ea71a4f52bf2445d7e9cb8b3db61f97f11eb6b10e28398f23ec2f3a", + "protocols/spir/protocol.json": "7bccf22b67ef1a5344a64364f075f7c92a97fec565b6b8fd1aebc87a5174d2f8", + "protocols/spir/protocol.md": "b067f2d74e8bf5c2cdd8583e126e84d50abbff8cc37c0b7887e58947ec27dbe9", + "protocols/spir/templates/plan.md": "3ddb80a3930487dd99cdb4d1f58815be83fb03ce88ae5278f7ca46e11c9a77a8", + "protocols/spir/templates/review.md": "68e0b3cdd63437943aa360a9da71fd50dae2d5dd97e2b1b30e932e7ab04dbd20", + "protocols/spir/templates/spec.md": "07237c211743814750576da0ba2755fd142c95d583380d3c52d23cc08e7f7b35", + "roles/architect.md": "b1671279d754b75a800898a4ff017c695a0c313f11e0e4f1bfc9c3d008c8e3d8", + "roles/builder.md": "80d03206f757f419c4d9858c8007b6c17fd1cd126c6740624a26779c7ca625a6", + "roles/consultant.md": "8d2e090940ef525d62c90fc3ff93a077d3329ec64badb8cc92a2152debea7cdb" +} \ No newline at end of file diff --git a/packages/codev/src/__tests__/governance-sweep.test.ts b/packages/codev/src/__tests__/governance-sweep.test.ts index 7b1ba1493..4ba554950 100644 --- a/packages/codev/src/__tests__/governance-sweep.test.ts +++ b/packages/codev/src/__tests__/governance-sweep.test.ts @@ -27,12 +27,11 @@ describe('Spec 987 — CLAUDE.md ≡ AGENTS.md', () => { }); describe('Spec 987 — MAINTAIN + skill reference the hot tier (both trees)', () => { + // Spec 1252: shadow tree deleted; former codev/-tree duplicates removed. const HOT_TIER_SURFACES = [ '.claude/skills/update-arch-docs/SKILL.md', 'codev-skeleton/.claude/skills/update-arch-docs/SKILL.md', - 'codev/protocols/maintain/protocol.md', 'codev-skeleton/protocols/maintain/protocol.md', - 'codev/protocols/maintain/prompts/maintain.md', 'codev-skeleton/protocols/maintain/prompts/maintain.md', ]; diff --git a/packages/codev/src/__tests__/prompt-behavior-metrics.test.ts b/packages/codev/src/__tests__/prompt-behavior-metrics.test.ts new file mode 100644 index 000000000..d422764ee --- /dev/null +++ b/packages/codev/src/__tests__/prompt-behavior-metrics.test.ts @@ -0,0 +1,187 @@ +/** + * Behavioural-metrics baseline script (Spec 1252, M12a / T14). + * + * The metrics exist so that a word-count win cannot be declared while agent + * behaviour silently degrades. For a before/after comparison to mean anything, + * the committed-artifact metrics must be DETERMINISTIC: the same commit must + * yield the same numbers. + * + * B5 (consult cost/duration) is deliberately absent from this module and from + * the determinism assertion — it derives from a rolling 30-day machine-local + * DB, so it is not reproducible from a commit. It is advisory context and + * drives no rollback trigger. (T14 originally asserted determinism over + * "B1–B5", which was self-contradictory; caught at delta review.) + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { tmpdir } from 'node:os'; +import { measureBehavior, render } from '../lib/prompt-behavior-metrics.js'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); + +/** Build a throwaway repo root with a hand-written status.yaml corpus. */ +function fixtureRoot(statusYamls: Record, prose: Record = {}) { + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-behavior-')); + for (const [proj, body] of Object.entries(statusYamls)) { + const d = path.join(root, 'codev', 'projects', proj); + fs.mkdirSync(d, { recursive: true }); + fs.writeFileSync(path.join(d, 'status.yaml'), body); + } + for (const [rel, body] of Object.entries(prose)) { + const p = path.join(root, rel); + fs.mkdirSync(path.dirname(p), { recursive: true }); + fs.writeFileSync(p, body); + } + return root; +} + +const TWO_PHASE_PROJECT = ` +id: '900' +protocol: spir +history: + - iteration: 1 + plan_phase: phase_1 + reviews: + - {model: gemini, verdict: APPROVE} + - {model: codex, verdict: REQUEST_CHANGES} + - {model: claude, verdict: APPROVE} + - iteration: 2 + plan_phase: phase_1 + reviews: + - {model: gemini, verdict: APPROVE} + - {model: codex, verdict: REQUEST_CHANGES} + - {model: claude, verdict: COMMENT} + - iteration: 1 + plan_phase: phase_2 + reviews: + - {model: gemini, verdict: APPROVE} +`; + +describe('behavioural metrics (M12a / T14)', () => { + it('is DETERMINISTIC over B1–B4 for a fixed corpus', () => { + const root = fixtureRoot({ '900-x': TWO_PHASE_PROJECT }); + try { + const a = measureBehavior(root); + const b = measureBehavior(root); + expect(a).toEqual(b); + // and stable across a re-render + expect(render(a)).toEqual(render(b)); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('computes B1 as the REQUEST_CHANGES share of all verdicts', () => { + const root = fixtureRoot({ '900-x': TWO_PHASE_PROJECT }); + try { + const m = measureBehavior(root); + // 7 verdicts: 4 APPROVE, 2 REQUEST_CHANGES, 1 COMMENT + expect(m.b1_totalVerdicts).toBe(7); + expect(m.b1_verdictCounts['REQUEST_CHANGES']).toBe(2); + expect(m.b1_requestChangesRate).toBeCloseTo(28.57, 1); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('computes B2 as max(iteration) per plan_phase, not rounds-to-unanimity', () => { + // The corpus above never reaches 3x APPROVE on phase_1 — which is exactly + // the real-world pattern (0 of 48 terminal phases in this repo end + // unanimously; porch advances on builder rebuttal). A rounds-to-unanimity + // metric would never resolve here; max(iteration) does. + const root = fixtureRoot({ '900-x': TWO_PHASE_PROJECT }); + try { + const m = measureBehavior(root); + expect(m.b2_phaseCount).toBe(2); // phase_1, phase_2 + expect(m.b2_roundsPerPhaseMax).toBe(2); // phase_1 reached iteration 2 + expect(m.b2_roundsPerPhaseMean).toBeCloseTo(1.5, 2); + expect(m.b4_roundsPerProjectMean).toBeCloseTo(3, 2); // 2 + 1 + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('ignores projects with empty history (pir/bugfix/air contribute nothing)', () => { + const root = fixtureRoot({ + '900-x': TWO_PHASE_PROJECT, + '901-y': "id: '901'\nprotocol: bugfix\nhistory: []\n", + }); + try { + const m = measureBehavior(root); + expect(m.sampleProjects).toEqual(['900-x']); + expect(m.b4_projectCount).toBe(1); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('survives a malformed status.yaml without aborting the run', () => { + const root = fixtureRoot({ + '900-x': TWO_PHASE_PROJECT, + '902-bad': 'id: [unclosed\n ::: not yaml :::\n', + }); + try { + const m = measureBehavior(root); + expect(m.sampleProjects).toEqual(['900-x']); // bad file skipped, run completes + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('B3 emits excerpts, not just counts, so a human can adjudicate', () => { + const root = fixtureRoot( + {}, + { + 'codev/reviews/1-x.md': 'I ran git add -A by mistake and it staged secrets\n', + 'codev/state/b_thread.md': 'Reminder: never use git add -A here.\n', + } + ); + try { + const m = measureBehavior(root); + const hit = m.b3_candidateHits.find((h) => h.rule === 'git-add-all'); + expect(hit, 'the confessional line should be flagged').toBeTruthy(); + expect(hit!.excerpt).toContain('git add -A'); + expect(hit!.file).toBe('codev/reviews/1-x.md'); + expect(hit!.line).toBe(1); + + // The prescriptive "never use..." line is documentation, not a breach. + expect(m.b3_candidateHits.filter((h) => h.file.endsWith('b_thread.md'))).toEqual([]); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('does NOT report gate-rejection counts (the data does not exist)', () => { + // Appendix D §2: no `rejected` gate state is ever persisted and + // `requested_at` is overwritten on re-request, so a rejected-then-approved + // gate is indistinguishable from a clean approval. A plausible-looking zero + // would be worse than an absent metric. + const m = measureBehavior(REPO_ROOT); + expect(Object.keys(m)).not.toContain('gateRejections'); + expect(JSON.stringify(m)).not.toMatch(/gateReject/i); + }); + + it('excludes the measuring project from its own baseline (B1–B4 and B3)', () => { + // The baseline is the PRE-PROJECT state. Project 1252's own status.yaml + // accumulates verdicts with every review iteration, and its thread/review + // files discuss scar rules at length — scanning either makes the baseline + // drift as the project runs. (Discovered live: the reproduction test below + // failed the moment this project's own iter-1 review landed, 160 → 163.) + const m = measureBehavior(REPO_ROOT); + expect(m.sampleProjects).not.toContain('1252-prompt-architecture-single-own'); + for (const h of m.b3_candidateHits) { + expect(h.file).not.toMatch(/spir-1252_|\/1252-/); + } + }); + + it('reproduces the committed baseline numbers on this repo', () => { + // Guards against a refactor silently changing what the baseline means. + const m = measureBehavior(REPO_ROOT); + expect(m.b1_totalVerdicts).toBe(160); + expect(m.b1_requestChangesRate).toBeCloseTo(51.88, 1); + expect(m.b2_roundsPerPhaseMean).toBeCloseTo(1.12, 2); + expect(m.b4_roundsPerProjectMean).toBeCloseTo(3.06, 2); + }); +}); diff --git a/packages/codev/src/__tests__/prompt-ownership.test.ts b/packages/codev/src/__tests__/prompt-ownership.test.ts new file mode 100644 index 000000000..76192858e --- /dev/null +++ b/packages/codev/src/__tests__/prompt-ownership.test.ts @@ -0,0 +1,363 @@ +/** + * Ownership map enforcement (Spec 1252, M1/M4 — T7 + T12). + * + * T12 — completeness: every normative candidate in the declared inventory + * boundary resolves to a disposition, and the catch-all cannot absorb + * cross-surface duplication. Validated against seeded lines so it cannot pass + * vacuously (Codex's spec-review requirement). + * + * T7 — single-owner: for every `enforcement: automated` class, the pattern + * matches on exactly the declared owner (scar: false) or on all + * must_appear_on (scar: true). Assertions DERIVE from the map file — + * restating ownership in test code would itself violate the single-owner + * rule. The real classes are `manual` until Phase 7 dedups their + * restatements; the enforcement machinery is proven here against fixtures. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { tmpdir } from 'node:os'; +import { + extractCandidates, + loadOwnershipMap, + validateMap, + checkCompleteness, + computeCompleteness, + resolveDisposition, + type OwnershipMap, +} from '../lib/prompt-ownership.js'; +import { buildPromptFromTemplate } from '../agent-farm/commands/spawn-roles.js'; +import { resolveCodevIncludes } from '../lib/skeleton.js'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); + +describe('ownership map — structure (M1)', () => { + it('loads and passes structural validation', () => { + const map = loadOwnershipMap(REPO_ROOT); + expect(validateMap(map, REPO_ROOT)).toEqual([]); + }); + + it('every instruction class has exactly one owner', () => { + const map = loadOwnershipMap(REPO_ROOT); + for (const c of map.instructions) { + expect(typeof c.owner, `${c.id}: owner must be a single surface id`).toBe('string'); + } + }); + + it('records why codev/resources/ is outside the drift regime (Q7 / required M1 coverage)', () => { + const raw = fs.readFileSync( + path.join(REPO_ROOT, 'codev/resources/prompt-ownership.yaml'), + 'utf-8' + ); + expect(raw).toMatch(/codev\/resources\/ is also deliberately excluded/); + expect(raw).toMatch(/user-evolved/); + }); +}); + +describe('completeness (M1 / T12)', () => { + it('zero undispositioned candidates on the live boundary', () => { + const report = checkCompleteness(REPO_ROOT); + expect( + report.undispositioned.map((c) => `${c.file}:${c.line} ${c.text.slice(0, 80)}`), + 'every normative candidate needs a disposition (mapped | scar | out-of-scope)' + ).toEqual([]); + expect(report.total).toBeGreaterThan(50); // extractor actually ran + }); + + it('no cross-surface duplication hides behind the catch-all', () => { + const report = checkCompleteness(REPO_ROOT); + expect( + report.multiFileViaCatchAll.map((c) => `${c.file}:${c.line} ${c.text.slice(0, 80)}`), + 'a normative text on 2+ files must have a specific disposition — add one ' + + '(mapped/scar/out-of-scope) rather than letting the catch-all absorb it' + ).toEqual([]); + }); + + it('a missing boundary file fails LOUDLY, never silently shrinking the scan', () => { + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-ownership-')); + try { + expect(() => extractCandidates(root, ['does/not/exist.md'])).toThrow( + /inventory_boundary file missing/ + ); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('SEEDED: a new normative line is undispositioned until someone dispositions it', () => { + // Guards T12 against vacuous passing: prove the extractor + resolver + // actually flag novel content. A map without the catch-all must leave the + // seeded line undispositioned. + const map = loadOwnershipMap(REPO_ROOT); + const noCatchAll: OwnershipMap = { + ...map, + dispositions: map.dispositions.filter((d) => !d.catch_all), + }; + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-ownership-')); + try { + fs.mkdirSync(path.join(root, 'seed'), { recursive: true }); + fs.writeFileSync( + path.join(root, 'seed/a.md'), + 'Some prose.\nNEVER frobnicate the sprocket without a permit.\n' + ); + const cands = extractCandidates(root, ['seed/a.md']); + expect(cands.length).toBe(1); + expect(resolveDisposition(noCatchAll, cands[0])).toBeNull(); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('SEEDED: duplicating a line across two files trips the REAL catch-all guard', () => { + // Exercises computeCompleteness itself (not a local re-implementation): + // a catch-all-only map over two files sharing one normative line must + // report both candidates via multiFileViaCatchAll. + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-ownership-')); + try { + fs.mkdirSync(path.join(root, 'seed')); + const line = 'ALWAYS varnish the widget before shipping.\n'; + fs.writeFileSync(path.join(root, 'seed/a.md'), line); + fs.writeFileSync(path.join(root, 'seed/b.md'), line); + const map: OwnershipMap = { + inventory_boundary: ['seed/a.md', 'seed/b.md'], + surfaces: [], + instructions: [], + dispositions: [ + { match: '/.*/', disposition: 'out-of-scope', note: 'catch-all', catch_all: true }, + ], + }; + const cands = extractCandidates(root, map.inventory_boundary); + expect(cands.length).toBe(2); + const report = computeCompleteness(map, cands); + expect(report.undispositioned).toEqual([]); + expect(report.multiFileViaCatchAll.map((c) => c.file).sort()).toEqual([ + 'seed/a.md', + 'seed/b.md', + ]); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('companion prompt-ownership.md parity marker matches the live extractor', () => { + // The human companion must be validated against the YAML/extractor + // (Codex, Phase-6 review): its t12-parity marker pins the live counts, so + // the .md cannot silently drift from reality. + const md = fs.readFileSync( + path.join(REPO_ROOT, 'codev/resources/prompt-ownership.md'), + 'utf-8' + ); + const m = md.match( + // + ); + expect(m, 'prompt-ownership.md must carry the t12-parity marker').toBeTruthy(); + const report = checkCompleteness(REPO_ROOT); + const map = loadOwnershipMap(REPO_ROOT); + expect(Number(m![1]), 'total').toBe(report.total); + expect(Number(m![2]), 'mapped').toBe(report.byDisposition['mapped']); + expect(Number(m![3]), 'scar').toBe(report.byDisposition['scar']); + expect(Number(m![4]), 'out-of-scope').toBe(report.byDisposition['out-of-scope']); + expect(Number(m![5]), 'classes').toBe(map.instructions.length); + // and every class row documents its CURRENT owner and enforcement — + // the companion is derived from the YAML, not hand-maintained prose + // (Codex, Phase-7 review) + for (const c of map.instructions) { + const row = md.split('\n').find((l) => l.startsWith(`| ${c.id} `)); + expect(row, `companion missing class row for ${c.id}`).toBeTruthy(); + expect(row!, `${c.id}: companion row must name owner ${c.owner}`).toContain(c.owner); + expect(row!, `${c.id}: companion row must state enforcement`).toContain(c.enforcement); + } + }); +}); + +describe('single-owner enforcement (M4 / T7)', () => { + /** Build the T7 assertion set from a map — used for both live and fixture maps. */ + function t7Failures(root: string, map: OwnershipMap): string[] { + const failures: string[] = []; + const surfaceById = new Map(map.surfaces.map((s) => [s.id, s])); + for (const c of map.instructions) { + if (c.enforcement !== 'automated') continue; + const allowed = new Set( + c.scar ? (c.must_appear_on ?? []) : [c.owner] + ); + const matcher = c.pattern.startsWith('/') + ? new RegExp(c.pattern.slice(1, -1)) + : null; + for (const s of map.surfaces) { + const p = path.join(root, s.path); + if (!fs.existsSync(p)) continue; + const content = fs.readFileSync(p, 'utf-8'); + const hit = matcher ? matcher.test(content) : content.includes(c.pattern); + // `references` (pointers) get NO exemption: a well-formed reference + // never reproduces the rule text (Codex, Phase-6 iter-2). Declared + // TS3-style retentions are exempt — they are full protocol-specific + // variants kept by decision, justified per class, and listed under + // retained_restatements rather than references. + const retained = new Set(c.retained_restatements ?? []); + if (hit && !allowed.has(s.id) && !retained.has(s.id)) { + failures.push(`${c.id}: pattern found on non-owner surface ${s.id}`); + } + if (!hit && allowed.has(s.id)) { + failures.push(`${c.id}: pattern MISSING from required surface ${s.id}`); + } + } + } + return failures; + } + + it('live map: all automated classes hold', () => { + const map = loadOwnershipMap(REPO_ROOT); + expect(t7Failures(REPO_ROOT, map)).toEqual([]); + }); + + it('FIXTURE: machinery detects a restatement on a non-owner surface', () => { + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-t7-')); + try { + fs.writeFileSync(path.join(root, 'owner.md'), 'RULE-X applies here.\n'); + fs.writeFileSync(path.join(root, 'other.md'), 'RULE-X applies here too.\n'); + const map: OwnershipMap = { + inventory_boundary: [], + surfaces: [ + { id: 'owner', path: 'owner.md', load: 'always-on' }, + { id: 'other', path: 'other.md', load: 'always-on' }, + ], + instructions: [ + { + id: 'rule-x', + summary: 'x', + owner: 'owner', + scar: false, + pattern: 'RULE-X', + enforcement: 'automated', + }, + ], + dispositions: [], + }; + const failures = t7Failures(root, map); + expect(failures).toEqual(['rule-x: pattern found on non-owner surface other']); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it('every manual class carries a justification naming its path to automated', () => { + const map = loadOwnershipMap(REPO_ROOT); + for (const c of map.instructions) { + if (c.enforcement === 'manual') { + expect( + c.manual_justification ?? '', + `${c.id}: manual classes must say why and when they flip` + ).toMatch(/Phase 7|dedup|include|retention/i); + } + } + }); +}); + +describe('served-surface dedup guard (S1 — assembled artifacts)', () => { + // The include model means AUTHORED ownership is single while SERVED prompts + // each carry the full text once. The failure mode that breaks S1 on the + // agent-facing surface is a rule appearing TWICE in one served artifact + // (e.g. two lines in one file converged to the same include — caught live + // by Codex at the Phase-7 review: plan.md served no-time-estimates twice). + // Guard every automated non-scar class across every served artifact. + const PROTOCOLS = ['air','aspir','bugfix','experiment','maintain','pir','research','spike','spir']; + + function countMatches(content: string, pattern: string): number { + const re = pattern.startsWith('/') + ? new RegExp(pattern.slice(1, -1), 'g') + : new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'); + return (content.match(re) ?? []).length; + } + + /** Protocols whose builder-prompt includes the given partial (1 nested level). */ + function protocolsIncluding(partialPath: string): string[] { + const token = partialPath.replace('codev-skeleton/', ''); + return PROTOCOLS.filter((proto) => { + const raw = fs.readFileSync( + path.join(REPO_ROOT, `codev-skeleton/protocols/${proto}/builder-prompt.md`), + 'utf-8' + ); + if (raw.includes(token)) return true; + // one nested level: any partial the prompt includes that itself includes the target + for (const m of raw.matchAll(/\{\{>\s*([^}\s]+)\s*\}\}/g)) { + const inner = path.join(REPO_ROOT, 'codev-skeleton', m[1]); + if (fs.existsSync(inner) && fs.readFileSync(inner, 'utf-8').includes(token)) return true; + } + return false; + }); + } + + it('every automated class is PRESENT where its include graph delivers it, and never over-served', () => { + // Cap alone is not enough: a broken {{> partials/...}} include yields n=0 + // and would pass silently — a removed rule is the worst outcome (Codex, + // Phase-7 iter-3). Presence is derived from the include graph, absence + // fails loudly. + const map = loadOwnershipMap(REPO_ROOT); + const surfaceById = new Map(map.surfaces.map((s2) => [s2.id, s2])); + const failures: string[] = []; + for (const proto of PROTOCOLS) { + // Render BOTH modes: conditional blocks ({{#if mode_soft}}) legitimately + // gate content per mode, so presence is asserted over the union while + // the over-serve cap applies per render. + const base = { + protocol_name: proto, project_id: '9999', input_description: 'guard', + issue: { number: 9999, title: 't', body: 'b' }, + }; + const renders = [ + buildPromptFromTemplate({ workspaceRoot: REPO_ROOT } as never, proto, + { ...base, mode: 'strict', mode_soft: false, mode_strict: true } as never), + buildPromptFromTemplate({ workspaceRoot: REPO_ROOT } as never, proto, + { ...base, mode: 'soft', mode_soft: true, mode_strict: false } as never), + ]; + for (const c of map.instructions) { + if (c.enforcement !== 'automated' || c.scar) continue; + const cap = c.served_max ?? 1; + let anyPresent = false; + renders.forEach((prompt, i) => { + const n = countMatches(prompt, c.pattern); + if (n > cap) { + failures.push(`${proto} (${i === 0 ? 'strict' : 'soft'}): class ${c.id} served ${n}x (cap ${cap})`); + } + if (n > 0) anyPresent = true; + }); + const owner = surfaceById.get(c.owner); + if (owner && owner.path.startsWith('codev-skeleton/partials/')) { + const expected = protocolsIncluding(owner.path); + if (expected.includes(proto) && !anyPresent) { + failures.push( + `${proto}: class ${c.id} MISSING from both mode renders — its owner ` + + `partial is in this protocol's include graph; a broken include?` + ); + } + } + } + } + expect(failures, failures.join('\n')).toEqual([]); + }); + + it('no automated class appears more than once in any expanded phase prompt', () => { + const map = loadOwnershipMap(REPO_ROOT); + const failures: string[] = []; + const promptFiles = map.inventory_boundary.filter((p) => p.includes('/prompts/') || p.includes('porch/prompts')); + const protoPrompts = [ + ...promptFiles, + 'codev-skeleton/protocols/spir/prompts/plan.md', + 'codev-skeleton/protocols/aspir/prompts/plan.md', + 'codev-skeleton/protocols/spir/prompts/specify.md', + 'codev-skeleton/protocols/aspir/prompts/specify.md', + ]; + for (const rel of [...new Set(protoPrompts)]) { + const p = path.join(REPO_ROOT, rel); + if (!fs.existsSync(p)) continue; + const expanded = resolveCodevIncludes(fs.readFileSync(p, 'utf-8'), REPO_ROOT); + for (const c of map.instructions) { + if (c.enforcement !== 'automated' || c.scar) continue; + const n = countMatches(expanded, c.pattern); + const cap = c.served_max ?? 1; + if (n > cap) failures.push(`${rel}: class ${c.id} served ${n}x (cap ${cap}) after expansion`); + } + } + expect(failures, failures.join('\n')).toEqual([]); + }); +}); diff --git a/packages/codev/src/__tests__/protocol-prompt-audit.test.ts b/packages/codev/src/__tests__/protocol-prompt-audit.test.ts index 8413549cc..3b99c9ef0 100644 --- a/packages/codev/src/__tests__/protocol-prompt-audit.test.ts +++ b/packages/codev/src/__tests__/protocol-prompt-audit.test.ts @@ -65,10 +65,8 @@ function formatViolations(violations: Violation[]): string { } describe('protocol prompt audit (#777 / #784 regression guards)', () => { - const protocolDirs = [ - path.join(repoRoot, 'codev/protocols'), - path.join(repoRoot, 'codev-skeleton/protocols'), - ]; + // Spec 1252: shadow tree deleted; single owner, single walk root. + const protocolDirs = [path.join(repoRoot, 'codev-skeleton/protocols')]; const files = protocolDirs.flatMap(walkMarkdown); it('finds protocol .md files to audit', () => { diff --git a/packages/codev/src/__tests__/review-prompt-routing.test.ts b/packages/codev/src/__tests__/review-prompt-routing.test.ts index 4970bf095..9d8bc6501 100644 --- a/packages/codev/src/__tests__/review-prompt-routing.test.ts +++ b/packages/codev/src/__tests__/review-prompt-routing.test.ts @@ -22,7 +22,7 @@ const ROUTING_FILES = [ ]; const files: string[] = []; -for (const tree of ['codev', 'codev-skeleton']) { +for (const tree of ['codev-skeleton']) { // Spec 1252: codev/ shadow tree deleted; skeleton is the single owner for (const f of ROUTING_FILES) files.push(`${tree}/${f}`); } files.push('codev-skeleton/porch/prompts/review.md'); // generic porch review prompt (skeleton-only) diff --git a/packages/codev/src/__tests__/scaffold.test.ts b/packages/codev/src/__tests__/scaffold.test.ts index 9fc4b39dc..7172f918c 100644 --- a/packages/codev/src/__tests__/scaffold.test.ts +++ b/packages/codev/src/__tests__/scaffold.test.ts @@ -11,7 +11,6 @@ import { createUserDirs, copyConsultTypes, copyResourceTemplates, - copyRoles, copyRootFiles, copySkills, } from '../lib/scaffold.js'; @@ -153,51 +152,6 @@ describe('Scaffold Utilities', () => { }); // Regression test for issue #266: codev init does not copy roles/ - describe('copyRoles', () => { - it('should copy all .md files from roles directory', () => { - const targetDir = path.join(tempDir, 'project'); - fs.mkdirSync(targetDir, { recursive: true }); - - const result = copyRoles(targetDir, mockSkeletonDir); - - expect(result.copied).toContain('architect.md'); - expect(result.copied).toContain('builder.md'); - expect(result.copied).toContain('consultant.md'); - expect(result.directoryCreated).toBe(true); - expect(fs.existsSync(path.join(targetDir, 'codev', 'roles', 'architect.md'))).toBe(true); - expect(fs.existsSync(path.join(targetDir, 'codev', 'roles', 'builder.md'))).toBe(true); - expect(fs.existsSync(path.join(targetDir, 'codev', 'roles', 'consultant.md'))).toBe(true); - }); - - it('should skip existing files in adopt mode', () => { - const targetDir = path.join(tempDir, 'project'); - fs.mkdirSync(path.join(targetDir, 'codev', 'roles'), { recursive: true }); - fs.writeFileSync(path.join(targetDir, 'codev', 'roles', 'architect.md'), 'custom content'); - - const result = copyRoles(targetDir, mockSkeletonDir, { skipExisting: true }); - - expect(result.copied).toContain('builder.md'); - expect(result.copied).toContain('consultant.md'); - expect(result.skipped).toContain('architect.md'); - expect(result.directoryCreated).toBe(false); - // Verify existing file was not overwritten - expect(fs.readFileSync(path.join(targetDir, 'codev', 'roles', 'architect.md'), 'utf-8')).toBe('custom content'); - }); - - it('should handle missing source directory gracefully', () => { - const targetDir = path.join(tempDir, 'project'); - fs.mkdirSync(targetDir, { recursive: true }); - const emptySkeletonDir = path.join(tempDir, 'empty-skeleton'); - fs.mkdirSync(emptySkeletonDir, { recursive: true }); - - const result = copyRoles(targetDir, emptySkeletonDir); - - expect(result.copied).toEqual([]); - expect(result.directoryCreated).toBe(true); - // Directory should still be created even if source is missing - expect(fs.existsSync(path.join(targetDir, 'codev', 'roles'))).toBe(true); - }); - }); describe('copyResourceTemplates', () => { it('should copy lessons-learned.md, arch.md, cheatsheet.md, and lifecycle.md', () => { diff --git a/packages/codev/src/__tests__/scar-rules.test.ts b/packages/codev/src/__tests__/scar-rules.test.ts new file mode 100644 index 000000000..ad5afd432 --- /dev/null +++ b/packages/codev/src/__tests__/scar-rules.test.ts @@ -0,0 +1,147 @@ +/** + * Scar-rule registry enforcement (Spec 1252, M5 / T6 / decision D3). + * + * Scar rules are prohibitions born from real incidents (data loss, bypassed + * human gates). They are exempt from the single-owner rule: the canonical + * wording is replicated VERBATIM on every surface it applies to. What this + * test makes impossible: + * + * - silently deleting a rule (count and ids are pinned to D3's ratified 8); + * - rewording a copy on any surface (byte comparison against the registry); + * - weakening the registry itself (schema assertions). + * + * Changing a canonical wording requires editing the registry AND every listed + * surface in one commit — deliberately loud and reviewable. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as yaml from 'js-yaml'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); +const REGISTRY = path.join(REPO_ROOT, 'codev', 'resources', 'scar-rules.yaml'); + +interface ScarRule { + id: string; + canonical: string; + must_appear_on: string[]; +} + +function loadRegistry(): ScarRule[] { + const doc = yaml.load(fs.readFileSync(REGISTRY, 'utf-8')) as { scar_rules: ScarRule[] }; + return doc.scar_rules; +} + +/** The eight ratified rule ids (D3, 2026-07-28). Changing this list is a spec-level act. */ +const RATIFIED_IDS = [ + 'git-add-explicit', + 'never-destroy-worktrees', + 'no-destructive-git', + 'human-gates', + 'no-hand-edit-status', + 'afx-from-root', + 'shellper-verified-orphan', + 'tower-restart-permission', +]; + +describe('scar-rule registry (M5 / T6)', () => { + it('contains exactly the eight ratified rules', () => { + const rules = loadRegistry(); + expect(rules.map((r) => r.id).sort()).toEqual([...RATIFIED_IDS].sort()); + }); + + it('every rule has a canonical wording of at most two sentences', () => { + for (const r of loadRegistry()) { + expect(r.canonical.trim().length, `${r.id}: empty canonical`).toBeGreaterThan(0); + // D3: one sentence, two max. Count terminal periods not inside backticks + // or parentheses-final abbreviations — approximate but effective: split + // on '. ' boundaries plus trailing period. + const stripped = r.canonical.replace(/`[^`]*`/g, 'CODE'); + const sentences = stripped.split(/(?<=[.!?])\s+/).filter((s) => s.trim().length > 0); + expect( + sentences.length, + `${r.id}: ${sentences.length} sentences — D3 caps at two` + ).toBeLessThanOrEqual(2); + } + }); + + it('every rule appears on CLAUDE.md and AGENTS.md (always-on surfaces)', () => { + for (const r of loadRegistry()) { + expect(r.must_appear_on, `${r.id} missing CLAUDE.md`).toContain('CLAUDE.md'); + expect(r.must_appear_on, `${r.id} missing AGENTS.md`).toContain('AGENTS.md'); + } + }); + + it('every canonical wording appears LINE-EXACTLY on every listed surface', () => { + // Substring matching (`includes`) is not enough: an appended qualifier — + // "…explicitly by path, unless convenient." — would weaken the rule while + // still containing the canonical substring (caught by Codex at the Phase-5 + // review). Enforce line-exactness instead: some line on the surface must + // BE the canonical wording, allowing only a list prefix ("- ", "4. ") and + // bold markers. Contextual notes (exceptions, conventions) live on their + // own adjacent lines, where they cannot mutate the rule sentence. + const lineMatches = (content: string, canonical: string): boolean => + content.split('\n').some((line) => { + const stripped = line.trim().replace(/^(?:[-*]|\d+\.)\s+/, '').replace(/^\*\*|\*\*$/g, ''); + return stripped === canonical; + }); + const failures: string[] = []; + for (const r of loadRegistry()) { + for (const rel of r.must_appear_on) { + const p = path.join(REPO_ROOT, rel); + if (!fs.existsSync(p)) { + failures.push(`${r.id}: surface missing entirely — ${rel}`); + continue; + } + if (!lineMatches(fs.readFileSync(p, 'utf-8'), r.canonical)) { + failures.push(`${r.id}: no line-exact canonical wording in ${rel}`); + } + } + } + expect( + failures, + failures.length + ? `Scar-rule enforcement failures — a rule was deleted, reworded, or its ` + + `surface dropped. This is never a test to weaken; fix the surface or ` + + `change the registry and ALL surfaces in one reviewed commit.\n` + + failures.map((f) => ` - ${f}`).join('\n') + : undefined + ).toEqual([]); + }); + + it('no stale wording variants survive on registry surfaces', () => { + // The convergence's point is ONE wording. Old variants of the two most + // duplicated rules must not linger next to the canonical. + const staleVariants = [ + 'NEVER USE `git add -A`', // the old banner + 'Never use `git add .` or `git add -A`', + "Don't use `git add .` or `git add -A`", + 'NEVER edit `status.yaml` directly', + 'NEVER edit status.yaml directly', + 'porch manages all state', + 'NEVER call `porch approve` without explicit human approval', + 'edit `status.yaml` to bypass checks', + // afx-from-root contradictions: any claim that afx works from anywhere + '`afx`, `consult`, `porch`, and `codev` are global commands', + '`afx`, `porch`, `consult`, `codev`) are global commands', + ]; + const surfaces = new Set(loadRegistry().flatMap((r) => r.must_appear_on)); + const failures: string[] = []; + for (const rel of surfaces) { + const p = path.join(REPO_ROOT, rel); + if (!fs.existsSync(p)) continue; + const content = fs.readFileSync(p, 'utf-8'); + for (const v of staleVariants) { + if (content.includes(v)) failures.push(`${rel}: stale variant "${v}"`); + } + } + expect(failures, failures.join('\n')).toEqual([]); + }); + + it('CLAUDE.md and AGENTS.md remain byte-identical (N3)', () => { + const a = fs.readFileSync(path.join(REPO_ROOT, 'CLAUDE.md')); + const b = fs.readFileSync(path.join(REPO_ROOT, 'AGENTS.md')); + expect(a.equals(b), 'CLAUDE.md and AGENTS.md have diverged').toBe(true); + }); +}); diff --git a/packages/codev/src/__tests__/shadow-drift-gate.test.ts b/packages/codev/src/__tests__/shadow-drift-gate.test.ts new file mode 100644 index 000000000..6f1e67bd8 --- /dev/null +++ b/packages/codev/src/__tests__/shadow-drift-gate.test.ts @@ -0,0 +1,135 @@ +/** + * Shadow-drift CI gate (Spec 1252, M2 / T5). + * + * ## Why this exists + * + * `protocol-drift-audit` (#1210) has detected shadow drift since it shipped, and + * `codev doctor` has been reporting it. Nobody read it. Seventeen framework + * files drifted anyway — including `protocols/spir/builder-prompt.md`, whose + * served copy lost the `Verify Phase` and `Multi-PR Mechanics` sections, so + * every SPIR builder spawned in this repo was missing its verify instructions + * while adopters got them. + * + * The gap was never detection. It was that nothing FAILED. This gate is the + * missing half: it turns the existing audit into a build-breaking check. + * + * It deliberately does NOT reimplement detection — it calls + * `auditProtocolDrift()` and adjudicates the result against an explicit + * allowlist. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { tmpdir } from 'node:os'; +import { auditProtocolDrift, FRAMEWORK_DRIFT_DIRS } from '../lib/protocol-drift-audit.js'; +import { getSkeletonDir, listSkeletonFiles, findWorkspaceRoot } from '../lib/skeleton.js'; +import { + SHADOW_DRIFT_ALLOWLIST, + ALLOWLISTED_PATHS, + type AllowEntry, +} from './fixtures/shadow-drift-allowlist.js'; + +const WORKSPACE_ROOT = findWorkspaceRoot(path.resolve(__dirname, '../../../..')); + +/** Findings that represent real divergence from the skeleton. */ +function differingFindings(root: string) { + return auditProtocolDrift(root).filter((f) => f.status === 'differs'); +} + +describe('shadow-drift gate (M2)', () => { + it('reports no un-adjudicated drift in this workspace', () => { + const unexpected = differingFindings(WORKSPACE_ROOT) + .filter((f) => !ALLOWLISTED_PATHS.has(f.relativePath)) + .map((f) => `${f.tier}/${f.relativePath}`); + + expect( + unexpected, + unexpected.length + ? `Un-adjudicated shadow drift.\n\n` + + `These project-local copies differ from the installed skeleton and are not in\n` + + `the allowlist:\n` + + unexpected.map((p) => ` - ${p}`).join('\n') + + `\n\nEither reconcile them to the skeleton (decision D1 — the skeleton is\n` + + `authoritative), or add an allowlist entry WITH a justification if a human\n` + + `has adjudicated the divergence. Do not add an entry merely to go green.\n` + : undefined + ).toEqual([]); + }); + + it('every allowlist entry carries a non-empty justification', () => { + const unjustified = SHADOW_DRIFT_ALLOWLIST.filter((e: AllowEntry) => !e.note?.trim()); + expect(unjustified.map((e) => e.relativePath)).toEqual([]); + }); + + it('allowlist contains no stale entries for files that no longer drift', () => { + // An entry that outlives its drift is how an allowlist silently becomes + // permanent. Once a file is reconciled, its entry must be removed. + const actuallyDrifting = new Set( + differingFindings(WORKSPACE_ROOT).map((f) => f.relativePath) + ); + const stale = SHADOW_DRIFT_ALLOWLIST.filter( + (e) => !actuallyDrifting.has(e.relativePath) + ).map((e) => e.relativePath); + + expect( + stale, + stale.length + ? `Stale allowlist entries — these files no longer differ from the skeleton, ` + + `so their entries must be deleted:\n` + stale.map((p) => ` - ${p}`).join('\n') + : undefined + ).toEqual([]); + }); + + /** + * A gate that has only ever seen a clean tree is indistinguishable from a + * no-op. This proves it bites: seed a real divergence in a temp workspace and + * require the audit to catch it. + */ + it('BITES: a seeded divergence is detected as drift', () => { + const rel = listSkeletonFiles(FRAMEWORK_DRIFT_DIRS[0]).find((f) => f.endsWith('.md')); + expect(rel, 'skeleton has no framework .md files — build the skeleton first').toBeTruthy(); + + const root = fs.mkdtempSync(path.join(tmpdir(), 'codev-drift-gate-')); + try { + const skeletonBytes = fs.readFileSync(path.join(getSkeletonDir(), rel!)); + + // (a) A byte-identical copy must NOT be reported as drift. + const local = path.join(root, 'codev', rel!); + fs.mkdirSync(path.dirname(local), { recursive: true }); + fs.writeFileSync(local, skeletonBytes); + expect(differingFindings(root).map((f) => f.relativePath)).toEqual([]); + + // (b) One mutated byte must be. + fs.writeFileSync(local, Buffer.concat([skeletonBytes, Buffer.from('\n\n')])); + expect(differingFindings(root).map((f) => f.relativePath)).toContain(rel); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + /** + * Phase-3 lifecycle guard (M2, per Gemini's iteration-2 review). + * + * PENDING_RECONCILE is a Phase-1-only concession. Once Phase 3 has reconciled + * the 17 drifted files, no such entry may remain — otherwise the allowlist + * becomes the permanent exemption it was designed to prevent. + * + * Enable by flipping PHASE_3_COMPLETE in Phase 3's commit. + */ + const PHASE_3_COMPLETE = true; + + it.skipIf(!PHASE_3_COMPLETE)( + 'after Phase 3, no PENDING_RECONCILE entries remain', + () => { + const pending = SHADOW_DRIFT_ALLOWLIST.filter( + (e) => e.reason === 'PENDING_RECONCILE' + ).map((e) => e.relativePath); + expect( + pending, + `Phase 3 is complete, so every PENDING_RECONCILE entry must be gone. ` + + `Only ESCALATED (open M11 adjudication) or TS3_RETAINED entries may remain.` + ).toEqual([]); + } + ); +}); diff --git a/packages/codev/src/__tests__/shadow-removal-equivalence.test.ts b/packages/codev/src/__tests__/shadow-removal-equivalence.test.ts new file mode 100644 index 000000000..239ff451e --- /dev/null +++ b/packages/codev/src/__tests__/shadow-removal-equivalence.test.ts @@ -0,0 +1,166 @@ +/** + * Shadow-tree removal equivalence (Spec 1252, M10 / T9). + * + * Phase 4 deleted 77 shadow copies from `codev/protocols|roles|consult-types`. + * The entire claim of that deletion is that it is a NO-OP for what agents are + * served: after Phases 3 and 4b reconciled every survivor to the skeleton, the + * resolver must now return the skeleton counterpart for every deleted path, + * with content byte-identical to what was resolved immediately before + * deletion (captured in `fixtures/shadow-removal-manifest.json`). + * + * Assembled-prompt equivalence (M10 clause ii) is verified DIRECTLY, not + * inferred: `fixtures/prompt-snapshots/.txt` were generated by + * running the real assembly path (`buildPromptFromTemplate`, which loads the + * resolved builder-prompt.md, inlines protocol.md via {{protocol_reference}}, + * and renders) against the PRE-DELETION tree reconstructed from git + * (`git archive adae5f3b^`), under a fixed TemplateContext. The test re-runs + * the same assembly against the live tree and requires byte-identical output. + * (The first draft inferred this from content hashes + renderTemplate purity; + * Codex's phase review correctly demanded the assembly path be exercised.) + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; +import { resolveCodevFile, getSkeletonDir } from '../lib/skeleton.js'; +import { + buildPromptFromTemplate, + builderPreamble, + type TemplateContext, +} from '../agent-farm/commands/spawn-roles.js'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); +// The manifest pins the LAST INTENTIONAL content state of every former shadow +// path. Originally captured pre-deletion (Phase 4: proved deletion was a +// no-op); regenerated in Phase 5 when scar-rule compression deliberately +// changed 24 skeleton files. Updating it is the explicit act that accompanies +// any intentional prompt-content change — unexplained drift still fails. +const MANIFEST: Record = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'fixtures/shadow-removal-manifest.json'), 'utf-8') +); + +const sha = (p: string) => createHash('sha256').update(fs.readFileSync(p)).digest('hex'); + +describe('shadow-removal equivalence (M10)', () => { + it('manifest covers all 77 deleted shadow copies', () => { + expect(Object.keys(MANIFEST).length).toBe(77); + }); + + it('every deleted path resolves to the skeleton with pre-deletion content', () => { + const mismatches: string[] = []; + for (const [rel, expectedSha] of Object.entries(MANIFEST)) { + // (i) the local copy must be gone — tier 2 no longer shadows tier 4 + const local = path.join(REPO_ROOT, 'codev', rel); + if (fs.existsSync(local)) { + mismatches.push(`${rel}: local shadow copy still exists`); + continue; + } + // (ii) the resolver must serve the file FROM THE SKELETON TIER — path + // identity, not just content identity (M10 requires proving where + // resolution lands; a content match from some other tier would hide a + // resolution bug) + const resolved = resolveCodevFile(rel, REPO_ROOT); + if (!resolved) { + mismatches.push(`${rel}: resolver returned nothing after deletion`); + continue; + } + const skeletonPath = path.join(getSkeletonDir(), rel); + if (path.resolve(resolved) !== path.resolve(skeletonPath)) { + mismatches.push(`${rel}: resolved to ${resolved}, expected skeleton tier ${skeletonPath}`); + continue; + } + // (iii) content must be byte-identical to what was served pre-deletion + if (sha(resolved) !== expectedSha) { + mismatches.push(`${rel}: resolved content differs from pre-deletion snapshot`); + } + } + expect( + mismatches, + mismatches.length + ? `Deletion was NOT a no-op:\n` + mismatches.map((m) => ` - ${m}`).join('\n') + : undefined + ).toEqual([]); + }); + + /** + * M10 clause (ii): assembled-prompt byte-equivalence, via the REAL assembly + * path. Snapshots were generated against the pre-deletion tree (git archive + * of the parent of the deletion commit) with this exact fixed context; the + * live assembly must reproduce them byte-for-byte. + */ + const FIXED_CTX: TemplateContext = { + protocol_name: 'PROTO', + mode: 'strict', + mode_soft: false, + mode_strict: true, + project_id: '9999', + input_description: 'M10 equivalence fixture — fixed context', + issue: { number: 9999, title: 'fixture', body: 'fixture body' }, + }; + const SNAPSHOT_PROTOCOLS = [ + 'air', 'aspir', 'bugfix', 'experiment', 'maintain', 'pir', 'research', 'spike', 'spir', + ]; + + it('assembled spawn prompts are byte-identical to pre-deletion snapshots', () => { + for (const proto of SNAPSHOT_PROTOCOLS) { + const snapshot = fs.readFileSync( + path.resolve(__dirname, `fixtures/prompt-snapshots/${proto}.txt`), + 'utf-8' + ); + const live = buildPromptFromTemplate( + { workspaceRoot: REPO_ROOT } as never, + proto, + { ...FIXED_CTX, protocol_name: proto } + ); + expect(live, `${proto}: assembled prompt changed across the deletion`).toBe(snapshot); + } + }); + + /** + * The FULL served prompt is preamble + assembled template (plus per-spawn + * notices). The preamble used to instruct "Read codev/roles/builder.md" — a + * literal-path fetch of a file Phase 4 deleted (and which never existed in + * fresh installs; the #1011 bug class). Caught by Codex at iter-4. The role + * is not fetched at all: it is harness-injected and mirrored to + * .builder-role.md. Guard both properties. + */ + it('the spawn preamble fetches nothing by literal framework path', () => { + const preamble = builderPreamble(); + expect(preamble).not.toMatch(/codev\/(roles|protocols|consult-types)\//); + // and it tells the builder where the role actually is + expect(preamble).toContain('.builder-role.md'); + expect(preamble).toContain('system prompt'); + }); + + it('the full served prompt (preamble + template) references no deleted paths', () => { + for (const proto of SNAPSHOT_PROTOCOLS) { + const full = + builderPreamble() + + '\n\n' + + buildPromptFromTemplate({ workspaceRoot: REPO_ROOT } as never, proto, { + ...FIXED_CTX, + protocol_name: proto, + }); + // No instruction to read/cat a codev/roles path (deleted, and never a + // valid fetch target in fresh installs). + expect(full, `${proto}: full prompt references codev/roles/`).not.toMatch( + /codev\/roles\// + ); + } + }); + + it('local-only entries survived and still resolve (M8 preservation / T8)', () => { + const preserved = [ + 'protocols/release/protocol.md', + 'protocols/maintain/templates/audit-report.md', + 'protocols/maintain/templates/lessons-learned.md', + ]; + for (const rel of preserved) { + const local = path.join(REPO_ROOT, 'codev', rel); + expect(fs.existsSync(local), `${rel} must survive deletion`).toBe(true); + // and the resolver serves the local copy (they have no skeleton counterpart) + expect(resolveCodevFile(rel, REPO_ROOT)).toBe(local); + } + }); +}); diff --git a/packages/codev/src/__tests__/shadow-tree-audit.test.ts b/packages/codev/src/__tests__/shadow-tree-audit.test.ts new file mode 100644 index 000000000..8dbf000b3 --- /dev/null +++ b/packages/codev/src/__tests__/shadow-tree-audit.test.ts @@ -0,0 +1,171 @@ +/** + * Local-unique content audit — process guard (Spec 1252, M11 / T11). + * + * The audit exists so that deleting the shadow tree cannot silently destroy + * codev-specific functionality. This test guards the PROCESS, not just the + * outcome: every shadow copy must appear in the committed audit with a valid + * classification, and nothing classified `local-unique` may be reconciled or + * deleted without a recorded architect ruling. + * + * The audit table is machine-parseable BY CONTRACT (fixed 6-column pipe table, + * enumerated values) — a builder rewriting it as free prose breaks this test, + * which is the point: weakening the audit must be loud. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; +import { getSkeletonDir, listSkeletonFiles } from '../lib/skeleton.js'; +import { FRAMEWORK_DRIFT_DIRS } from '../lib/protocol-drift-audit.js'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); +const AUDIT_PATH = path.join(REPO_ROOT, 'codev', 'resources', '1252-shadow-tree-audit.md'); + +const CLASSIFICATIONS = new Set(['rot', 'local-unique']); +const TERMINAL_STATES = new Set(['TS1', 'TS2', 'TS3', 'TS4', 'pending']); + +interface AuditRow { + file: string; + divergence: string; + classification: string; + terminalState: string; + note: string; +} + +/** Parse the audit's fixed 6-column table. Throws loudly on shape violations. */ +function parseAudit(): AuditRow[] { + const text = fs.readFileSync(AUDIT_PATH, 'utf-8'); + const rows: AuditRow[] = []; + for (const line of text.split('\n')) { + // data rows: | n | `path` | divergence | classification | ts | note | + const m = line.match(/^\|\s*\d+\s*\|\s*`([^`]+)`\s*\|([^|]+)\|([^|]+)\|([^|]+)\|(.*)\|\s*$/); + if (!m) continue; + rows.push({ + file: m[1].trim(), + divergence: m[2].trim(), + classification: m[3].trim(), + terminalState: m[4].trim(), + note: m[5].trim(), + }); + } + return rows; +} + +/** The actual shadow-copy set, computed the same way the audit computed it. */ +function actualShadowCopies(): Map { + const skeletonDir = getSkeletonDir(); + const out = new Map(); + const sha = (p: string) => createHash('sha256').update(fs.readFileSync(p)).digest('hex'); + for (const sub of FRAMEWORK_DRIFT_DIRS) { + for (const rel of listSkeletonFiles(sub)) { + if (!/\.(md|json)$/.test(rel)) continue; + const local = path.join(REPO_ROOT, 'codev', rel); + if (!fs.existsSync(local)) continue; + out.set( + rel, + sha(local) === sha(path.join(skeletonDir, rel)) ? 'identical' : 'differs' + ); + } + } + return out; +} + +describe('shadow-tree audit (M11 / T11)', () => { + it('audit records all 77 copies and covers every shadow copy that still exists', () => { + const rows = parseAudit(); + // The audit is a historical record: rows persist after their files are + // deleted (Phase 4). The fixed total pins the record; the subset check + // guarantees no shadow copy can exist un-audited (e.g. a reintroduced one + // would first trip the drift gate, then this). + expect(rows.length, 'the audited record is 77 shadow copies').toBe(77); + const audited = new Set(rows.map((r) => r.file)); + for (const rel of actualShadowCopies().keys()) { + expect(audited.has(rel), `shadow copy missing from audit: ${rel}`).toBe(true); + } + }); + + it('every row carries a valid classification and terminal state', () => { + for (const r of parseAudit()) { + expect(CLASSIFICATIONS.has(r.classification), `${r.file}: bad classification "${r.classification}"`).toBe(true); + expect(TERMINAL_STATES.has(r.terminalState), `${r.file}: bad terminal state "${r.terminalState}"`).toBe(true); + expect(r.note.length, `${r.file}: every row needs a non-empty note`).toBeGreaterThan(0); + } + }); + + it('divergence column matches reality (audit cannot go stale silently)', () => { + const actual = actualShadowCopies(); + for (const r of parseAudit()) { + const real = actual.get(r.file); + if (!real) continue; // deletion handled in the M8 test below + expect(r.divergence, `${r.file}: audit says "${r.divergence}" but tree says "${real}"`).toBe(real); + } + }); + + it('pending is only ever used with local-unique + an ESCALATED note', () => { + for (const r of parseAudit()) { + if (r.terminalState === 'pending') { + expect(r.classification, `${r.file}: pending requires local-unique`).toBe('local-unique'); + expect(r.note, `${r.file}: a pending row must cite its escalation`).toMatch(/ESCALATED/); + } + if (r.classification === 'rot') { + expect(r.terminalState, `${r.file}: rot rows resolve immediately`).not.toBe('pending'); + } + } + }); + + /** + * Completion guard: "pending escalation" is NOT a terminal state. Flip when + * the architect has ruled on all escalations (before M8 deletion executes). + * The spec's completion rule: all rows in TS1–TS4, zero open escalations. + */ + const ALL_ESCALATIONS_RESOLVED = true; + + it.skipIf(!ALL_ESCALATIONS_RESOLVED)('at completion: zero rows remain pending', () => { + const pending = parseAudit().filter((r) => r.terminalState === 'pending'); + expect(pending.map((r) => r.file)).toEqual([]); + }); + + /** + * M8 process guard (arms itself once deletion starts): any shadow copy that + * no longer exists locally must have been audited as TS1/TS2/TS4 — a file + * that vanished while `pending` or `TS3` (retain!) is a process violation. + */ + it('no file was deleted while pending or marked TS3-retain', () => { + for (const r of parseAudit()) { + const local = path.join(REPO_ROOT, 'codev', r.file); + if (!fs.existsSync(local)) { + expect( + ['TS1', 'TS2', 'TS4'].includes(r.terminalState), + `${r.file} is gone from codev/ but its audit state is "${r.terminalState}" — ` + + `deletion without a resolving ruling is exactly what M11 forbids` + ).toBe(true); + } + } + }); + + /** + * AUTOMATIC completion guard (added after Codex's Phase-2 review): the + * manual ALL_ESCALATIONS_RESOLVED flag can be forgotten; this cannot. + * Deletion is the point of no return — the moment ANY audited file is gone + * from codev/ (i.e. Phase 4 has started), every escalation must already be + * resolved, not just the deleted file's own. Escalations may stay open + * through Phases 2–3 (the spec's design: M3 skips escalated files), but + * never into Phase 4. + */ + it('once deletion has started, zero pending rows may remain anywhere', () => { + const rows = parseAudit(); + const deletionStarted = rows.some( + (r) => !fs.existsSync(path.join(REPO_ROOT, 'codev', r.file)) + ); + if (!deletionStarted) return; // Phases 2–3: open escalations are legitimate + const pending = rows.filter((r) => r.terminalState === 'pending').map((r) => r.file); + expect( + pending, + `Phase 4 deletion has begun but these escalations are unresolved:\n` + + pending.map((p) => ` - ${p}`).join('\n') + + `\nEvery pending row needs an architect ruling (or the TS3 escape hatch + ` + + `follow-up issue) BEFORE any deletion executes (M8 is gated on M11).` + ).toEqual([]); + }); +}); diff --git a/packages/codev/src/__tests__/skeleton-embed-sync.test.ts b/packages/codev/src/__tests__/skeleton-embed-sync.test.ts new file mode 100644 index 000000000..43e352101 --- /dev/null +++ b/packages/codev/src/__tests__/skeleton-embed-sync.test.ts @@ -0,0 +1,78 @@ +/** + * Embedded-skeleton sync guard (Spec 1252, Phase 4 iter-3). + * + * `resolveCodevFile()` serves the EMBEDDED skeleton (`packages/codev/skeleton`, + * a build-time copy made by `pnpm copy-skeleton`), while developers edit the + * SOURCE tree (`codev-skeleton/`). That copy relationship is the same drift + * class this project deleted the codev/ shadow tree over — a stale embedded + * copy would let source-tree tests pass while agents are served old content. + * + * This guard closes the loop: every framework file in the source tree must be + * byte-identical to its embedded counterpart, and vice versa (no extra or + * missing files). With it green, a test that reads `codev-skeleton/...` and a + * test that reads through the resolver are validating the same bytes — the + * source-reading tests guard the commit surface (fail where the dev edits), + * this guard ties that surface to the serving surface. + * + * Skips loudly if the embedded skeleton has not been built. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; +import { getSkeletonDir } from '../lib/skeleton.js'; + +const REPO_ROOT = path.resolve(__dirname, '../../../..'); +const SOURCE_SKELETON = path.join(REPO_ROOT, 'codev-skeleton'); + +const sha = (p: string) => createHash('sha256').update(fs.readFileSync(p)).digest('hex'); + +function walk(dir: string): string[] { + const out: string[] = []; + for (const e of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, e.name); + if (e.isDirectory()) out.push(...walk(p)); + else out.push(p); + } + return out; +} + +describe('embedded skeleton ↔ source skeleton sync', () => { + const embedded = getSkeletonDir(); + const built = fs.existsSync(embedded); + + it('embedded skeleton exists (run `pnpm copy-skeleton` if this fails locally)', () => { + expect(built, `embedded skeleton missing at ${embedded}`).toBe(true); + }); + + it.skipIf(!built)('every source file is embedded byte-identically, and nothing extra ships', () => { + const srcFiles = new Map( + walk(SOURCE_SKELETON).map((p) => [path.relative(SOURCE_SKELETON, p), p]) + ); + const embFiles = new Map(walk(embedded).map((p) => [path.relative(embedded, p), p])); + + const problems: string[] = []; + for (const [rel, srcPath] of srcFiles) { + const embPath = embFiles.get(rel); + if (!embPath) { + problems.push(`missing from embedded: ${rel}`); + } else if (sha(srcPath) !== sha(embPath)) { + problems.push(`stale in embedded: ${rel}`); + } + } + for (const rel of embFiles.keys()) { + if (!srcFiles.has(rel)) problems.push(`embedded but not in source: ${rel}`); + } + + expect( + problems, + problems.length + ? `Embedded skeleton is out of sync with codev-skeleton/ — agents are ` + + `being served different bytes than the source tree tests validate.\n` + + `Run \`pnpm copy-skeleton\` in packages/codev.\n` + + problems.map((p) => ` - ${p}`).join('\n') + : undefined + ).toEqual([]); + }); +}); diff --git a/packages/codev/src/agent-farm/__tests__/baked-decisions.test.ts b/packages/codev/src/agent-farm/__tests__/baked-decisions.test.ts index 3f41e9a6b..221d7f525 100644 --- a/packages/codev/src/agent-farm/__tests__/baked-decisions.test.ts +++ b/packages/codev/src/agent-farm/__tests__/baked-decisions.test.ts @@ -19,6 +19,15 @@ import { describe, it, expect } from 'vitest'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { renderTemplate, type TemplateContext } from '../commands/spawn-roles.js'; +import { resolveCodevIncludes } from '../../lib/skeleton.js'; + +// Spec 1252 (Phase 4): the codev/protocols shadow tree was DELETED — the +// skeleton is the single owner and the resolver serves it at tier 4. The +// codev-vs-skeleton mirror-parity pairs in this file therefore collapsed to +// skeleton-only paths: where an entry once compared two trees, both sides now +// name the same skeleton file (trivially equal, kept for structural +// compatibility with the PHASE tables). The grep-regression value — the baked +// wording exists in what agents are served — is fully preserved. // ============================================================================ // Helpers @@ -28,7 +37,14 @@ const repoRoot = path.resolve(__dirname, '../../../../..'); const baselineDir = path.resolve(__dirname, 'fixtures/baselines'); function readRepoFile(relativePath: string): string { - return fs.readFileSync(path.resolve(repoRoot, relativePath), 'utf-8'); + // Spec 1252 (Phase 7): expand {{> partials/...}} includes so every assertion + // in this suite operates on the SERVED text — shared sections (Baked + // Decisions, flaky handling, PR strategy) now live in single-owner partials + // that assembly expands into each prompt. + return resolveCodevIncludes( + fs.readFileSync(path.resolve(repoRoot, relativePath), 'utf-8'), + repoRoot, + ); } function readBaseline(baselineName: string): string { @@ -79,17 +95,17 @@ interface BuilderPromptFile { const PHASE_1_FILES: BuilderPromptFile[] = [ { label: 'codev SPIR builder-prompt', - relPath: 'codev/protocols/spir/builder-prompt.md', + relPath: 'codev-skeleton/protocols/spir/builder-prompt.md', baselineName: 'spir-builder-prompt.md.baseline', }, { label: 'codev ASPIR builder-prompt', - relPath: 'codev/protocols/aspir/builder-prompt.md', + relPath: 'codev-skeleton/protocols/aspir/builder-prompt.md', baselineName: 'aspir-builder-prompt.md.baseline', }, { label: 'codev AIR builder-prompt', - relPath: 'codev/protocols/air/builder-prompt.md', + relPath: 'codev-skeleton/protocols/air/builder-prompt.md', baselineName: 'air-builder-prompt.md.baseline', }, { @@ -153,53 +169,12 @@ describe('Spec 746 Phase 1: builder-prompt baked-decisions instruction', () => { expect(baseline).not.toContain('## Baked Decisions'); }); - // Mirror-parity for the Baked Decisions paragraph specifically (Phase 1). - // - // The codev/ and codev-skeleton/ copies of each builder-prompt have - // pre-existing structural differences outside this work's scope (skeleton - // has Multi-PR Workflow / Verify Phase sections that codev/ doesn't, and - // a different PR-merged notification string). Those are PRE-EXISTING and - // not Phase 1's responsibility to reconcile. - // - // What IS Phase 1's responsibility: ensure the Baked Decisions paragraph - // itself is byte-identical across both copies, so future drift in this - // paragraph (e.g., someone edits codev/ but forgets skeleton) is caught. - describe('baked-decisions paragraph is byte-identical across codev/ and skeleton', () => { - const PROTOCOLS = ['spir', 'aspir', 'air'] as const; - const BAKED_HEADER = '## Baked Decisions'; - - // Extract the Baked Decisions paragraph from a file's full content. - // Returns the heading + body up to (but not including) the next heading - // or the end of file. Throws if the heading is not found. - function extractBakedSection(label: string, fullContent: string): string { - const headerIdx = fullContent.indexOf(BAKED_HEADER); - if (headerIdx === -1) { - throw new Error(`${label}: "${BAKED_HEADER}" heading not found`); - } - const rest = fullContent.slice(headerIdx); - // Find the next markdown heading line (starts with #, on its own line). - const lines = rest.split('\n'); - const endLine = lines.findIndex( - (line, i) => i > 0 && /^#{1,6}\s/.test(line), - ); - const sectionLines = endLine === -1 ? lines : lines.slice(0, endLine); - // Trim trailing blank lines so a stray newline doesn't cause false mismatches. - while (sectionLines.length > 0 && sectionLines[sectionLines.length - 1].trim() === '') { - sectionLines.pop(); - } - return sectionLines.join('\n'); - } - - for (const protocol of PROTOCOLS) { - it(`${protocol}: codev/ and skeleton Baked Decisions paragraphs match`, () => { - const codevContent = readRepoFile(`codev/protocols/${protocol}/builder-prompt.md`); - const skeletonContent = readRepoFile(`codev-skeleton/protocols/${protocol}/builder-prompt.md`); - const codevSection = extractBakedSection(`codev ${protocol}`, codevContent); - const skeletonSection = extractBakedSection(`skeleton ${protocol}`, skeletonContent); - expect(skeletonSection).toEqual(codevSection); - }); - } - }); + // Spec 1252 (Phase 4): the mirror-parity describe that lived here compared + // the Baked Decisions paragraph across codev/ and codev-skeleton/. The + // codev/ shadow tree is deleted — there is no second tree, so the + // comparison became file-vs-itself and was removed as vacuous. Drift of the + // paragraph is now impossible by construction (single owner), and its + // presence/wording is still asserted by the grep-regression tests above. }); // ============================================================================ @@ -215,17 +190,17 @@ interface DraftingPromptFile { const PHASE_2_FILES: DraftingPromptFile[] = [ { label: 'codev SPIR specify.md', - relPath: 'codev/protocols/spir/prompts/specify.md', + relPath: 'codev-skeleton/protocols/spir/prompts/specify.md', baselineName: 'spir-specify.md.baseline', }, { label: 'codev ASPIR specify.md', - relPath: 'codev/protocols/aspir/prompts/specify.md', + relPath: 'codev-skeleton/protocols/aspir/prompts/specify.md', baselineName: 'aspir-specify.md.baseline', }, { label: 'codev AIR implement.md', - relPath: 'codev/protocols/air/prompts/implement.md', + relPath: 'codev-skeleton/protocols/air/prompts/implement.md', baselineName: 'air-implement.md.baseline', }, { @@ -293,17 +268,17 @@ describe('Spec 746 Phase 2: drafting-prompt baked-decisions clause', () => { const PAIRS: MirrorPair[] = [ { protocol: 'spir specify.md', - codev: 'codev/protocols/spir/prompts/specify.md', + codev: 'codev-skeleton/protocols/spir/prompts/specify.md', skeleton: 'codev-skeleton/protocols/spir/prompts/specify.md', }, { protocol: 'aspir specify.md', - codev: 'codev/protocols/aspir/prompts/specify.md', + codev: 'codev-skeleton/protocols/aspir/prompts/specify.md', skeleton: 'codev-skeleton/protocols/aspir/prompts/specify.md', }, { protocol: 'air implement.md', - codev: 'codev/protocols/air/prompts/implement.md', + codev: 'codev-skeleton/protocols/air/prompts/implement.md', skeleton: 'codev-skeleton/protocols/air/prompts/implement.md', }, ]; @@ -329,13 +304,15 @@ describe('Spec 746 Phase 2: drafting-prompt baked-decisions clause', () => { return sectionLines.join('\n'); } + // Spec 1252 (Phase 4): the codev/ tree is deleted — both sides of each + // former pair now name the same skeleton file, so clause-equality is + // vacuous. What still matters: the clause EXISTS and extracts cleanly on + // the single owner. (Source↔embedded parity is enforced globally by + // skeleton-embed-sync.test.ts.) for (const pair of PAIRS) { - it(`${pair.protocol}: codev/ and skeleton clauses match`, () => { - const codevContent = readRepoFile(pair.codev); - const skeletonContent = readRepoFile(pair.skeleton); - const codevClause = extractBakedClause(`codev ${pair.protocol}`, codevContent); - const skeletonClause = extractBakedClause(`skeleton ${pair.protocol}`, skeletonContent); - expect(skeletonClause).toEqual(codevClause); + it(`${pair.protocol}: baked clause present and extractable`, () => { + const clause = extractBakedClause(pair.protocol, readRepoFile(pair.skeleton)); + expect(clause.length).toBeGreaterThan(0); }); } }); @@ -359,32 +336,32 @@ interface ReviewerPromptFile { const PHASE_3_FILES: ReviewerPromptFile[] = [ { label: 'codev SPIR spec-review', - relPath: 'codev/protocols/spir/consult-types/spec-review.md', + relPath: 'codev-skeleton/protocols/spir/consult-types/spec-review.md', baselineName: 'spir-spec-review.md.baseline', }, { label: 'codev ASPIR spec-review', - relPath: 'codev/protocols/aspir/consult-types/spec-review.md', + relPath: 'codev-skeleton/protocols/aspir/consult-types/spec-review.md', baselineName: 'aspir-spec-review.md.baseline', }, { label: 'codev SPIR plan-review', - relPath: 'codev/protocols/spir/consult-types/plan-review.md', + relPath: 'codev-skeleton/protocols/spir/consult-types/plan-review.md', baselineName: 'spir-plan-review.md.baseline', }, { label: 'codev ASPIR plan-review', - relPath: 'codev/protocols/aspir/consult-types/plan-review.md', + relPath: 'codev-skeleton/protocols/aspir/consult-types/plan-review.md', baselineName: 'aspir-plan-review.md.baseline', }, { label: 'codev AIR impl-review', - relPath: 'codev/protocols/air/consult-types/impl-review.md', + relPath: 'codev-skeleton/protocols/air/consult-types/impl-review.md', baselineName: 'air-impl-review.md.baseline', }, { label: 'codev AIR pr-review', - relPath: 'codev/protocols/air/consult-types/pr-review.md', + relPath: 'codev-skeleton/protocols/air/consult-types/pr-review.md', baselineName: 'air-pr-review.md.baseline', }, { @@ -497,44 +474,42 @@ describe('Spec 746 Phase 3: reviewer-prompt baked-decisions clause', () => { const PAIRS: MirrorPair[] = [ { protocol: 'spir spec-review', - codev: 'codev/protocols/spir/consult-types/spec-review.md', + codev: 'codev-skeleton/protocols/spir/consult-types/spec-review.md', skeleton: 'codev-skeleton/protocols/spir/consult-types/spec-review.md', }, { protocol: 'aspir spec-review', - codev: 'codev/protocols/aspir/consult-types/spec-review.md', + codev: 'codev-skeleton/protocols/aspir/consult-types/spec-review.md', skeleton: 'codev-skeleton/protocols/aspir/consult-types/spec-review.md', }, { protocol: 'spir plan-review', - codev: 'codev/protocols/spir/consult-types/plan-review.md', + codev: 'codev-skeleton/protocols/spir/consult-types/plan-review.md', skeleton: 'codev-skeleton/protocols/spir/consult-types/plan-review.md', }, { protocol: 'aspir plan-review', - codev: 'codev/protocols/aspir/consult-types/plan-review.md', + codev: 'codev-skeleton/protocols/aspir/consult-types/plan-review.md', skeleton: 'codev-skeleton/protocols/aspir/consult-types/plan-review.md', }, { protocol: 'air impl-review', - codev: 'codev/protocols/air/consult-types/impl-review.md', + codev: 'codev-skeleton/protocols/air/consult-types/impl-review.md', skeleton: 'codev-skeleton/protocols/air/consult-types/impl-review.md', }, { protocol: 'air pr-review', - codev: 'codev/protocols/air/consult-types/pr-review.md', + codev: 'codev-skeleton/protocols/air/consult-types/pr-review.md', skeleton: 'codev-skeleton/protocols/air/consult-types/pr-review.md', }, ]; + // Spec 1252 (Phase 4): pairwise equality collapsed to single-owner + // presence — see the note on the earlier PAIRS loop. for (const pair of PAIRS) { - it(`${pair.protocol}: codev/ and skeleton sections match`, () => { - const codevContent = readRepoFile(pair.codev); - const skeletonContent = readRepoFile(pair.skeleton); - // Reuse the same extractBakedSection helper defined at the top of this describe. - const codevSection = extractBakedSection(`codev ${pair.protocol}`, codevContent); - const skeletonSection = extractBakedSection(`skeleton ${pair.protocol}`, skeletonContent); - expect(skeletonSection).toEqual(codevSection); + it(`${pair.protocol}: baked section present and extractable`, () => { + const section = extractBakedSection(pair.protocol, readRepoFile(pair.skeleton)); + expect(section.length).toBeGreaterThan(0); }); } }); @@ -555,9 +530,9 @@ interface ProtocolDocFile { } const PHASE_4_FILES: ProtocolDocFile[] = [ - { label: 'codev SPIR protocol.md', relPath: 'codev/protocols/spir/protocol.md' }, - { label: 'codev ASPIR protocol.md', relPath: 'codev/protocols/aspir/protocol.md' }, - { label: 'codev AIR protocol.md', relPath: 'codev/protocols/air/protocol.md' }, + { label: 'codev SPIR protocol.md', relPath: 'codev-skeleton/protocols/spir/protocol.md' }, + { label: 'codev ASPIR protocol.md', relPath: 'codev-skeleton/protocols/aspir/protocol.md' }, + { label: 'codev AIR protocol.md', relPath: 'codev-skeleton/protocols/air/protocol.md' }, { label: 'skeleton SPIR protocol.md', relPath: 'codev-skeleton/protocols/spir/protocol.md' }, { label: 'skeleton ASPIR protocol.md', relPath: 'codev-skeleton/protocols/aspir/protocol.md' }, { label: 'skeleton AIR protocol.md', relPath: 'codev-skeleton/protocols/air/protocol.md' }, @@ -603,17 +578,17 @@ describe('Spec 746 Phase 4: protocol documentation discoverability paragraph', ( const PAIRS: DocPair[] = [ { protocol: 'spir protocol.md', - codev: 'codev/protocols/spir/protocol.md', + codev: 'codev-skeleton/protocols/spir/protocol.md', skeleton: 'codev-skeleton/protocols/spir/protocol.md', }, { protocol: 'aspir protocol.md', - codev: 'codev/protocols/aspir/protocol.md', + codev: 'codev-skeleton/protocols/aspir/protocol.md', skeleton: 'codev-skeleton/protocols/aspir/protocol.md', }, { protocol: 'air protocol.md', - codev: 'codev/protocols/air/protocol.md', + codev: 'codev-skeleton/protocols/air/protocol.md', skeleton: 'codev-skeleton/protocols/air/protocol.md', }, ]; @@ -635,13 +610,12 @@ describe('Spec 746 Phase 4: protocol documentation discoverability paragraph', ( return sectionLines.join('\n'); } + // Spec 1252 (Phase 4): pairwise equality collapsed to single-owner + // presence — see the note on the earlier PAIRS loop. for (const pair of PAIRS) { - it(`${pair.protocol}: codev/ and skeleton sections match`, () => { - const codevContent = readRepoFile(pair.codev); - const skeletonContent = readRepoFile(pair.skeleton); - const codevSection = extractBakedDocsSection(`codev ${pair.protocol}`, codevContent); - const skeletonSection = extractBakedDocsSection(`skeleton ${pair.protocol}`, skeletonContent); - expect(skeletonSection).toEqual(codevSection); + it(`${pair.protocol}: baked docs section present and extractable`, () => { + const section = extractBakedDocsSection(pair.protocol, readRepoFile(pair.skeleton)); + expect(section.length).toBeGreaterThan(0); }); } }); @@ -660,26 +634,26 @@ describe('Spec 746 Phase 4 final sweep: end-to-end regression check', () => { // - Phase 4: 3 codev + 3 skeleton protocol.md (6) const ALL_TOUCHED_FILES = [ // Phase 1 - 'codev/protocols/spir/builder-prompt.md', - 'codev/protocols/aspir/builder-prompt.md', - 'codev/protocols/air/builder-prompt.md', + 'codev-skeleton/protocols/spir/builder-prompt.md', + 'codev-skeleton/protocols/aspir/builder-prompt.md', + 'codev-skeleton/protocols/air/builder-prompt.md', 'codev-skeleton/protocols/spir/builder-prompt.md', 'codev-skeleton/protocols/aspir/builder-prompt.md', 'codev-skeleton/protocols/air/builder-prompt.md', // Phase 2 - 'codev/protocols/spir/prompts/specify.md', - 'codev/protocols/aspir/prompts/specify.md', - 'codev/protocols/air/prompts/implement.md', + 'codev-skeleton/protocols/spir/prompts/specify.md', + 'codev-skeleton/protocols/aspir/prompts/specify.md', + 'codev-skeleton/protocols/air/prompts/implement.md', 'codev-skeleton/protocols/spir/prompts/specify.md', 'codev-skeleton/protocols/aspir/prompts/specify.md', 'codev-skeleton/protocols/air/prompts/implement.md', // Phase 3 - 'codev/protocols/spir/consult-types/spec-review.md', - 'codev/protocols/aspir/consult-types/spec-review.md', - 'codev/protocols/spir/consult-types/plan-review.md', - 'codev/protocols/aspir/consult-types/plan-review.md', - 'codev/protocols/air/consult-types/impl-review.md', - 'codev/protocols/air/consult-types/pr-review.md', + 'codev-skeleton/protocols/spir/consult-types/spec-review.md', + 'codev-skeleton/protocols/aspir/consult-types/spec-review.md', + 'codev-skeleton/protocols/spir/consult-types/plan-review.md', + 'codev-skeleton/protocols/aspir/consult-types/plan-review.md', + 'codev-skeleton/protocols/air/consult-types/impl-review.md', + 'codev-skeleton/protocols/air/consult-types/pr-review.md', 'codev-skeleton/protocols/spir/consult-types/spec-review.md', 'codev-skeleton/protocols/aspir/consult-types/spec-review.md', 'codev-skeleton/protocols/spir/consult-types/plan-review.md', @@ -687,9 +661,9 @@ describe('Spec 746 Phase 4 final sweep: end-to-end regression check', () => { 'codev-skeleton/protocols/air/consult-types/impl-review.md', 'codev-skeleton/protocols/air/consult-types/pr-review.md', // Phase 4 - 'codev/protocols/spir/protocol.md', - 'codev/protocols/aspir/protocol.md', - 'codev/protocols/air/protocol.md', + 'codev-skeleton/protocols/spir/protocol.md', + 'codev-skeleton/protocols/aspir/protocol.md', + 'codev-skeleton/protocols/air/protocol.md', 'codev-skeleton/protocols/spir/protocol.md', 'codev-skeleton/protocols/aspir/protocol.md', 'codev-skeleton/protocols/air/protocol.md', @@ -754,8 +728,13 @@ describe('Spec 746 end-to-end smoke: builder-prompt rendering with baked-decisio for (const protocol of ['spir', 'aspir', 'air']) { describe(`${protocol} builder-prompt`, () => { - const templatePath = path.resolve(repoRoot, `codev/protocols/${protocol}/builder-prompt.md`); - const template = fs.readFileSync(templatePath, 'utf-8'); + const templatePath = path.resolve(repoRoot, `codev-skeleton/protocols/${protocol}/builder-prompt.md`); + // Spec 1252 (Phase 7): mirror production loading — builder-prompt + // templates are include-expanded ({{> partials/...}}) before rendering. + const template = resolveCodevIncludes( + fs.readFileSync(templatePath, 'utf-8'), + repoRoot, + ); const ctx = makeContext(protocol); const rendered = renderTemplate(template, ctx); @@ -783,9 +762,13 @@ describe('Spec 746 end-to-end smoke: builder-prompt rendering with baked-decisio for (const protocol of ['spir', 'aspir', 'air']) { it(`${protocol} builder-prompt: instruction paragraph is still present (it's unconditional)`, () => { - const template = fs.readFileSync( - path.resolve(repoRoot, `codev/protocols/${protocol}/builder-prompt.md`), - 'utf-8', + // Spec 1252 (Phase 7): expand includes to mirror production loading. + const template = resolveCodevIncludes( + fs.readFileSync( + path.resolve(repoRoot, `codev-skeleton/protocols/${protocol}/builder-prompt.md`), + 'utf-8', + ), + repoRoot, ); const ctx: TemplateContext = { protocol_name: protocol.toUpperCase(), diff --git a/packages/codev/src/agent-farm/__tests__/bugfix-619-aspir-prompt.test.ts b/packages/codev/src/agent-farm/__tests__/bugfix-619-aspir-prompt.test.ts index 63fc0cead..8ca62cf9e 100644 --- a/packages/codev/src/agent-farm/__tests__/bugfix-619-aspir-prompt.test.ts +++ b/packages/codev/src/agent-farm/__tests__/bugfix-619-aspir-prompt.test.ts @@ -77,8 +77,8 @@ describe('has_phases_json check uses regex', () => { const protocolFiles = [ path.resolve(__dirname, '../../../../../codev-skeleton/protocols/aspir/protocol.json'), path.resolve(__dirname, '../../../../../codev-skeleton/protocols/spir/protocol.json'), - path.resolve(__dirname, '../../../../../codev/protocols/aspir/protocol.json'), - path.resolve(__dirname, '../../../../../codev/protocols/spir/protocol.json'), + path.resolve(__dirname, '../../../../../codev-skeleton/protocols/aspir/protocol.json'), + path.resolve(__dirname, '../../../../../codev-skeleton/protocols/spir/protocol.json'), ]; for (const file of protocolFiles) { diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-builder-prompt.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-builder-prompt.md.baseline index 5836e8036..e7998e326 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-builder-prompt.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-builder-prompt.md.baseline @@ -19,14 +19,14 @@ You are running in STRICT mode. This means: - Follow porch signals and gate approvals ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) {{/if}} ## Protocol Follow the AIR protocol. Read and internalize the protocol before starting any work. The full protocol text is included below under **## Protocol Reference (full text)**. -{{#if issue}} ## Issue #{{issue.number}} **Title**: {{issue.title}} @@ -57,13 +57,19 @@ Always use `afx send architect "..."` to notify the architect at key moments: ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks +1. Never hand-edit `status.yaml` — only porch commands modify project state. 2. **DO NOT** skip porch checks or use any workaround to avoid the failure 3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in the PR body under a "Flaky Tests" section +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) 5. Commit the skip and continue with your work ## Getting Started 1. Read the AIR protocol 2. Review the issue details 3. Implement the feature + +--- + +## Protocol Reference (full text) + +{{protocol_reference}} diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-implement.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-implement.md.baseline index 52767f21a..516a20ec7 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-implement.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/air-implement.md.baseline @@ -57,7 +57,7 @@ Fix any failures before proceeding. If build/test commands don't exist, check `p ### 5. Commit Stage and commit your changes: -- Use explicit file paths (never `git add -A` or `git add .`) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. - Commit message: `[Air #{{issue.number}}] feat: ` ## Signals diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-builder-prompt.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-builder-prompt.md.baseline index a50bdd6a8..3b6b579c4 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-builder-prompt.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-builder-prompt.md.baseline @@ -20,8 +20,9 @@ You are running in STRICT mode. This means: - Do not deviate from the porch-driven workflow ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) - **NEVER skip the 3-way review** — always follow porch next → porch done cycle - **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval {{/if}} @@ -52,23 +53,62 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: + +1. Cut a branch, open a PR, wait for merge +2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) +3. Continue to the next slice, open another PR +4. Repeat + +**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. + +Record PRs in status.yaml: `porch done {{project_id}} --pr --branch ` +Record merges: `porch done {{project_id}} --merged ` + +## Verify Phase + +After the final PR merges, the project enters the **verify** phase. You stay alive through verify: +1. Pull the integration branch into your worktree +2. Run `porch done {{project_id}}` to signal verification is ready +3. The architect approves `verify-approval` when satisfied + +If verification is not needed: `porch verify {{project_id}} --skip "reason"` + ## Notifications Always use `afx send architect "..."` to notify the architect at key moments: - **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` - **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} complete. PR merged. Ready for cleanup."` +- **PR merged**: `afx send architect "Project {{project_id}} PR merged. Entering verify phase."` - **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks +1. Never hand-edit `status.yaml` — only porch commands modify project state. 2. **DO NOT** skip porch checks or use any workaround to avoid the failure 3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) 5. Commit the skip and continue with your work ## Getting Started 1. Read the protocol document thoroughly 2. Review the spec and plan (if available) 3. Begin implementation following the protocol phases + +--- + +## Protocol Reference (full text) + +{{protocol_reference}} diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-specify.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-specify.md.baseline index 6da1868f8..9fc41e266 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-specify.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/aspir-specify.md.baseline @@ -119,7 +119,7 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Specification with user feedback` 4. `[Spec {{project_id}}] Final approved specification` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/specs/{{artifact_name}}.md ``` @@ -134,6 +134,6 @@ git add codev/specs/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) +- Don't estimate time — AI development makes time estimates meaningless - Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-builder-prompt.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-builder-prompt.md.baseline index f56f68082..51f9ea25a 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-builder-prompt.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-builder-prompt.md.baseline @@ -20,8 +20,9 @@ You are running in STRICT mode. This means: - Do not deviate from the porch-driven workflow ### ABSOLUTE RESTRICTIONS (STRICT MODE) -- **NEVER edit `status.yaml` directly** — only porch commands may modify project state -- **NEVER call `porch approve` without explicit human approval** — only run it after the architect says to +- Never hand-edit `status.yaml` — only porch commands modify project state. +- Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization. + (Run `porch approve` only after the architect relays the human decision.) - **NEVER skip the 3-way review** — always follow porch next → porch done cycle - **NEVER advance plan phases manually** — porch handles phase transitions after unanimous review approval {{/if}} @@ -52,23 +53,62 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: + +1. Cut a branch, open a PR, wait for merge +2. After merge: `git fetch origin && git checkout -b origin/` — where `` is the branch the architect targets PRs at (usually `main`; check the open PR's `baseRefName` if unsure) +3. Continue to the next slice, open another PR +4. Repeat + +**Important**: Do NOT run `git checkout ` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/` via fetch. + +Record PRs in status.yaml: `porch done {{project_id}} --pr --branch ` +Record merges: `porch done {{project_id}} --merged ` + +## Verify Phase + +After the final PR merges, the project enters the **verify** phase. You stay alive through verify: +1. Pull the integration branch into your worktree +2. Run `porch done {{project_id}}` to signal verification is ready +3. The architect approves `verify-approval` when satisfied + +If verification is not needed: `porch verify {{project_id}} --skip "reason"` + ## Notifications Always use `afx send architect "..."` to notify the architect at key moments: - **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` - **PR ready**: `afx send architect "PR #N ready for review (project {{project_id}})"` -- **PR merged**: `afx send architect "Project {{project_id}} complete. PR merged. Ready for cleanup."` +- **PR merged**: `afx send architect "Project {{project_id}} PR merged. Entering verify phase."` - **Blocked**: `afx send architect "Blocked on project {{project_id}}: [reason]"` ## Handling Flaky Tests If you encounter **pre-existing flaky tests** (intermittent failures unrelated to your changes): -1. **DO NOT** edit `status.yaml` to bypass checks +1. Never hand-edit `status.yaml` — only porch commands modify project state. 2. **DO NOT** skip porch checks or use any workaround to avoid the failure 3. **DO** mark the test as skipped with a clear annotation (e.g., `it.skip('...') // FLAKY: skipped pending investigation`) -4. **DO** document each skipped flaky test in your review under a `## Flaky Tests` section +4. **DO** document each skipped flaky test under a "Flaky Tests" section in the artifact where your protocol records outcomes (review file, PR body, findings, or maintenance-run file) 5. Commit the skip and continue with your work ## Getting Started 1. Read the protocol document thoroughly 2. Review the spec and plan (if available) 3. Begin implementation following the protocol phases + +--- + +## Protocol Reference (full text) + +{{protocol_reference}} diff --git a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-specify.md.baseline b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-specify.md.baseline index 6da1868f8..9fc41e266 100644 --- a/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-specify.md.baseline +++ b/packages/codev/src/agent-farm/__tests__/fixtures/baselines/spir-specify.md.baseline @@ -119,7 +119,7 @@ Make commits at these milestones: 3. `[Spec {{project_id}}] Specification with user feedback` 4. `[Spec {{project_id}}] Final approved specification` -**CRITICAL**: Never use `git add .` or `git add -A`. Always stage specific files: +**CRITICAL**: Never `git add -A` / `--all` / `.` — stage each file explicitly by path. For example: ```bash git add codev/specs/{{artifact_name}}.md ``` @@ -134,6 +134,6 @@ git add codev/specs/{{artifact_name}}.md - Don't run `consult` commands yourself (porch handles consultations) - Don't include implementation details (that's for the Plan phase) -- Don't estimate time (AI makes time estimates meaningless) +- Don't estimate time — AI development makes time estimates meaningless - Don't start coding (you're in Specify, not Implement) -- Don't use `git add .` or `git add -A` (security risk) +- Never `git add -A` / `--all` / `.` — stage each file explicitly by path. diff --git a/packages/codev/src/agent-farm/commands/spawn-roles.ts b/packages/codev/src/agent-farm/commands/spawn-roles.ts index 66189c7c4..ac99b454d 100644 --- a/packages/codev/src/agent-farm/commands/spawn-roles.ts +++ b/packages/codev/src/agent-farm/commands/spawn-roles.ts @@ -105,7 +105,11 @@ function loadBuilderPromptTemplate(config: Config, protocolName: string): string if (!templatePath) { return null; } - return readFileSync(templatePath, 'utf-8'); + // Spec 1252 (Phase 7): expand {{> partials/...}} includes so template-family + // content (shared blocks across protocol builder-prompts) can have a single + // authored owner while every served prompt still carries the full text. + // Mirrors the existing include expansion on the protocol_reference path. + return resolveCodevIncludes(readFileSync(templatePath, 'utf-8'), config.workspaceRoot); } /** @@ -163,6 +167,21 @@ export function buildPromptFromTemplate( * Build a resume notice to prepend to the builder prompt. * Tells the builder this is a resumed session and to check existing porch state. */ +/** + * The one-line builder preamble prepended to every spawn prompt. + * + * Single owner for a sentence that was previously hardcoded at four call + * sites in spawn.ts (Spec 1252). It used to say "Read codev/roles/builder.md" + * — a literal-path fetch instruction (the #1011 bug class) that broke in + * fresh installs and, after Spec 1252 deleted the codev/roles shadow tree, + * pointed at a deleted path everywhere. The role is not fetched by the + * builder at all: spawn injects it via the harness system prompt and writes a + * copy to .builder-role.md in the worktree. + */ +export function builderPreamble(): string { + return 'You are a Builder. Your full role definition is delivered via your system prompt (with default role injection, a copy is also written to `.builder-role.md` in your worktree).'; +} + export function buildResumeNotice(_projectId: string): string { return `## RESUME SESSION diff --git a/packages/codev/src/agent-farm/commands/spawn.ts b/packages/codev/src/agent-farm/commands/spawn.ts index 217398f43..1a046d560 100644 --- a/packages/codev/src/agent-farm/commands/spawn.ts +++ b/packages/codev/src/agent-farm/commands/spawn.ts @@ -48,6 +48,7 @@ import { validateProtocol, loadProtocol, resolveMode, + builderPreamble, } from './spawn-roles.js'; import { getResolver } from '../../commands/porch/artifacts.js'; import { @@ -475,7 +476,7 @@ async function spawnSpec(options: SpawnOptions, config: Config): Promise { const branchNotice = options.branch ? `\n## Existing Branch\nYou are continuing work on existing branch \`${options.branch}\`. This branch may have commits from another contributor. Review the existing commits before making changes.\n` : ''; - const builderPrompt = `You are a Builder. Read codev/roles/builder.md for your full role definition.\n${resumeNotice}${branchNotice}\n${initialPrompt}`; + const builderPrompt = `${builderPreamble()}\n${resumeNotice}${branchNotice}\n${initialPrompt}`; const role = options.noRole ? null : loadRolePrompt(config, 'builder'); const commands = getResolvedCommands(); @@ -543,12 +544,12 @@ async function spawnTask(options: SpawnOptions, config: Config): Promise { project_id: builderId, input_description: 'an ad-hoc task', task_text: taskDescription, }; const prompt = buildPromptFromTemplate(config, protocol, templateContext); - builderPrompt = `You are a Builder. Read codev/roles/builder.md for your full role definition.\n${resumeNotice}\n${prompt}`; + builderPrompt = `${builderPreamble()}\n${resumeNotice}\n${prompt}`; if (!options.resume) { await initPorchInWorktree(worktreePath, protocol, builderId, worktreeName); } } else { - builderPrompt = `You are a Builder. Read codev/roles/builder.md for your full role definition.\n${resumeNotice}\n# Task\n\n${taskDescription}`; + builderPrompt = `${builderPreamble()}\n${resumeNotice}\n# Task\n\n${taskDescription}`; } const role = options.noRole ? null : loadRolePrompt(config, 'builder'); @@ -845,7 +846,7 @@ async function spawnIssueDrivenBuilder( const branchNotice = options.branch ? `\n## Existing Branch\nYou are continuing work on existing branch \`${options.branch}\`. This branch may have commits from another contributor. Review the existing commits before making changes.\n` : ''; - const builderPrompt = `You are a Builder. Read codev/roles/builder.md for your full role definition.\n${resumeNotice}${branchNotice}\n${prompt}`; + const builderPrompt = `${builderPreamble()}\n${resumeNotice}${branchNotice}\n${prompt}`; const resume = discoverResumeSession(worktreePath, options.resume, getBuilderHarness(config.workspaceRoot)); const role = options.noRole ? null : loadRolePrompt(config, 'builder'); diff --git a/packages/codev/src/lib/prompt-behavior-metrics.ts b/packages/codev/src/lib/prompt-behavior-metrics.ts new file mode 100644 index 000000000..e325c440f --- /dev/null +++ b/packages/codev/src/lib/prompt-behavior-metrics.ts @@ -0,0 +1,388 @@ +/** + * prompt-behavior-metrics.ts — behavioural-impact measurement of prompt changes. + * Spec 1252, criterion M12 / Appendix D / test T14. + * + * Lives in `src/lib/` beside `protocol-drift-audit.ts` and + * `framework-ref-audit.ts` — same module shape (a measurement library, unit + * tested), and it needs this package's `js-yaml` dependency, which a root-level + * `scripts/` file cannot resolve in this pnpm workspace. The runnable entry + * point is `packages/codev/scripts/measure-prompt-behavior.ts`. + * + * ## Why this exists + * + * M6 counts words. A word reduction that degrades agent compliance is a loss, + * and word counts cannot see that. This script measures BEHAVIOUR: how often + * reviewers demand changes, how many rounds phases take, and whether scar rules + * are being violated. + * + * Run at Phase 1 (before any prompt content changes) to produce the baseline, + * and again in the post-merge verify phase to compare. + * + * ## What is deliberately NOT measured, and why + * + * Two metrics were requested and cannot be delivered from committed history. + * They are omitted rather than faked, because a plausible-looking zero is worse + * than an absent metric: + * + * - GATE REJECTION COUNTS. Across all projects, a gate's `status` only ever + * takes `approved | complete | in_progress | pending` — there is no + * `rejected` state — and `requested_at` is a scalar that a re-request + * OVERWRITES rather than appends to. A rejected-then-approved gate is + * indistinguishable from a clean first-time approval. (Making this minable + * would need porch to append gate events; out of scope here.) + * + * - HISTORICAL CONSULT TOKENS/COST. Raw consult logs (`codev/projects/*​/*.txt`) + * are gitignored, and `consult stats` is a rolling 30-day machine-local DB. + * There is no historical series to baseline against, so B5 is captured as a + * FORWARD snapshot only — advisory, non-deterministic, and excluded from + * T14's determinism assertion and from every rollback trigger. + * + * Usage (from packages/codev): + * npx tsx scripts/measure-prompt-behavior.ts [repo-root] + * npx tsx scripts/measure-prompt-behavior.ts --json + */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as yaml from 'js-yaml'; + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +type Verdict = 'APPROVE' | 'REQUEST_CHANGES' | 'COMMENT' | string; + +interface ReviewRec { + model?: string; + verdict?: Verdict; +} +interface HistoryItem { + iteration?: number; + plan_phase?: string | null; + reviews?: ReviewRec[]; +} +interface StatusYaml { + id?: string; + protocol?: string; + history?: HistoryItem[]; +} + +export interface ScarHit { + rule: string; + file: string; + line: number; + excerpt: string; +} + +export interface BehaviorMetrics { + /** B1 — share of all CMAP verdicts that are REQUEST_CHANGES. */ + b1_requestChangesRate: number; + b1_verdictCounts: Record; + b1_totalVerdicts: number; + /** B2 — review rounds per plan phase: max(iteration) per plan_phase. */ + b2_roundsPerPhaseMean: number; + b2_roundsPerPhaseMedian: number; + b2_roundsPerPhaseMax: number; + b2_phaseCount: number; + /** B3 — candidate scar-rule violations (REQUIRES HUMAN ADJUDICATION). */ + b3_candidateHits: ScarHit[]; + b3_filesScanned: number; + /** B4 — review rounds per project. */ + b4_roundsPerProjectMean: number; + b4_roundsPerProjectMedian: number; + b4_projectCount: number; + /** Sample provenance. */ + sampleProjects: string[]; +} + +// --------------------------------------------------------------------------- +// The eight ratified scar rules (decision D3) and their violation markers. +// +// These patterns look for the DANGEROUS COMMAND / ACT, not for the rule text. +// That is still fuzzy: documentation *about* a rule reads much like a violation +// of it. Hence excerpts, not just counts — a human adjudicates before the hard +// rollback trigger fires. +// --------------------------------------------------------------------------- + +const SCAR_PATTERNS: Array<{ rule: string; re: RegExp }> = [ + { rule: 'git-add-all', re: /\bgit\s+add\s+(-A\b|--all\b|\.(?:\s|$))/ }, + { rule: 'destroy-worktree', re: /\bgit\s+worktree\s+remove\b|\bgit\s+branch\s+-D\b/ }, + { rule: 'destructive-git', re: /\bgit\s+(reset\s+--hard|checkout\s+--\s+\.|clean\s+-[a-z]*f|stash\b)/ }, + { rule: 'auto-approve-gate', re: /auto-?approv\w*/i }, + { rule: 'hand-edit-status', re: /(hand|manual\w*)[- ]edit\w*\s+status\.yaml|edited?\s+status\.yaml\s+(directly|by hand)/i }, + { rule: 'afx-from-worktree', re: /\bafx\s+spawn\b[^\n]*\bfrom\s+(inside\s+)?(a\s+)?worktree/i }, + { rule: 'kill-shellper', re: /kill\w*\s+[^\n]{0,40}shellper/i }, + { rule: 'restart-tower', re: /\b(restart|stop)\w*\s+tower\b/i }, +]; + +/** Phrases indicating the surrounding text DESCRIBES a rule rather than reports a breach. */ +const DOCUMENTATION_MARKERS = + /\b(never|do not|don'?t|must not|forbidden|prohibited|avoid|rule|policy|reminder|guard|prevent)\b/i; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function mean(xs: number[]): number { + return xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0; +} +function median(xs: number[]): number { + if (!xs.length) return 0; + const s = [...xs].sort((a, b) => a - b); + const m = Math.floor(s.length / 2); + return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2; +} +function round2(n: number): number { + return Math.round(n * 100) / 100; +} + +function walk(dir: string, pred: (p: string) => boolean): string[] { + if (!fs.existsSync(dir)) return []; + const out: string[] = []; + for (const e of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, e.name); + if (e.isDirectory()) out.push(...walk(p, pred)); + else if (pred(p)) out.push(p); + } + return out; +} + +// --------------------------------------------------------------------------- +// Metric collection +// --------------------------------------------------------------------------- + +/** + * B1/B2/B4 — CMAP verdicts and review rounds. + * + * Sample: projects whose `status.yaml` has a non-empty `history`. In practice + * this is SPIR (and one legacy `spider`) — porch only persists per-plan-phase + * review history for protocols that loop that way, so pir/bugfix/air contribute + * nothing. Sorted for deterministic output. + */ +function collectReviewMetrics(root: string, excludeProjects: string[]) { + const projDir = path.join(root, 'codev', 'projects'); + const files = fs.existsSync(projDir) + ? fs + .readdirSync(projDir) + .filter((d) => !excludeProjects.includes(d)) + .map((d) => path.join(projDir, d, 'status.yaml')) + .filter((f) => fs.existsSync(f)) + .sort() + : []; + + const verdictCounts: Record = {}; + const phaseRounds: number[] = []; + const projectRounds: number[] = []; + const sampleProjects: string[] = []; + + for (const f of files) { + let doc: StatusYaml; + try { + doc = yaml.load(fs.readFileSync(f, 'utf-8')) as StatusYaml; + } catch { + continue; // a malformed status file must not abort the measurement + } + const history = doc?.history ?? []; + if (!history.length) continue; + + sampleProjects.push(path.basename(path.dirname(f))); + + const byPhase = new Map(); + for (const item of history) { + for (const r of item.reviews ?? []) { + const v = r.verdict ?? 'UNKNOWN'; + verdictCounts[v] = (verdictCounts[v] ?? 0) + 1; + } + const ph = item.plan_phase ?? '__none__'; + byPhase.set(ph, Math.max(byPhase.get(ph) ?? 0, item.iteration ?? 0)); + } + const rounds = [...byPhase.values()]; + phaseRounds.push(...rounds); + projectRounds.push(rounds.reduce((a, b) => a + b, 0)); + } + + const total = Object.values(verdictCounts).reduce((a, b) => a + b, 0); + return { + verdictCounts, + total, + rcRate: total ? (verdictCounts['REQUEST_CHANGES'] ?? 0) / total : 0, + phaseRounds, + projectRounds, + sampleProjects: sampleProjects.sort(), + }; +} + +/** + * B3 — candidate scar-rule violations mined from committed prose. + * + * Scans `codev/reviews/*.md` and `codev/state/*_thread.md`. Emits EXCERPTS, not + * just counts: the mining cannot distinguish "we violated this" from "never do + * this", so every hit is a candidate requiring human adjudication. Lines that + * look like rule documentation are filtered out to cut the obvious noise, but + * the filter is conservative by design — it is better to hand a human a false + * positive than to silently drop a real breach. + */ +function collectScarHits(root: string, excludeBasenamePrefixes: string[]) { + const excluded = (p: string) => + excludeBasenamePrefixes.some((pre) => path.basename(p).startsWith(pre)); + const targets = [ + ...walk(path.join(root, 'codev', 'reviews'), (p) => p.endsWith('.md')), + ...walk(path.join(root, 'codev', 'state'), (p) => p.endsWith('_thread.md')), + ] + .filter((p) => !excluded(p)) + .sort(); + + const hits: ScarHit[] = []; + for (const file of targets) { + const lines = fs.readFileSync(file, 'utf-8').split('\n'); + lines.forEach((line, i) => { + if (DOCUMENTATION_MARKERS.test(line)) return; // prescriptive, not a breach report + for (const { rule, re } of SCAR_PATTERNS) { + if (re.test(line)) { + hits.push({ + rule, + file: path.relative(root, file), + line: i + 1, + excerpt: line.trim().slice(0, 200), + }); + break; + } + } + }); + } + return { hits, filesScanned: targets.length }; +} + +export interface MeasureOptions { + /** + * Project directory names to exclude from B1/B2/B4. + * + * The baseline is defined as the PRE-PROJECT state (spec 1252, M12): the + * project doing the measuring must not contaminate its own baseline. Its + * review verdicts accumulate in its status.yaml *while it runs*, so an + * unexcluded rerun mid-project would drift from the committed artifact — + * which is exactly how this option came to exist (the Phase-1 reproduction + * test failed the moment this project's own iter-1 review landed). + */ + excludeProjects?: string[]; + /** + * Basename prefixes excluded from B3's prose scan, for the same reason: this + * project's own thread/review discuss scar rules at length and grow with + * every phase, so scanning them makes B3 non-reproducible AND self-inflating. + */ + excludeFilePrefixes?: string[]; +} + +/** This project's own artifacts — excluded from its own baseline by default. */ +export const SELF_PROJECT_DIR = '1252-prompt-architecture-single-own'; +export const SELF_FILE_PREFIXES = ['spir-1252_', '1252-']; + +/** Collect all behavioural metrics for a repo root. Deterministic over B1–B4. */ +export function measureBehavior(root: string, opts: MeasureOptions = {}): BehaviorMetrics { + const rv = collectReviewMetrics(root, opts.excludeProjects ?? [SELF_PROJECT_DIR]); + const scar = collectScarHits(root, opts.excludeFilePrefixes ?? SELF_FILE_PREFIXES); + return { + b1_requestChangesRate: round2(rv.rcRate * 100), + b1_verdictCounts: rv.verdictCounts, + b1_totalVerdicts: rv.total, + b2_roundsPerPhaseMean: round2(mean(rv.phaseRounds)), + b2_roundsPerPhaseMedian: median(rv.phaseRounds), + b2_roundsPerPhaseMax: rv.phaseRounds.length ? Math.max(...rv.phaseRounds) : 0, + b2_phaseCount: rv.phaseRounds.length, + b3_candidateHits: scar.hits, + b3_filesScanned: scar.filesScanned, + b4_roundsPerProjectMean: round2(mean(rv.projectRounds)), + b4_roundsPerProjectMedian: median(rv.projectRounds), + b4_projectCount: rv.projectRounds.length, + sampleProjects: rv.sampleProjects, + }; +} + +// --------------------------------------------------------------------------- +// Rendering +// --------------------------------------------------------------------------- + +/** Render metrics as the committed markdown baseline artifact. */ +export function render(m: BehaviorMetrics): string { + const byRule = new Map(); + for (const h of m.b3_candidateHits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1); + + const lines: string[] = [ + '# Behavioural metrics (Spec 1252, M12 / Appendix D)', + '', + '## B1 — CMAP verdict distribution', + '', + `Total verdicts: **${m.b1_totalVerdicts}** across ${m.b4_projectCount} projects with review history.`, + '', + '| Verdict | Count | Share |', + '|---|---:|---:|', + ...Object.entries(m.b1_verdictCounts) + .sort((a, b) => b[1] - a[1]) + .map( + ([v, c]) => + `| ${v} | ${c} | ${round2((c / Math.max(m.b1_totalVerdicts, 1)) * 100)}% |` + ), + '', + `**B1 REQUEST_CHANGES rate: ${m.b1_requestChangesRate}%** — the load-bearing metric.`, + '', + '## B2 — review rounds per plan phase', + '', + `mean **${m.b2_roundsPerPhaseMean}**, median ${m.b2_roundsPerPhaseMedian}, max ${m.b2_roundsPerPhaseMax} (n=${m.b2_phaseCount} phases)`, + '', + '> Advisory only. The observed range is too narrow to detect a subtle', + '> regression. Note also that phases advance on builder *rebuttal*, not on', + '> unanimous approval — 0 terminal phases in this corpus end with 3x APPROVE —', + '> so a "rounds to unanimity" metric would never resolve.', + '', + '## B4 — review rounds per project', + '', + `mean **${m.b4_roundsPerProjectMean}**, median ${m.b4_roundsPerProjectMedian} (n=${m.b4_projectCount} projects). Advisory.`, + '', + '## B3 — candidate scar-rule violations', + '', + `Scanned **${m.b3_filesScanned}** files (codev/reviews + codev/state threads).`, + `Candidate hits: **${m.b3_candidateHits.length}**`, + '', + '> **These are CANDIDATES, not findings.** Keyword mining cannot distinguish', + '> "we did this" from "never do this". Every hit requires human adjudication', + '> before the hard rollback trigger fires. B3 is the metric that matters most —', + '> it is the only one that would catch a compressed scar rule losing its force.', + '', + ]; + + if (byRule.size) { + lines.push('| Rule | Candidate hits |', '|---|---:|'); + for (const [r, c] of [...byRule.entries()].sort((a, b) => b[1] - a[1])) { + lines.push(`| ${r} | ${c} |`); + } + lines.push('', '### Excerpts for adjudication', ''); + for (const h of m.b3_candidateHits.slice(0, 50)) { + lines.push(`- \`${h.file}:${h.line}\` **[${h.rule}]** — ${h.excerpt}`); + } + if (m.b3_candidateHits.length > 50) { + lines.push(`- …and ${m.b3_candidateHits.length - 50} more (see --json for the full list)`); + } + lines.push(''); + } + + lines.push( + '## B5 — consult cost/duration', + '', + '**Not captured here.** `consult stats` is a rolling 30-day machine-local DB,', + 'so it is not reproducible from a commit. Capture it separately as advisory', + 'context; it is excluded from T14 determinism and drives no rollback trigger.', + '', + '## Sample provenance', + '', + ...m.sampleProjects.map((p) => `- ${p}`), + '' + ); + return lines.join('\n'); +} + +/** CLI entry, invoked by `packages/codev/scripts/measure-prompt-behavior.ts`. */ +export function runCli(argv: string[], cwd: string): string { + const json = argv.includes('--json'); + const root = argv.find((a) => !a.startsWith('--')) ?? cwd; + const m = measureBehavior(path.resolve(root)); + return json ? JSON.stringify(m, null, 2) : render(m); +} diff --git a/packages/codev/src/lib/prompt-ownership.ts b/packages/codev/src/lib/prompt-ownership.ts new file mode 100644 index 000000000..d145fc81e --- /dev/null +++ b/packages/codev/src/lib/prompt-ownership.ts @@ -0,0 +1,252 @@ +/** + * prompt-ownership.ts — the machine-readable ownership map and its + * completeness machinery (Spec 1252, M1/M4 — Appendix A). + * + * The single-owner rule: every instruction has exactly one owning surface; + * other surfaces reference, never restate. This module provides: + * + * - the mechanical CANDIDATE EXTRACTOR: normative statements (MUST/NEVER/ + * ALWAYS/DO NOT/Don't/Never …) collected from the declared inventory + * boundary, each with a stable id; + * - the map loader/validator for codev/resources/prompt-ownership.yaml; + * - disposition resolution: every candidate must be `mapped`, `scar`, or + * `out-of-scope` (with justification) — there is no fourth state, so the + * map cannot rot silently as the prompt surface grows (T12). + * + * Why dispositions support pattern matching rather than per-line ids: the + * boundary yields hundreds of normative lines, most of them phase-prompt + * process instructions that are individually owned by their file. Requiring a + * one-to-one disposition per line would make the map unmaintainable, which is + * how maps die. A disposition entry covers a family via `match` (substring or + * /regex/), carries one justification, and first-match-wins keeps resolution + * deterministic. + */ + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; +import * as yaml from 'js-yaml'; + +// --------------------------------------------------------------------------- +// Types (mirror Appendix A) +// --------------------------------------------------------------------------- + +export interface OwnedSurface { + id: string; + path: string; + load: 'always-on' | 'spawn' | 'phase-prompt' | 'on-demand'; +} + +export interface InstructionClass { + id: string; + summary: string; + /** Surface id — exactly one owner. */ + owner: string; + scar: boolean; + /** Detection pattern: substring, or /regex/ when slash-delimited. */ + pattern: string; + enforcement: 'automated' | 'manual'; + /** For scar rules: surfaces that must all carry it (mirrors scar-rules.yaml). */ + must_appear_on?: string[]; + /** For non-scar: surfaces allowed to carry a one-line POINTER — pointers + * must NOT reproduce the rule text (they never trip the pattern; T7 + * enforces that). */ + references?: string[]; + /** Declared TS3-style retained restatements: surfaces that keep a full, + * protocol-specific variant by decision. T7 exempts exactly these, and + * each class using this field must justify it. Distinct from `references` + * so pointer surfaces stay pattern-forbidden (Codex, Phase-6 iter-2). */ + retained_restatements?: string[]; + /** Required for enforcement: manual — why no reliable pattern exists. */ + manual_justification?: string; + /** Max occurrences of the pattern permitted in ONE served artifact + * (default 1). Raised only with a comment when a declared retention is + * inlined into the same assembly (e.g. the protocol doc's description of + * the baked-decisions convention rides into every spawn prompt beside the + * instruction section itself). */ + served_max?: number; +} + +export interface Disposition { + /** Substring, or /regex/ when slash-delimited. Matched against the LINE. */ + match: string; + disposition: 'mapped' | 'scar' | 'out-of-scope'; + /** Instruction-class id (required when disposition is `mapped`). */ + class?: string; + /** Justification (required when disposition is `out-of-scope`). */ + note?: string; + /** + * A catch-all may only absorb SINGLE-FILE candidates. Any candidate whose + * text appears on 2+ files must resolve via a specific entry — otherwise + * the catch-all would make completeness vacuous for exactly the failure + * class (cross-surface duplication) the single-owner rule targets. + */ + catch_all?: boolean; +} + +export interface OwnershipMap { + inventory_boundary: string[]; + surfaces: OwnedSurface[]; + instructions: InstructionClass[]; + dispositions: Disposition[]; +} + +export interface Candidate { + file: string; + line: number; + text: string; + /** sha1 of file-relative normalized text — stable across line-number drift. */ + id: string; +} + +// --------------------------------------------------------------------------- +// Extraction +// --------------------------------------------------------------------------- + +/** + * A line is a normative candidate when it contains an imperative/prohibitive + * construction. Deliberately coarse — over-collecting is safe (a candidate + * just needs a disposition), under-collecting silently exempts content. + */ +const NORMATIVE = /\b(must(?:\s+not)?|never|always|do(?:\s+|n')t?\s*not?|don't|do not)\b/i; + +/** Lines that are markdown noise, not instructions. */ +const NOISE = /^\s*(#|```|\||