Skip to content

Latest commit

 

History

History
2230 lines (1766 loc) · 243 KB

codeboost-plan-indexed-review.md

File metadata and controls

2230 lines (1766 loc) · 243 KB

codeboost design: review AI-made pull requests one plan item at a time

Generated by /office-hours on 2026-09-22 Branch: main Repo: codeabovelab/codeboost Status: APPROVED Mode: Builder (open source / research) Writing standard: plain language, ISO 24495-1:2023 Last checked against the code: 2026-09-26 (see "Lane status" under "Parallel build lanes"). The summary and build-step status were updated later as lanes merged. For the current state of each lane, see the lane table in docs/architecture.md.

About this document

Who it is for. You, the builder of codeboost. Also future contributors, and anyone running an engineering review of this design.

What it is for. It records what we decided to build, and why. The next step, an engineering review (/plan-eng-review), starts from this document.

How to read it.

  • Read the Summary first. It fits on one screen.
  • Special words, such as "segment" and "stale approval," are defined in Terms used, just below the Summary.
  • Use the headings to jump to one topic. Each section stands on its own.

Summary

  • What codeboost is. A local app that takes GitHub issues, helps you write a detailed plan with Claude or Codex, runs the plan with an AI agent, and opens a pull request (PR).
  • What makes it different. You review the PR one plan item at a time. Pick a plan item on the left and see only its code on the right. Code that belongs to no plan item is flagged in a red "Unplanned changes" row.
  • Why that matters. Other tools make you read a raw diff and guess what the agent meant. In codeboost, the plan you approved is the index to the code.
  • How it stays trustworthy. codeboost records commits in a trusted ledger with either an owning plan item or an explicit foreign/unowned classification. Rewriting a foreign commit never turns it into owned work. It also checks each change against the files the plan item said it would touch. One blind spot remains: an unrelated edit inside a file the plan item declared is caught only by the review agent and by you.
  • How it stays safe. Agents run inside a container that holds only the task's code and the credential for that phase, so your other files and credentials are not there. Ask, code-writing runs, and conflict resolution use provider-specific containers; exact-head cmd: checks use a credential-free read-only profile. codeboost needs your approval before its own dependency installation or invocation of changed scripts; containment must also cover commands the agent already ran.
  • It learns from you. After each task, codeboost turns your feedback into short lessons. You approve each lesson before agents use it, and a Learning screen shows whether you are repeating yourself less.
  • Where the build is. Built: the plan and linking library, SQLite store, review screen with Ask and change requests, guarded merge gate with merge-queue support, agent isolation boundary, Plans screen (lane G, #145; #155 lists unbuilt parts and #159 tracks suggestion-card non-conformance), opt-in code-writing runner and publishing, durable local rebase/conflict resolution, and pre-merge base/head refresh with exact-head cmd: checks. Still deferred: pushing the rewritten head, waiting for its required checks, handing that exact pair to guarded merge, and the Queue, Lessons and Learning screens (the ranked Issues screen is built). Optional real-PR validation is tracked separately in #19 and is not a prerequisite.

Terms used

Term Meaning
Plan A list of plan items for one GitHub issue. Each plan has a revision number (r1, r2, …).
Plan item One change in the plan, with an ID such as P1. It lists the files it will change and how to check it.
Plan schema The file that defines the structure every plan must have (schema/plan.schema.json). Agents answer in it, and imported plans are checked against it.
Declared files The files a plan item says it will change.
Invocation One run of an AI agent (Claude or Codex) on one task.
Trailer A line at the end of a git commit message, such as Plan-Item: P1.
Hunk Git's name for one block of changed lines in a diff.
Segment Part of a hunk where every line came from the same plan item. codeboost shows segments, not whole hunks.
In scope A change that is in one of its plan item's declared files.
Unplanned change A change that codeboost did not make for any plan item.
Ambiguous change A change that more than one plan item touched, so codeboost cannot say which one owns it.
Approval Your sign-off on one plan item. It records exactly which lines you saw.
Stale approval An approval whose text, file-change metadata, item definition, or dependencies have since changed. You must review that plan item again.
Run window A time when codeboost may run tasks, such as weeknights 22:00–06:00.
Sandbox An operating-system limit on what an agent can read, write, and reach over the network.
Lesson A short rule codeboost learned from your feedback, such as "every retry change needs a test for the 5xx path." It is used only after you approve it.
Container A sealed box (Docker or Podman) that runs one agent. It can see only the folders codeboost puts in it.

The problem

You want to hand GitHub issues to an AI agent without losing control. Today you read an issue, prompt an agent, and get a PR. Then you read a raw diff and try to work out what the agent meant to do.

codeboost keeps your approved plan in control from start to finish. It follows the 9 steps you described:

  1. List the GitHub issues for a repo, most critical first.
  2. Write a plan for an issue, with help from Claude or Codex.
  3. The plan says exactly what changes, file by file.
  4. Approved plans go into a task queue. You can reorder or cancel tasks.
  5. You choose when the queue runs and when it stops. When it stops, the task already running finishes.
  6. The agent carries out the plan, reviews its own work in rounds until nothing is found, then opens a PR.
  7. You review by plan item: pick one on the left, see its code on the right.
  8. You can ask the agent about a plan item, or ask for changes to it.
  9. You approve, and the PR merges. Or you reject, and the task goes back to the queue with your feedback.
  10. codeboost learns from your feedback, so you give the same feedback less often. (Added during the engineering review, L1 to L4.)

Why this is worth building

The plan becomes the index to the diff. Other tools use the plan only before the work starts. After that, you review the diff on its own. In codeboost, the plan items act as the table of contents for the PR.

It targets why agent PRs fail. A 2026 study of 33,596 agent-made PRs, "Where Do AI Coding Agents Fail? An Empirical Study of Failed Agentic Pull Requests in GitHub" (arXiv:2601.15195), found that unmerged PRs tend to change more code and often don't match how the team works. Developers also report two other failures: agents change files the task did not need (scope creep), and agents fix issues that another PR already fixed. We treat all of these as ideas to test, not as proven rankings.

Approvals expire when the code changes. This idea came from the outside reviewer. When you approve plan item P1, codeboost records the exact text and file-change metadata you saw. If a later revision changes that fingerprint, the approval becomes stale. Next time, you see only what changed since you approved. So rejecting and revising stays quick. You never have to re-read everything.

Limits we work within

  • One user, one machine. codeboost uses the claude and codex tools you already have installed and signed in, plus gh for GitHub. It stores no API keys and runs no server on the internet.
  • Agent tools change often. Their options and output formats change. So the code that talks to each agent is small and versioned.
  • Easy to install. It is open source. It must install with one command and no compiler. It also needs Docker or Podman, because agents run in containers (engineering review, R1).
  • Safe by default. It runs without you watching, on text from GitHub issues that anyone may have written. See "Keeping unattended runs safe."

Assumptions we agreed on

  1. The value is in the review, not the queue. Many tools already turn issues into PRs: issue-orchestrator, Agent Orchestrator, Bernstein, NEEDLE, no_human, and GitHub's own Copilot agent. So codeboost keeps its queue simple and puts its effort into steps 7 to 9.
  2. Two separate signals link code to plan items. This assumption was changed after the outside review. Signal 1 is the runner-owned commit ledger (O5); trailers are informational and cannot establish ownership. A commit absent from the ledger is foreign even if its trailer names a plan item. Signal 2 is the plan item's declared files. The review screen shows separate checks for each plan item: attributed, in scope, tests, and AI review (renamed from "correct" by design-review D21). Ambiguous changes are always shown as ambiguous. codeboost never guesses an owner. Neither signal can catch an unrelated edit inside a declared file. Only the review agent and you can catch that (engineering review, R3).
  3. Local and single-user. You start codeboost from the command line. It opens in your browser.
  4. Rejecting revises the same PR. Your feedback attaches to plan items. The plan gets a new revision. The agent redoes only the affected plan items.

What an outside reviewer said

We asked Codex (OpenAI's agent) to read a summary of this session cold. Its main points:

  • The best version: every plan item is a claim you can check, with its code, its tests, and its links to other plan items. Approvals expire when their evidence changes.
  • What excites you most: your step 7, "User reviews by selecting each specific change in the plan on the left." Build that first.
  • An existing tool to learn from: natiixnt/AgentDiff. It is MIT-licensed, written in Python, and compares a plan with a diff. We confirmed it exists. It has 1 star, so it is an early prototype. It lacks plan revisions, reliable links from code to plan items, per-item feedback, and approvals tied to exact code.
  • An assumption it challenged: trailers alone cannot catch scope creep, because a trailer only records what the agent claimed. We agreed and changed assumption 2.

Where we disagreed: the plan format is what makes code-to-item links possible. So we design it on day one, even though the planning screen comes later.

Options we considered

Option Decision Reason
A. Build only the review screen Not chosen as the end goal You would still run agents, the queue, and scheduling by hand. It becomes the first two build steps of option B.
B. Build all 9 steps, starting with the review screen Chosen codeboost must run the agent itself to make the code-to-item links reliable.
C. Build only the plan format and review screen, and let other tools run the agents Not chosen codeboost could not control how other tools commit, so the links would be unreliable. One idea is kept: the plan appears in the PR description on GitHub.

What we will build

We build all 9 steps as one local app. We started with the review screen. Optional human validation may check whether it works, but the cancelled experiment no longer stops the remaining roadmap (see "Delivery milestones and optional validation").

Tools and storage

These are proposals. The engineering review will confirm them.

  • Language: TypeScript. A Node server and a React user interface, shipped as one npm package.
  • Storage: SQLite. It holds tasks, plan revisions, approvals, feedback, the schedule, and a run log. SQLite is the only master copy of each plan.
  • Storage code: All database access goes through one small module. It uses only Node's built-in node:sqlite (engineering review, R7). The minimum Node version is the oldest one that continuous integration proves loads node:sqlite with no warning. Node 26 is confirmed today. On an older Node, codeboost stops at start-up and tells you which version to install. The module is still a thin wrapper, so an API change touches one file.
  • Workspaces: each task gets its own standalone clone (git clone --local --no-hardlinks), whose .git folder sits inside the task folder, so git works inside the agent's container (engineering review, O6). Objects must be independent copies, with no hard links or alternates back to the source. codeboost pushes to GitHub from outside the container. It never touches or mounts your own checkout. Elsewhere in this document, "worktree" means this per-task folder.
  • Agents: one small adapter per agent: claude -p and codex exec. Each takes a prompt, a worktree, and a set of permissions, and reports progress as it runs.
  • GitHub: codeboost uses gh for issues, PRs, and merging. Only codeboost runs gh. Agents never do.

The plan format

Changed by decision P1 (below, in the Decision ledger). The full rules are in docs/plan-format.md.

  • One schema is the contract. schema/plan.schema.json defines every plan, version 1. codeboost passes it to Claude (claude -p --json-schema) or Codex (codex exec --output-schema) when they draft a plan, and checks every imported plan against it.
  • YAML and JSON have the same structure. People read and write YAML; agents return JSON. Every field is always present, with null or [] when it has nothing to say.
  • Each declared file carries its own change. A file entry has a path, a kind (edit, add, delete, or rename), the old path for a rename, and what changes in it. This keeps the plan file by file (step 3).
  • Acceptance entries are typed. cmd is a command codeboost runs. check is a statement the review agent judges.
  • After the schema, codeboost checks meaning. For example: unique IDs, depends_on only to earlier items, no .. in paths, and valid projected file operations: existing sources for edits/deletes/renames, unused destinations for adds/renames. A failure blocks approval; a warning, such as "No test command", does not.

Each plan looks like this (shortened; the full example is schema/examples/plan-412-r3.yaml):

schema_version: 1
issue: 412
revision: 3
summary: Keep the Idempotency-Key header on every retry.
items:
  - id: P1
    title: Preserve idempotency key across retries
    intent: Every retry must send the same key as the first attempt.
    files:                                  # declared files (signal 2), each with its change
      - path: src/retry/client.go
        kind: edit
        renamed_from: null
        change: Read the key once before the loop and set it on every attempt.
    acceptance:
      - type: cmd                           # a command codeboost runs
        text: go test ./src/retry/... -run TestRetryKeepsKey
      - type: check                         # the review agent judges this
        text: The key is set on every attempt, not only the first.
    depends_on: []
questions: []                               # open choices the agent wants you to decide

Where the plan lives. The plan is not committed to the PR branch. Instead, codeboost writes it into the PR description, between two markers: <!-- codeboost:plan:start --> and <!-- codeboost:plan:end -->.

  • codeboost rewrites only the text between the markers, on each new revision. It also adds a PR comment such as "plan r3."
  • codeboost never changes text outside the markers.
  • If someone edits between the markers on GitHub, codeboost replaces that text and saves the old text in the task's log.

This keeps the plan out of the code, and there is only one master copy.

How codeboost runs a plan

codeboost makes every commit.

  • For each plan item, codeboost runs one agent invocation. It tells the agent not to commit.
  • When the invocation ends, codeboost commits the changes itself. It adds two trailers: Plan-Item: P<n> and Plan-Revision: r<k>.
  • If the agent commits anyway, codeboost undoes those commits (keeping the changes) and commits them again with its own trailers.
  • So a trailer is a fact codeboost saw, not a claim the agent made.
  • If a plan item produced no changes, codeboost marks it "planned but unchanged."

Review rounds.

  1. After all plan items run, a separate review agent checks each plan item against its intent and its check: entries. This agent can read but not edit.
  2. codeboost runs every cmd: entry on the final code.
  3. Each problem found is filed against one plan item. If a problem spans several plan items, it is split into one problem per plan item.
  4. codeboost fixes each problem with a new invocation for that plan item. The fix commit carries that plan item's trailer.
  5. Rounds stop when a round finds nothing, or after 3 rounds. After 3 rounds, the task moves to needs human.

When the plan is wrong. A plan item's invocation may edit only its declared files. If it needs another file, it must stop and propose a plan change: the file, the reason, and the new plan item text. Then codeboost:

  1. saves the partial changes with the proposal, for reference only;
  2. resets the worktree to the last codeboost commit, so nothing partial is kept;
  3. moves the task to needs amendment and frees the queue for other tasks;
  4. waits for you to approve or edit the proposal on the planning screen. Your approval creates the next plan revision;
  5. puts the task back in the queue at its old position, and re-runs that plan item from the start.

The runner does not yet save this proposal, and the Plans screen cannot show or edit one (#155). Today a needs-amendment pause comes from an out-of-scope edit (next paragraph), and the next revision comes from an import or an applied agent draft or suggestion.

If an invocation finishes normally and passes the safety audit but edited an undeclared regular file within the task repository, codeboost still commits the change. Unsafe path, metadata, symlink, or submodule violations instead stop the invocation before any test or commit and move it to needs human. The change shows on that plan item's row, marked out of scope. Execution deliberately pauses in needs amendment before any later item or check invocation. A person must approve a revised plan and continuation; the runner reconciles the already-executed prefix with the audited current head, then validates remaining operations from that actual checkpoint. Do not silently add the file to scope or erase its original out-of-scope evidence.

Checking whether the issue is already fixed. Before it opens the PR, and again before merging, codeboost checks:

  • whether something other than this task's PR closed the issue;
  • whether GitHub shows other open or merged PRs that link to the issue;
  • whether new commits on the base branch mention the issue number.

It ignores this task's own PR, any draft PRs it opened earlier, and its own commits. If any check matches, the task moves to possibly already fixed. codeboost does not open a PR. You choose to continue, or to cancel and delete the workspace.

Keeping unattended runs safe

Issue text is untrusted. Anyone may have written it. So codeboost puts issue text inside a clearly marked data block in each prompt, and tells the agent it is data, not instructions. The agent follows only the plan items you approved.

Which issues can be queued.

  • By default, only issues written by repo collaborators.
  • Other issues need you to click "trust this issue." codeboost records that choice.

Which comments reach the agent.

  • By default, only comments from repo collaborators.
  • If you chose "trust this issue," comments from other people are included too, inside the same data block.
  • Every invocation records which comments it was given.

The container (the real safety boundary). Changed by the engineering review, R1 (answer D2: B). Every invocation, of every phase, runs inside a Docker or Podman container. The agent tool itself runs inside it. The container holds only:

  • the task's folder, including its own .git (O6), mounted as /work: writable only for carrying out/fixing, read-only for planning/questions/review; its .git is stored on a separate runner-owned filesystem and exposed only at the read-only /work/.git mount in every agent phase. No writable inode aliases exist; the worktree backing directory contains only an empty mountpoint. Only the runner updates metadata. Startup must reject layouts without this separation; a nested read-only bind on the writable task filesystem is insufficient. This is the only project folder an execution-phase agent can write to;
  • a dedicated read-only /run/codeboost-input mount containing only the registry-selected schema copied by the runner; Codex output is written to a runner-created directory in bounded /tmp scratch and collected before teardown, using container-visible paths and no-follow bounded regular-file reads; Claude output uses bounded stdout instead;
  • the agent's own sign-in. For Codex, that is its auth.json from CODEX_HOME, mounted read-only at /run/codeboost-auth/codex/auth.json, with CODEX_HOME=/run/codeboost-auth/codex explicitly set inside the container. The CODEX_HOME directory itself is a writable size/inode-limited tmpfs for ephemeral CLI state; only its auth.json file is bind-mounted read-only. This location is separate from the empty HOME; the startup probe must run the actual authenticated codex exec path and confirm output/state creation without printing credentials. If the pinned CLI cannot use this credential layout, refuse the invocation rather than making the host credential writable. For Claude, it is a long-lived token made with claude setup-token, passed as an environment variable. (On macOS, Claude keeps its normal sign-in in the keychain, which a container cannot read.)

Ask runs in this container (since 2026-09-26). Ask was briefly an exception to R1: until lane D's container existed, it ran the vendor CLI on your computer with the CLI's own restrictions. That exception is closed. Ask now uses lane D's invocation contract in the "questions" phase:

  • a clone of the reviewed head, mounted read-only at /work; the agent may read, list and search it but cannot run commands;
  • vendor-only network and no other file from your computer;
  • Claude signs in with CLAUDE_CODE_OAUTH_TOKEN (from claude setup-token); Codex uses its auth.json. codeboost does not store either;
  • the setup runs in a worker thread (runner/question-worker.ts) because lane D's Docker and Git calls are synchronous; the review server stays responsive. Storage is released only after the container settles.

There is no host fallback: without Docker or the sign-in, Ask fails with a message that names what is missing.

Nothing else from your computer is inside. So ~/.ssh, ~/.config/gh, ~/.npmrc, ~/.aws, ~/.docker, and your git credential helper simply are not there. The container's HOME is its own empty folder.

How the container is locked down. Docker and Podman leave a container's own files writable by default. So codeboost starts every agent container with these settings, and a start-up self-test fails the run if any is missing:

Setting Why
Read-only root filesystem (--read-only) The agent cannot change the tools in the image, such as git, go, or the agent CLI itself.
Writable scratch only as size-limited in-memory folders (--tmpfs): /tmp, the empty HOME, and the Codex CODEX_HOME state directory when selected (its auth file remains read-only). All are emptied when the container ends. Tools that need scratch space still work, and nothing written there outlives the invocation or reaches the task's code.
Build caches point inside the scratch folders (for example GOCACHE, npm_config_cache). Caches do not need a writable root.
Runs as a non-root user; all Linux capabilities dropped (--cap-drop=ALL); --security-opt=no-new-privileges The agent cannot become root or use privileged system calls.
No --privileged, no --device, no host network, no Docker socket, and no host mounts other than the bounded worktree, separate read-only Git metadata, runner-prepared read-only schema input, and read-only sign-in file Nothing on the host is reachable through the container.
Limits on processes, memory, and CPU (--pids-limit, --memory, --cpus) Bound the agent's consumption of these resources; they do not guarantee zero host performance impact.
No Docker daemon log (--log-driver=none) The supervisor reads the agent's output as it is written (docker start --attach) and bounds it there. The daemon keeps no copy that a fast writer could grow before the supervisor stops the container.
/work lives on a dedicated size-limited task filesystem with hard byte and inode limits, allocated before the invocation; never an unbounded host-directory bind Large output and many tiny files fail inside the task filesystem instead of growing without limit on the host.

Output and time enforcement. A trusted supervisor outside the invocation container incrementally captures every agent/check command with hard limits of 16 MiB stdout, 4 MiB stderr, and 20 MiB combined, including protocol envelopes. Host buffers, persisted logs, and UI forwarding obey the same per-invocation limits; task-log retention has a configured total byte cap and never accumulates unbounded output across retries. Before launch, require a finite wall deadline (default 10 minutes, capped by the remaining task budget; configured overrides must also be finite). On overflow/deadline or capture failure, stop consuming into retained buffers, terminate the entire container including descendants, escalate to forced container kill if graceful termination fails, and record a bounded failure diagnostic. Never wait indefinitely for EOF from an orphan child, silently treat truncated output as success, or run tests/commit after this failure. Container tests must exercise infinite stdout, infinite stderr, mixed streams, and a child ignoring SIGTERM, while measuring bounded host capture and completed termination. For structured vendor output, the transport cap includes envelope headroom; separately enforce the 1 MiB plan-document limit after extraction.

Disk enforcement. The runner requires configured per-task byte/inode caps and a total task-storage pool cap. Allocate/reserve the backing storage before the agent starts, leaving configured host free-space headroom; do not use a grow-on-demand backing file that can exhaust the host. Refuse to start if the platform cannot enforce the caps. Scratch tmpfs mounts have their own size/inode limits. The startup/CI probe must attempt to exceed byte and inode limits and confirm writes fail without consuming storage beyond the allocated pool. Post-run checks alone are not a disk guard.

So the only place an agent can change something that lasts is /work, and codeboost checks every change there against the declared files before it commits (see "Checks after import" and "After each run" in docs/plan-format.md).

Network (engineering review, R2, answer D3: A). The container sits on an internal network. A small proxy lets it reach only the agent vendor's API hosts, and the host list is pinned with each image version. As a second layer, codeboost turns off the agent's own ways to reach the web: for Claude, --disallowedTools WebFetch,WebSearch and --strict-mcp-config with no servers; for Codex, web search is turned off. So a hostile issue cannot make the agent send your code to an outside server.

If Docker or Podman is missing or not running, codeboost runs no agents and tells you what to install. When the container image is built, codeboost pins the claude and codex versions it tested.

Changes that need your approval.

  • Dependencies. Only codeboost installs them, as a separate step with the network on. If a task changed a package manifest or lock file, codeboost first stops and shows you the change. It waits in needs approval.
  • Scripts. If a task changed a script that codeboost is about to run (package.json scripts, a Makefile, CI settings, or test settings), codeboost stops in needs approval before its own invocation. This gate applies to codeboost-run commands after the agent invocation; it does not intercept commands the agent runs during that invocation.

Permissions by phase.

Phase Can edit files Can run commands Network
Planning, questions No No Agent vendor's API only
Carrying out and fixing Worktree only Allowed list only (test, lint, build) Agent vendor's API only
Reviewing No cmd: checks only Agent vendor's API only

Phase enforcement. The runner selects the mount and tool profile before launching the agent. Planning/questions expose read/list/search tools only; the dispatcher denies process execution, shell, write, and edit tools. Review uses the same read-only /work mount and cannot invoke arbitrary processes: it may request only the exact approved cmd: argv through a runner-controlled dispatcher. Those checks use the read-only project mount and writable scratch; a check that requires writing project files fails explicitly rather than weakening the mount. Carrying-out/fixing uses a writable /work and the command allowlist. Every dispatched command must match an approved argv array element-for-element, including all flags and arguments; executable/subcommand prefixes are insufficient. Changed argv requires explicit approval of a new allowlist entry, separately from approving the plan. These are enforced permissions, not prompt requests; if an adapter cannot enforce a phase profile, refuse that phase. Container tests must attempt file writes and forbidden process/tool calls in every phase and confirm refusal.

All phases run in the container (R1). The allowed list comes from your repo's scripts, and you can edit it. It limits accidental commands; it is not a hostile-code boundary. A carrying-out agent can edit an allowed script and execute the changed script in the same invocation, before codeboost gets control back. The container and network restrictions must therefore contain arbitrary code from the start. Script approval protects codeboost's later invocation only; it does not prevent that earlier agent execution. The real-container suite must exercise this edit-then-execute case and confirm that host access and disallowed network access remain blocked.

Credentials. Build the agent environment from an explicit allowlist, not by inheriting the host environment and guessing secret names. Remove GH_TOKEN, GITHUB_TOKEN, and unrelated credentials. Add only the selected CLI's required sign-in: the configured Codex auth mount and CODEX_HOME, or Claude's configured long-lived token variable. Preserve that selected credential through environment filtering; never add both vendors' credentials. Test authentication for each profile and absence of unrelated secret sentinels. Only codeboost itself is signed in to GitHub.

Known limits. The README states these plainly:

  • The agent tool can always reach its own sign-in (your Claude or Codex account), because it is mounted into the container.
  • The container's guarantees are those of Docker or Podman.
  • Installing dependencies runs their install scripts with the network on. That is why it needs your approval.

How codeboost links code to plan items

It follows each commit, not only the final code. For every commit in the task, codeboost records which lines it added and removed, and which plan item the commit belongs to. Then it traces each line of the final diff back to the commit that last changed it.

  • An added line belongs to the commit that added it.
  • A removed line belongs to the commit that removed it. So even changes that only delete code have an owner.
  • A line changed by commits from two or more plan items is marked multi-item.

It trusts its own commit ledger, not commit messages (engineering review, O5). runner/store keeps a ledger of every commit codeboost creates, with SHA, nullable plan-item owner, and origin classification. Rewriting a foreign commit records a new entry with owner null and origin foreign; creating the rewritten commit does not assign it to a plan item. When codeboost rebases, it also records which old commit became which new one. Only ledger entries with an explicit non-null plan-item owner count as that item's work; entries marked unowned/foreign remain Unplanned. A commit that is not in the ledger is foreign, even if its message carries a Plan-Item trailer, so its lines go to the Unplanned row. Trailers stay in history as a readable label, not as proof.

It shows segments, not whole hunks. codeboost splits each hunk wherever the owner changes. For example, a hunk with some lines from P1 and some from P2 becomes two segments: one on P1's row, one on P2's row. Both carry a "shares a hunk with P1/P2" label.

Changes with no text lines (engineering review, O7). V1 can review externally produced gitlink changes, but cannot author submodule-pointer changes; a future typed target-commit operation is required before enabling that execution path. Some changes have no lines: binary content, file mode (such as the executable bit), empty files added or deleted, renames without content change, symlinks, and submodule pointers. Each one becomes a file-change segment. It is owned through the commit ledger and placed by the same table below. Its approval records the old and new path, the old and new mode, and the old and new typed object IDs: {kind: blob, oid} for regular files/symlinks, {kind: commit, oid} for mode-160000 gitlinks, and null for an absent side. On the review screen it shows as a card, for example "binary changed (12 KB → 14 KB)", "made executable", or "renamed from x". The merge gate treats it like any other segment.

Where each segment goes. First find who made the segment (rows). Then find whose declared files it is in (columns).

Who made it In no plan item's files In only this plan item's files In other plan items' files only In several plan items' files, including this one
One plan item (Px) Px row, out of scope Px row, in scope Px row, out of scope, naming the owner Px row, in scope, labeled "shared file"
Several plan items Ambiguous row Ambiguous row Ambiguous row Ambiguous row
Not codeboost (for example, someone pushed to the branch) Unplanned row Unplanned row Unplanned row Unplanned row

So the red "Unplanned changes" row holds only changes codeboost did not make. When an agent works outside its declared files, the change stays on that plan item's row, marked out of scope. That way you can see which plan item did it.

The checks on each plan item ("Correct" was renamed to Tests and AI review by D21).

Check Green Warning Grey
Attributed None of this plan item's lines are in the Ambiguous row. Amber: some are. The chip links to them. No changes
In scope Every segment is in a declared file. Red: some are not. The chip lists the files. No changes
Tests Every cmd: check passes on the latest code. Red: one fails. "n/a": no cmd: checks
AI review No open problems. Shows the number of open problems. —

A plan item with no changes can be approved only if you confirm "no change needed." codeboost records that.

What an approval records. When you approve a plan item, codeboost saves its changes: for each file, the added and removed lines in order. It leaves out line numbers and surrounding lines. The only thing it adjusts is line endings (Windows to Unix). Spaces and tabs count. For every non-line file-change segment it also stores the operation kind, old/new paths, old/new modes, and old/new typed object IDs (blob/commit or null), as defined above. This metadata is part of the approval fingerprint, not an empty text snapshot. Segment addition/removal and changes to any metadata field invalidate the owning approval and any standalone acceptance of that segment, propagating to dependents. Immediately before merge, recompute and compare both text and metadata fingerprints against the current base/head pair. So:

  • a whitespace-only change to approved code makes the approval stale. This matters in Python, YAML, Makefiles, and text strings;
  • code that only moved up or down, because of other plan items or a rebase, keeps its approval.

An approval also covers the job, the place, and the dependencies (engineering review, O2). Besides the lines, an approval records:

  • a fingerprint bound to the stable repository/task/plan IDs and plan-item id, including its title, intent, changes, declared files, acceptance checks, and depends_on list. If any of these changes, the approval becomes stale; an ID-only import is a different ownership key and cannot inherit the old approval, even when all text matches;
  • for each segment, the name of the function it sits in, taken from git's hunk header (not a line number). If the same lines move into a different function, the approval becomes stale. Line shifts and clean rebases still keep it;
  • its dependencies. If a plan item becomes stale, every plan item that lists it in depends_on becomes stale too.

Changes since you approved. For a stale plan item, the review screen opens on "Changed since approval." It shows the difference between what you approved and what is there now.

Assigning ambiguous or unplanned changes. You can assign a segment in the Ambiguous or Unplanned row to a plan item, or accept it as it is.

  • codeboost remembers your choice by file, exact content, and which copy it is among identical segments in that file (1st, 2nd, and so on, in file order). The choice survives new revisions, re-runs, and rebases, as long as all three stay the same. If the content changes, the copy number changes, or the number of identical copies in that file changes, the choice lapses and you decide again (engineering review, R4 and O1).
  • Assigning a segment adds it to that plan item. So that plan item's approval always becomes stale, and you approve it again with the segment included.
  • Accepting a segment as it is creates a separate approval, which goes stale by the same rule.

The review screen

You chose mockup B: ~/.gstack/projects/codeboost/designs/mockup-20260922/variant-B.png.

  • Left: the plan items. Each shows its declared files, its number of changes, and its status checks. Below them are the Ambiguous row and the red Unplanned row.
  • Right: the code for the selected plan item. Keyboard keys move through changes ("Change 1 of 5", D24). A label shows when the approval is stale. A switch shows "Changed since approval."
  • Bottom: a conversation about the selected plan item only.
  • Top: the "Reject with feedback" and "Approve & merge" buttons, and a list of anything that blocks merging.

Screen specifications (design review, 2026-09-22)

Added by the design review. Each rule cites the design-review decision (Dn) that approved it. In this section and in the "Design review" section, Dn means a design-review question. The engineering review's Decision ledger uses its own D numbers. Where a rule here differs from a mockup, the rule wins. The mockups show the look, not the behavior.

Review screen: approving one plan item (D12).

  • The header of the selected item's code pane has an "Approve P1" button (key a).
  • An item with no changes shows "Confirm no change needed" instead.
  • The page header shows progress, such as "3 of 5 approved".
  • The circle on each row of the plan-item list shows state only: not reviewed, approved, or stale. It is not a button.
  • When every item is approved, the main button reads "Merge PR".

One menu on every screen (D13).

  • Every screen uses the same left menu: Issues, Plans, Queue, Review, Lessons, Learning, Settings. The current page is highlighted, and the repo name is shown at the top.
  • Inside Lessons, the states are tabs: Inbox, Active, Turned off, Discarded.
  • Items the mockups show but the plan does not have (Drafts, Templates, Rules, Experiments, PRs, Metrics) are removed.

Review screen: plan-item list (D14).

  • Each row shows: item ID, title, approval state, change count, and the four status icons.
  • Declared files appear only for the selected item.
  • A strip above the list always stays visible, for example "2 unplanned · 1 ambiguous changes". Each part links to its row.

What you see in each state (D15).

Screen Loading Empty Error Success Partial
Review screen The list and code pane show grey row outlines; the header says "Linking changes to plan items…" Only if a plan has no changes at all: "No code changes yet. The agent made no commits for this plan." with Open task Linking failed: "Could not read this branch's history." with the git error, Retry and Open task Header shows "5 of 5 approved" and Merge PR Some items approved and some not: the header shows the count, and stale items are marked
Lessons inbox Grey row outlines "No lessons waiting. New lessons appear here after a task closes." with View active lessons "Could not load lessons." with Retry After approving: the row leaves the inbox with "Approved: now used in future tasks" and Undo for 10 seconds Filters hide some rows: "Showing 12 of 31 · Clear filters"
Learning screen Grey outlines on tiles, chart, and table "Not enough tasks yet. Numbers appear after 5 closed tasks." "Could not load learning data." with Retry Tiles, chart, and table filled Fewer than 5 closed tasks: tiles say "Not enough tasks yet" (D18)

Task states that wait on you. Each shows a full-width banner above the plan-item list, with a headline and one main action:

Task state Headline Main action Other actions
Needs human "Review rounds stopped after 3. 2 problems are still open." Review anyway Add guidance · Cancel task
Needs amendment "P3 needs a file the plan did not declare: src/config.ts." Review plan change Cancel task
Needs approval "This task changed package.json. Approve the dependency change before tests run." Review dependency change Cancel task
Possibly already fixed "Possibly already fixed by #401." Continue Cancel task
Approved, merge blocked "GitHub refused the merge:" plus GitHub's exact message Retry merge Open on GitHub

While merging (D16).

  • The header turns into a step list: Fetch → Rebase → Push → Re-run checks → GitHub checks → Already-fixed check → Merge. Each step shows its status and elapsed time. A Cancel button is always shown. Amended 2026-10-21 (user decisions, PR #194): the step list is a bar under the review strip, and the header keeps the merge control and its blockers; Cancel merge shows only while the merge job runs, since an ended job has nothing to cancel.
  • You can leave the screen. The steps keep running, and the task row in the Queue shows the current step.
  • Each failure ends in a named banner that jumps to the first affected item, for example:
    • "Rebase changed P2 and P4. Review them again."
    • "Checks failed on the rebased code: pnpm test in P3."
    • "Someone pushed to this PR after your review. Review the new changes."

Stale items (D17).

  • Each stale item states its reason in words: "Code changed", "Acceptance checks changed", "Moved to another function", or "Depends on P2, which changed". It shows the before and after for that reason.
  • A labeled switch toggles between "Since approval" and "Full change". Stale items open on "Since approval".
  • Stale items carry a badge in the plan-item list.

Learning screen: honest numbers (D18).

  • Each tile has an info tip that says how it is counted, for example "rejections ÷ closed tasks in this period", and which direction is better.
  • Change arrows are hidden until both periods have at least 5 closed tasks. Until then, the tile says "Not enough tasks yet".
  • The chart's horizontal axis is task number, not week. Each line is labeled directly at its end.
  • A lesson is flagged after 3 repeats of matching feedback since you approved it. The table's column heading says so.

Asking vs requesting a change (D19).

  • The composer has two tabs: "Ask" (answered right away, changes nothing) and "Request change" (saved for the next revision).
  • Saved requests show on the item, for example "2 pending changes".
  • The reject button names the count, for example "Send 3 change requests", and opens a short summary before sending.
  • You cannot merge while change requests are pending.

Merge blockers (D20).

  • While blockers remain, the main button is disabled and reads "3 blockers". Clicking it opens a list in which each line jumps to its fix:
    • "Review 2 stale items"
    • "Resolve 3 unplanned changes"
    • "Open failed check"
    • "Send 2 pending change requests"
  • There is no "Merge anyway…" (D20 amended 2026-09-24). codeboost never merges while a blocker remains. To override a blocker, merge on GitHub yourself; GitHub's own rules then apply. This keeps one rule for every blocker, including the server-side base protection that no override may bypass (step 9, point 5).
  • In build step 2 (read-only), there is no merge button. The header shows review progress only.

Status labels (D21). "Correct" is replaced by two labeled states:

  • Tests: "3/3 passed", "Not run", "Out of date", or "No tests defined". "No tests defined" looks different from "passed".
  • AI review: "No open findings" or "2 open".

Your approval (D12) stays a separate control. No label claims the change is "correct".

Scope labels everywhere follow L3. The approved Learning mockup shows "Global", "Backend", and "Frontend". Build them as "This repo" and "All my repos" (L3, D23 in the engineering review). No new decision was made here.

Design system (D22). Run /design-consultation before build step 2 to create DESIGN.md. It must define:

  • the UI and code fonts;
  • CSS color variables: surfaces, text, one blue accent, and the status meanings (green = ok, amber = attribution warning, red = scope or test failure or blocker, grey = not applicable);
  • the spacing scale, row height, and focus ring.

Every screen uses those tokens. Until DESIGN.md exists, build step 2 does not start. Done 2026-09-22: DESIGN.md ("Evidence Desk") was created by /design-consultation. It also adds the provenance gutter to every diff.

Status never relies on color alone (D23).

  • Every status uses a distinct icon (✓ ok, ! warning, ✕ failure, – not applicable), a short word, and its color.
  • Text and icons meet 4.5:1 contrast on the dark background.
  • Each check has a screen-reader label, for example "In scope: fail, 1 file outside declared files".

One keyboard map (D24).

Screen Keys
Review j/k next and previous change · n/p next and previous plan item · a approve item · r request change · ? show all keys
Lessons j/k move · Enter expand · a approve · e edit · d discard · x select · / search
  • The count reads "Change 2 of 7", not "Hunk", and file-change cards are counted too.
  • Shortcuts are off while a text box has focus. Esc leaves the text box.
  • Every control can be reached with Tab and shows a visible focus ring.

Window sizes (D25). codeboost is a desktop tool, supported from 1280px wide.

Width Layout
1440px and wider All three panes show: plan-item list, code, and conversation
1280–1439px The conversation pane collapses into a tab, and the plan-item list narrows
Below 1280px A notice asks for a wider window

Panes can be resized, and each one can be collapsed. Phones and tablets are not supported.

Assigning and accepting changes (D26).

  • The Ambiguous row always shows. When it is empty, it is collapsed and shows "0".
  • Each Ambiguous or Unplanned change has two controls: "Assign to…" (a list of plan items) and "Accept as is".
  • Before assigning, an inline note warns you, for example: "Assigning to P2 makes P2's approval stale."
  • Changes an agent resolved during a rebase carry the tag "conflict resolved by agent".

File-change cards (D27). One card design sits inside the code pane. Cards appear in change order and count toward "Change n of m". Each card shows:

  • an icon for the kind of change;
  • old → new path, old → new mode, and old → new size;
  • an image preview where possible. Otherwise it says "No preview available";
  • the content IDs, inside an expandable "Details".

A rename that also changes content shows the card, with the text change below it.

Lessons inbox: bulk actions (D28).

  • Bulk Discard only. There is no bulk approve: each lesson is approved one at a time, matching L2. The approved mockup's "Approve 2" button is not built.
  • Selection counts only visible rows, for example "12 selected on this page". "Select all 31 matching" is a separate, explicit link.
  • Selection clears when the filters or sort change. Checking a box never expands a row.

Asking questions and requesting changes (step 8)

Questions. You get an answer right away, at any time, even outside run windows. The agent can read but not edit. It sees the plan item, its current code, its open problems, and the conversation so far. A question never creates a new revision.

Change requests. Nothing happens until you click "Reject with feedback." Then codeboost:

  1. collects all your change requests into the next plan revision;
  2. marks the affected plan items to run again;
  3. puts the task back in the queue. It runs only during run windows;
  4. re-runs only those plan items. Each fix commit carries its plan item's trailer;
  5. runs the review rounds again.

Approvals on other plan items stay valid, as long as their code did not change.

Approving and merging (step 9)

When you can merge. "Approve & merge" works only when all of these are true:

  • every plan item is approved, and no approval is stale;
  • the Ambiguous and Unplanned rows are empty, or you assigned or accepted every segment in them;
  • every plan item's cmd: checks pass on the latest code, or it has none;
  • no plan item has open problems, or you marked each open problem "accepted";
  • GitHub's required checks pass on the latest code;
  • the "already fixed" check finds nothing.

The top of the screen lists anything that is not yet true. codeboost has no "Merge anyway" (D20, amended 2026-09-24): to merge with a blocker, use GitHub directly.

What happens when you click "Approve & merge".

  1. codeboost fetches the latest base branch and PR head, recording both SHAs.
  2. Compare both SHAs with the base/head used for attribution, approvals, and validation. If the head changed even when the base did not, reload the history and ledger, recompute links and approval staleness, and return changed or unplanned items to review. Re-run all cmd: checks for any head without current passing results. Continue only after the current head satisfies review and validation; do not skip the rule refresh in step 4 even when both SHAs match.
  3. If the base has moved, codeboost rebases the PR branch (see below) and pushes it. After every rebase, recompute attribution, segment choices, approval staleness, and all merge blockers for the resulting head. If any item is stale or any foreign/ambiguous segment is new, changed, or still unaccepted/unassigned, stop and return to review even when no owned item's code changed. Only after those blockers are cleared, re-run every plan item's cmd: checks on the rebased code, in the container. If the base did not move, keep the current head and the validation requirements from step 2. If any check fails, merging stops and you go back to review (engineering review, O3). Test results are tied to the commit they ran on. Results for any other commit are shown as out of date.
  4. codeboost waits for GitHub's required checks on the new code. It reads which checks are required from the branch's rules at that moment (the union of all applicable active rulesets and classic branch protection, preserving check context and required app identity). Only a successfully read, explicitly empty union passes at once; an unreadable or ambiguous source blocks merging as unknown. Code reviews, such as Copilot code review, are not checks and do not count. The screen shows the checks' progress. If they take longer than 30 minutes, the task moves to approved, merge blocked (engineering review, R6).
  5. Immediately before merging, re-fetch both head and base; if either differs from the validated pair, restart attribution/rebase/checks instead of merging. Run the "already fixed" check again. The merge backend must also enforce the validated base/head pair atomically on the server (or validate the final merge candidate in a protected server-side merge queue). A final client-side fetch alone cannot close the race. If the repository/backend cannot provide that guarantee, automatic merging is blocked and the person must use GitHub's manual workflow; codeboost has no override for this guard. Zero required checks still passes step 4, but does not waive this merge requirement. For a backend that provides the base guard, also pin the head with gh pr merge --match-head-commit <sha>. The sha is the commit whose approvals, cmd: results, and required checks all passed. If anyone pushed after that, GitHub refuses the merge. codeboost then reloads the PR, recomputes the links, and sends you back to review, with the changed plan items stale (engineering review, O4).

codeboost also rebases before it first shows you the review. So you always review code that sits on the latest base.

How rebasing works. A clean rebase keeps approvals only if the recomputed text, file-change metadata, item definitions, and context still match; ignoring line numbers alone is not enough. If there is a conflict:

  1. Git stops on one commit. Before assigning any plan item or launching an invocation, look up its ledger entry. A missing entry or an explicit null owner takes the foreign/unowned branch below; do not infer an owner from trailers. Only an entry with a non-null owner enters the following owned-commit steps, with that owner as Px.
  2. For an owned commit, codeboost runs a sandboxed invocation to fix the conflict. The agent sees Px's plan item, the conflicting files, and the base commits that caused the conflict. It may edit only the conflicting files.
  3. The fixed commit keeps Px's trailers.
  4. If the fix needs another file, or the invocation fails, codeboost cancels the rebase (git rebase --abort). That puts the branch back as it was. The task moves to needs human.
  5. Any plan item whose code changed in the fix gets a stale approval.

The foreign/unowned conflict branch (engineering review, R5, answer D6: B). Step 1 above routes both missing-ledger commits (such as a person's push) and explicitly unowned ledger entries here, regardless of their trailers. Do not run the Px-specific steps for this branch:

  1. codeboost runs a conflict-resolution invocation in the same container, with the same network rule. The agent sees the conflicting files, that commit, and the base commits that caused the conflict. It may edit only the conflicting files.
  2. The resolved commit keeps its original author and gets no Plan-Item trailer. The runner records it as an explicitly unowned ledger entry (owner null, origin foreign, plus its source SHA) and maps the old SHA to the new SHA while preserving that classification. Its lines therefore stay in the red Unplanned row, marked "conflict resolved by agent," regardless of whether any trailer is present.
  3. If the fix needs another file, or the invocation fails, codeboost cancels the rebase and moves the task to needs human, as for any other conflict.

If codeboost is stopped or crashes during a rebase, it always cancels the rebase first when it recovers.

Merge method. By default, codeboost uses a merge commit. This keeps every plan item's commits and trailers in the repo history. You can choose squash for a repo instead. Then the squash message lists each plan item and its trailers, but the line-by-line links live only in codeboost's database.

When GitHub refuses the merge. For example, a rule may require a second reviewer, a check may be blocked, or there may be a conflict. Then codeboost shows GitHub's exact error, and the task moves to approved, merge blocked.

Checking branch rules. At repository setup and again before merging, read both all applicable active rulesets (including inherited organization rules) and classic branch protection, following pagination. Combine required checks from both sources; one never replaces the other. Preserve each required check's context and app identity, and require every applicable condition. Permission errors, incomplete responses, and ambiguous not-found responses mean "unknown" and block merging; only a confirmed absence of protection counts as an empty source. Do not learn unknown rules by attempting a merge. codeboost 1.0 does not support rules that require a second human reviewer, and it warns you about them when you add the repo. Acceptance cases include rulesets with no checks plus a classic required check, checks required by both, and either source unreadable.

The queue, stopping, and recovery (steps 4 and 5)

Run windows. You can start and stop the queue by hand. You can also set weekly times, such as weeknights 22:00–06:00. codeboost 1.0 runs one task at a time.

Stopping (your step 5). When you click stop, or a run window ends, the running task finishes. It keeps going until it opens its PR or reaches a state that needs you (needs human, needs amendment, needs approval, or possibly already fixed). No new task starts. A task that is waiting for you never blocks the queue.

Time and round limits. Each task has limits so that "finishing" cannot run forever. The defaults are 2 hours and 3 review rounds, and you can change them. When a task hits a limit, it moves to needs human.

Stopping right now. "Hard stop" ends the agent at once. The runner cancels any rebase and preserves partial output separately for diagnosis, then discards the execution filesystem. Before continuation it materializes a fresh filesystem from the trusted recorded head and validates actual occupancy/types; a reset or reuse of the interrupted checkout is insufficient. Later, the task continues from the next unfinished plan item under the normal queue/run-window rules.

After a crash, sleep, or restart. When codeboost starts, recover the ledger/checkpoint and cancel any interrupted rebase through the runner. Preserve partial output only for diagnosis; never reuse or merely reset the previous execution filesystem. Rebuild from the trusted recorded head, recheck actual entry types/occupancy and phase protection, then put eligible unfinished work first in the queue. No invocation starts until these checks pass and the queue/run window permits it.

Needs human. codeboost opens a draft PR with the plan in its description. The review screen shows the open problems on their plan items. You can:

  • review it anyway, treating the problems as known;
  • add guidance and send it back to the queue. Your guidance becomes feedback for the next revision;
  • cancel. codeboost closes the draft PR and deletes the worktree.

Learning from your feedback (step 10)

Added by the engineering review (L1 to L4). The agent tools cannot be retrained, so codeboost learns by adding approved lessons to its prompts.

How a lesson is made (L1).

  1. A task closes: it is merged, or you cancel it. "Reject with feedback" does not close a task: it creates the next plan revision and puts the task back in the queue (step 8). Each reject round's feedback stays with the task and is included when the task finally closes.
  2. An agent reads your feedback on that task: rejection notes, change requests, and your accept, assign, and "accepted finding" choices. It never reads issue text or comments from other people.
  3. It writes short lessons, such as "In this repo, every retry change needs a test for the 5xx path." Each lesson links to the feedback it came from.

You approve each lesson first (L2). New lessons wait in a Lessons inbox. You approve, edit, or discard each one. Nothing unapproved ever reaches a prompt. You can edit, turn off, or delete any lesson later. Each task records which lessons its invocations used.

Where a lesson applies (L3). By default, only in the repo it came from. When you approve it, or later, you can mark it "all my repos."

Where lessons are used. In planning, execution, and review prompts, inside a clearly labeled "Lessons from your past reviews" section. They are stored in runner/store.

Is it working? (L4). For each repo, a Learning screen shows over time:

  • rejections per task;
  • review rounds per task;
  • repeated feedback, meaning new feedback that matches a lesson you already approved.

A lesson whose feedback keeps repeating is flagged for rewording or removal.

Delivery milestones and optional validation

Superseding product decision (2026-09-23). The paired human go/no-go experiment was cancelled before timed results were recorded. It did not pass and provides no comparative review evidence. The cancellation removes it as a prerequisite for later roadmap steps. Optional future validation is tracked in #19 and must use fresh blinded packages and a freshly committed protocol. Historical experiment decisions and review records below remain as design history.

The numbers below identify delivery milestones, not a requirement to implement them serially. Use the parallel lanes below to schedule work; milestone completion still requires all of its acceptance criteria. Development can proceed in separate worktrees while the product continues to run one task at a time.

  1. Plan format and linking engine. A code library, tested with sample git histories. Done.
  2. Read-only review screen. It works on any branch whose commits are in the commit ledger, with a plan loaded into the database. It shows rows, segments, the four checks, approvals, and the per-item conversation. It does not merge (engineering review, O8). Done; the screen has since gained the merge gate from build step 4.
  3. Optional validation. A future real-PR comparison may test the assumptions in "How we will know it works," but it is non-blocking under the superseding decision above.
  4. Merge gate and merging (product workflow step 9): the merge rules, the pre-merge sequence, and merging through gh. Increment 1 (PR #23), merge-queue support (#38, #46, closing #24) and the pre-merge automation (lane F, F3–F6, #22) have merged. Done: the last items are closed: #176 (PR #195), #174 (PR #197), and the merge job's step list and Cancel button (PR #194). The rest of D16 and DT7 (named failure banners, the Queue-row step, the blocker list with links) is tracked in #199. See the scope and completion criteria below.
  5. Running agents. Per-task clones, containers, agent adapters, permissions, one invocation per plan item, review rounds, the "already fixed" check, and opening PRs (step 6). Isolation boundary merged (lane D, PRs #31, #40, #44, #47, #50), and the runner merged (lane F; see the lane table in docs/architecture.md). Not built: review rounds and screen buttons for the runner actions.
  6. Planning screen. Writing plans with an agent, and approving plan changes (steps 2 and 3). Done for T18: planning backend (lane E, E1–E4) and the Plans screen (lane G, G1–G4, #145; PRs #148, #150, #151, #152). Not built: paste import, in-screen editing, the amendment-proposal view, check warnings, answering questions and a whole-plan approval step (#155). The suggestion cards do not yet conform to the v1 contract (#159).
  7. Queue, schedule, and recovery (steps 4 and 5).
  8. Issue list, sorted by how critical each issue is (step 1). Done: ranking backend (H1–H3), the Issues screen (H4a, #55), and the author-bound "trust this issue" action and runner guard (H4b, #108, PR #139) have merged.
  9. Learning from your feedback (step 10): lessons, the Lessons inbox, and the Learning screen. It needs the reject loop from steps 4 to 7.

Build step 4: scope and progress

Numbering. Build steps above identify delivery milestones; the parallel lanes define execution order. Product workflow steps describe the user journey. Implementation task IDs (T1–T18) below identify individual engineering requirements, not delivery order. In particular, build step 4 is merge gate and merging; T4 is approval fingerprints and dependent staleness. Say “build step 4” (or “build step 4, increment 1” for PR #23), not “Task 4.”

Increment 1 — guarded merge gate (merged 2026-09-24 in PR #23, #21; see docs/implementation/guarded-merge.md). Add blockers derived from the current review snapshot, trusted GitHub base/head and required-check reads, branch-rule refresh, server-enforced base protection, a head-pinned merge command, and the review UI action. Cover stale or missing approvals, unresolved changes, open change requests, missing or stale acceptance evidence, GitHub refusals, and stale/double submission. Zero required checks does not waive atomic base protection. This increment implements parts of T6, T7, and T12; it does not complete the full build step.

Increment 1 alone did not rebase or run acceptance commands: a moved base or a missing command result blocked merging and returned to review. It never bypassed unavailable evidence. With a runner, the pre-merge automation below replaces that refusal with a rebase and a command run. Without a runner, a moved base or a missing command result still blocks merging.

Work for build step 4 (pre-merge automation, #22, closed by PR #178):

  • Deliver and validate increment 1 against its final head, including unit/integration and browser regressions, typecheck, and the required review loop.
  • Add the automated pre-merge rebase path and preserve ledger mappings and attribution. Resolve foreign-commit conflicts under the approved agent policy (T3, T11); return conflicts requiring human action to review. Done in F3–F5 (PRs #136, #138, #140, #144, #149).
  • Integrate runner-controlled, containerized execution of approved cmd: argv and bind results to the resulting head (T6; depends on the agent isolation and phase enforcement work in build step 5, including T1, T2, and T9). Done in F5 (PR #149).
  • Validate the complete pre-merge sequence, including the already-fixed check, approval freshness, refreshed required checks, guarded merge, and races involving either base or head changes (T6, T7, T12). Built in F6a–F6c (PRs #153, #161, #177), and T7 is verified. T6 and T12 are verified (PR #183). The merge job's step list and Cancel button are built (PR #194). The rest of D16 and DT7 (named failure banners, the Queue-row step, the blocker list with links) is tracked in #199. #176 was closed by PR #195 and #174 by PR #197.

Sequencing decision. The guarded gate can land before the agent runner. Build step 5 supplied the execution prerequisites, and the pre-merge automation shipped only after they were integrated (F3–F6, #22). Build step 4 stayed open until those items were done: #174, #176, and the step list and Cancel button. All three are now merged. The safe refusal in increment 1 was an intentional interim behavior, not evidence that the automation had shipped. Optional human validation in #19 remains non-blocking.

Open questions

  • How to rank issues (step 1). Decided 2026-09-24 (lane H1). A fixed additive score from priority labels, security, bug, reactions, comments and age, with a reason for each signal. AI triage is left out, so the same issues always sort the same way. Trust comes from the repository's collaborator list and never changes the score. Rules: docs/implementation/issue-prioritization.md.
  • Running several tasks at once. Version 1.0 runs one task at a time. Running several needs a way to spot two tasks that plan to change the same files. This is postponed.
  • A different agent for each phase. For example, Codex could review Claude's work. The adapters allow this. The settings screen is postponed.
  • Reusing AgentDiff. Decided 2026-09-22. Its plan checker and diff parser were read before build step 1. They do not give the ledger-backed line history codeboost needs, so no code was copied (docs/implementation/build-step-1.md).
  • A stronger network sandbox. A later version might run agents in a container that can reach only package registries.

How we will know it works

Test cases for build step 1. The tests must cover all of these:

  • two plan items;
  • an agent editing a file its plan item did not declare. Expected: shown on that plan item's row as out of scope;
  • a change pushed without a trailer. Expected: shown in the Unplanned row;
  • a change that only deletes lines. Expected: owned by the plan item that deleted them;
  • one line changed by two plan items. Expected: shown in the Ambiguous row, with both plan items' "Attributed" checks amber;
  • one hunk with lines from two plan items. Expected: split into two segments, each labeled as sharing a hunk;
  • a new revision that changes one approved plan item. Expected: only that approval goes stale;
  • a rebase that only moves lines. Expected: no approval goes stale;
  • an import that changes only a plan-item ID. Expected: the old approval cannot transfer; the new item requires review and merge blocks until ownership and approvals are reconciled;
  • a whitespace-only change to approved code. Expected: that approval goes stale;
  • approve each non-line segment type, then independently change its content/object ID, path, mode, operation, or presence without adding text lines. Expected: approval and dependent approvals become stale and merge blocks; an unchanged fingerprint survives line shifts;
  • assigning an Unplanned segment to a plan item. Expected: that plan item goes stale, and the assignment survives an unrelated revision;
  • the "already fixed" check run against the task's own PR. Expected: no match.

Historical cancelled real-PR test. The following procedure is retained as design history. It was not completed, produced no result, and is not a roadmap prerequisite; #19 tracks any fresh optional validation.

  1. Write the rules down first (engineering review, O9). Commit this test's pairs, pass rule, and stopping rule to the repo before the first review. Do not change them afterwards.

  2. Pick at least 4 pairs of similar small issues in a repo you own.

  3. Make every PR by hand, using the method in "The assignment" below. (Build step 5, running agents, does not exist yet.)

  4. Before you review, run a small script, scripts/plant.ts (changed by the engineering review, R3). For each PR it plants two unrelated changes:

    • one in a file that no plan item declared;
    • one in a file that a plan item did declare.

    The script adds each plant to a randomly chosen plan item's commit, keeps that commit's Plan-Item trailer, and records the amended commit in codeboost's commit ledger (O5). That is how an agent's stray edit would look. It saves the places in a sealed file. Open that file only after you decide on each PR.

  5. In each pair, review one PR as a raw diff on GitHub and the other in codeboost. Alternate which PR of the pair gets which method from one pair to the next, so harder PRs do not all land on one side. Time each review, from opening to deciding.

  6. Count the changes you could not explain from the plan or the diff.

  7. Count two catch rates for each method: plants in undeclared files, and plants in declared files.

The check passes if all of these hold:

  • codeboost catches at least 3 of the 4 undeclared-file plants it sees, and more than the raw-diff review catches;
  • the median codeboost review time is no slower than the median raw-diff time;
  • no change is left unexplained.

Report the declared-file catch rate for both methods, with no pass bar. It shows how much the blind spot matters.

Stopping rule. Stop after 4 pairs. If the result is within one catch of the bar, run 4 more pairs once, then decide. Do not add more after that.

Unattended runs. Queue 3 issues, set a run window, and walk away. When you come back, each task has either a PR ready for review or a clear state (needs human, needs amendment, or possibly already fixed). This holds even if the laptop slept during the run.

Rejecting. Reject with feedback on one plan item. The next revision targets that plan item. Recompute approval fingerprints after its changes: its approval and all transitive dependents become stale as required by the dependency rule. Only unaffected, non-dependent items whose definitions, content, and context remain unchanged keep their approvals. The UI must show those propagated stale states before another merge attempt.

How people will install it

  • One command (planned). Run npx codeboost inside a repo. It starts the local server and opens the app in your browser. The package is not published yet; today you run npm start -- --config … or npm run demo from a checkout.
  • Requirements. Node 26.7.0 or later: CI proves this version runs node:sqlite with no warning, and codeboost refuses older versions with an upgrade message. Planned, not yet implemented: codeboost will check for git, a signed-in gh, a running Docker or Podman, and at least one of claude or codex with its sign-in (a claude setup-token token, or Codex's auth.json), and tell you what is missing. Today the CLI (web/cli.ts) checks only the Node version before it starts; a missing tool shows up later as an error from the feature that needs it.
  • No compiler needed. It has no native modules. It uses Node's built-in node:sqlite.
  • Releases. GitHub Actions runs all tests on every PR. When we tag a version, it publishes to npm and creates a GitHub release.
  • Later, maybe: a Homebrew formula.

What to do next

  1. Done: create the repository, README, plan/linking foundation, persistent store, and read-only review screen. Also done: the guarded merge gate (PR #23), planning audit and authoring contract (E1, E2), suggestion orchestration (E3), issue ranking backend (H1–H3), merge-queue support (K1–K3), the agent isolation boundary (D1–D5), the runner (lane F, F1–F6 except review rounds, including the pre-merge automation in #22), the Issues screen (H4a), planning acceptance (E4) and the Plans screen (G1–G4, #145; #155 lists unbuilt parts and #159 tracks suggestion-card non-conformance).
  2. Finish the open lane work listed in the lane table in docs/architecture.md, then continue the roadmap from the current open issues; the cancelled experiment is not a prerequisite.
  3. Optionally run the non-blocking human validation tracked in #19.
  4. The engineering review (2026-09-22) settled how agents run, their container, network, and permissions. Re-run /plan-eng-review before implementing code-writing agents if anything in those areas changes.
  5. Test this document with a reader (ISO 24495-1 asks for this). Ask one engineer who was not in this session to read the Summary and Terms, then explain codeboost back to you. Fix any part they misread.

Historical assignment. This was completed before the initial implementation and is retained as design history:

  1. Pick one real, small issue in a repo you own.
  2. Write a plan for it by hand, in the format above.
  3. Run Claude on one plan item at a time. Tell it not to commit.
  4. After each plan item, commit the changes yourself, with Plan-Item: P<n> in the commit message.
  5. Use git log -p and git diff base..HEAD to sort every change into the table in "How codeboost links code to plan items."
  6. Write down every case where the table was unclear. Those cases become your first test cases.

How reviewer concerns were resolved

You asked us to resolve all 17 concerns from the second review round before approval. We did this after the review had ended, so no independent reviewer has re-checked these fixes.

Concern Where it is resolved
R2-1: the allowed list is not a real boundary Keeping unattended runs safe: the sandbox, changes that need your approval, and the note on the allowed list
R2-2: agents can read credential files Keeping unattended runs safe: the sandbox (empty HOME, blocked folders, credential helper off) and known limits
R2-3: comments from non-collaborators Keeping unattended runs safe: which comments reach the agent
R2-4: the "already fixed" check matches its own PR How codeboost runs a plan: checking whether the issue is already fixed; test cases
R2-5: rebasing restarts GitHub's checks Approving and merging: what happens when you click "Approve & merge"
R2-6: how rebase conflicts are handled Approving and merging: how rebasing works
R2-7: partial changes when the plan is wrong How codeboost runs a plan: when the plan is wrong
R2-8: hunks with lines from several plan items How codeboost links code to plan items: segments; test cases
R2-9: whether assignments carry forward How codeboost links code to plan items: assigning ambiguous or unplanned changes
R2-10: whitespace changes How codeboost links code to plan items: what an approval records; test cases
R2-11: what the "Attributed" check means How codeboost links code to plan items: the four checks
R2-12: failing checks do not block merging Approving and merging: when you can merge
R2-13: stopping did not match step 5 The queue, stopping, and recovery: stopping, and time and round limits
R2-14: who owns the PR description; when questions run The plan format: where the plan lives; Asking questions
R2-15: how go/no-go PRs are made and planted How we will know it works: the real-PR test
R2-16: citations Why this is worth building
R2-17: node:sqlite stability; reading branch rules Tools and storage; Approving and merging: checking branch rules

What I noticed about how you think

  • You wrote "user can define when to start working on the plans in the task queue and when to stop but allowing the task to finish." The words "but allowing the task to finish" show you think about work that is already running. Most first drafts skip that.
  • You made "The plan will explicitly define all the changes required in details on a file by file level" its own step, apart from writing the plan. That split made the linking design possible. The declared-files check comes straight from your step 3.
  • You wrote that a rejected task goes back "with all of user's feedback," not back to the start. You were already designing a revision loop, not a retry button.
  • When approving, you asked for the plan to meet ISO 24495-1:2023. You treat the document as something other people must be able to use, not only a record for yourself.

About the next section

The section below is the review tool's original record, copied word for word. It is kept as history, so it is not rewritten in plain language. For what changed, see "How reviewer concerns were resolved" above.

Reviewer Concerns

Disposition: CONCERNS_RECORDED

Stop: CONVERGENCE

R2-1 — feasibility

Problem

The Execute/fix shell allowlist (test, lint, build, package install) is not a real boundary: the same agent can edit test files, package.json scripts, Makefile targets, or add dependencies with install scripts in the worktree, then run an allowlisted command that executes that code. With no network sandbox, this yields arbitrary code execution and egress on the user's machine from an agent steered by untrusted issue text, which conflicts with the 'safe by default' constraint.

Remedy

State the allowlist's real guarantee honestly (it limits accidental commands, not a hostile agent), and either add a containment layer for execute/fix (OS sandbox or container, or Claude/Codex sandbox modes with network off except during a codeboost-run install step) or require user approval before running commands whose definitions the agent changed in this task (script, Makefile, lockfile, dependency changes).

R2-2 — completeness

Problem

Credential protection only strips environment variables. File edits are limited to the worktree, but file reads and allowlisted commands can still reach ~/.config/gh/hosts.yml or the OS keyring-backed gh token, ~/.ssh, ~/.npmrc, cloud credential files, and the git credential helper, so 'gh auth stays with codeboost's own process' is not enforced.

Remedy

Define read restrictions for agent invocations (deny paths outside the worktree, or run with a separate HOME/credential-free profile) and document which credential stores remain reachable in v1 as a known limit.

R2-3 — completeness

Problem

Eligibility is decided by the issue author, but comments from non-collaborators on an eligible issue still flow into planning and execution prompts, so untrusted text reaches the agent without the 'trust this issue' action.

Remedy

State whether non-collaborator comments are excluded, included only after explicit trust, or included in the delimited data block, and record which comments were supplied to each invocation.

R2-4 — feasibility

Problem

The superseded check looks for gh timeline cross-references to open or merged PRs, but codeboost's own PR (and a needs-human draft PR) cross-references the issue, so the pre-merge check would match itself and move every task to 'possibly superseded'.

Remedy

Exclude the task's own PR (and its prior draft PRs) and its own branch commits from all superseded signals, and add this case to the tests.

R2-5 — feasibility

Problem

codeboost rebases onto the current base right before merge, which force-pushes the branch and restarts CI; the merge gate requires required checks to pass, so merge is blocked (or races pending checks) immediately after the rebase. The waiting behavior and whether the rebase happens on 'Approve & merge' click or earlier is undefined.

Remedy

Define the pre-merge sequence: rebase and push, wait for required checks on the new head (with timeout and UI status), re-run the superseded check, then merge; or merge only if the base has not moved since checks last passed.

R2-6 — feasibility

Problem

Rebase-conflict handling says 'an invocation scoped to the conflicted items' but git rebase stops per replayed commit. The document does not state the permission profile, which trailer the resolved commit keeps, how a conflict spanning several items' commits is handled, or how a hard stop or crash mid-rebase is recovered.

Remedy

Specify the conflict protocol: when codeboost pauses the rebase, what context and profile the agent gets, that the resolved commit keeps the original commit's trailers (or a new trailer rule), handling of multi-item conflicts, and rebase --abort on stop or crash recovery.

R2-7 — completeness

Problem

On a scope escape the invocation stops and returns a plan_amendment, but the document does not say what happens to the partial edits that invocation already made in declared files: committed under the item's trailer, discarded by reset, or kept uncommitted in the worktree while the task waits.

Remedy

Choose one behavior (e.g., reset the worktree to the last codeboost commit and re-run the whole item after the amendment is approved) and state it.

R2-8 — clarity

Problem

Provenance is defined per line (a line changed by several items is multi-item), but classification is per final hunk. A hunk can contain adjacent lines from different single-item commits without any single line being multi-item; its row and chips are undefined.

Remedy

Define hunk provenance from its lines (e.g., a hunk whose lines come from more than one item goes to Ambiguous, or hunks are split at provenance boundaries) and add a fixture for adjacent lines from two items.

R2-9 — completeness

Problem

Merge-gate decisions that assign an Ambiguous or Unplanned hunk to an item or accept it as-is are recorded, but their persistence across revision r+1, re-execution, and rebases is undefined, and it is not stated whether an assigned hunk becomes part of the item's approval snapshot.

Remedy

State the identity used to carry assignment/accept decisions forward, when they are invalidated, and whether assigned hunks enter the target item's content hash.

R2-10 — consistency

Problem

The approval snapshot is whitespace-normalized, yet the document says only a change to the item's own added or removed lines invalidates approval. A whitespace-only change to approved code (significant in Python, YAML, Makefiles, string literals) would not invalidate the approval, so the user can merge code they did not see.

Remedy

Restrict normalization to what cannot change semantics (e.g., line endings and trailing whitespace only), or state the accepted risk and exclude whitespace-significant files from normalization.

R2-11 — clarity

Problem

The Attributed chip is defined as green when every hunk in the row has single-item provenance and amber for shared-file, but the classification table sends every multi-item and no-trailer hunk to other rows, so every item row is single-item by construction. The chip therefore never signals missing attribution, and 'shared-file' overlaps with the In-scope judgment the premise says is kept separate. The chip state for a planned-but-unchanged item is also undefined.

Remedy

Redefine the Attributed chip so it can fail (e.g., amber/red when the item has hunks in the Ambiguous row) or drop it, move the shared-file marker to the scope judgment or a hunk badge, and define chips for items with no hunks.

R2-12 — clarity

Problem

The merge gate does not include the Correct signals, so failing cmd: acceptance commands or open review findings (e.g., after 'review anyway' from needs human) do not block Approve & merge. It is not stated whether this is intended.

Remedy

State explicitly whether failing tested or reviewed sub-signals block merge, show a warning, or are covered only by item approval, and list them among the unmet conditions if they gate.

R2-13 — consistency

Problem

Problem statement step 5 (the user's requirement) says a stop lets the in-flight task finish, and the coaching note praises that phrasing, but the soft stop parks the task at the next phase boundary instead of finishing it. The deviation from the stated requirement is not acknowledged.

Remedy

Either make soft stop finish the whole task (with the per-task budget as the bound) or record the phase-boundary behavior as a deliberate change to requirement 5 with its rationale for user approval.

R2-14 — clarity

Problem

The plan is re-rendered into the PR description on every revision, which silently overwrites any edits made to the description on GitHub; the behavior is unstated. Step 8 questions also run 'outside run windows', which can be read as only outside windows rather than regardless of windows.

Remedy

State that codeboost owns the PR description (or a delimited section of it) and what happens to external edits, and reword the question rule to 'regardless of run windows'.

R2-15 — feasibility

Problem

The decision gate runs after slice 2, before the executor exists, but the real-PR test needs a PR whose commits carry Plan-Item trailers. How that PR is produced is unstated. The user also plants the out-of-scope edit and then reviews the same PR, so catching a plant whose location they already know proves little.

Remedy

State that gate PRs are produced by the manual per-item protocol from The Assignment, and have someone else plant the out-of-scope edit (or plant it by script at a random location unknown to the reviewer) in both PRs.

R2-16 — consistency

Problem

The MSR '26 study of unmerged bug-fix PRs is still cited without title, authors, or link, and the arXiv 2601.15195 claim links to alphaxiv.org rather than arxiv.org; the specific findings attributed to both could not be verified from the document.

Remedy

Add a full citation and link for the MSR '26 study and use the canonical arxiv.org URL, or remove the attribution and keep the claim only as a hypothesis.

R2-17 — feasibility

Problem

node:sqlite is still experimental in Node 22.x (it prints an ExperimentalWarning and its API can change in minor releases), which is a stability risk for the single source of truth. Detecting branch protection 'when a repo is added' may also require admin permission for the protection API, so the detection can fail for non-admin collaborators.

Remedy

Pin a tested Node version range and isolate SQLite access behind a small storage module (with better-sqlite3 or a WASM build as fallback), and define the branch-protection detection method (rulesets API vs protection API) and its behavior when permission is denied.

Prior finding evidence

R1-18 → R2-16 (persisting)

The 33k-PR claim now cites arXiv 2601.15195 and claims are framed as hypotheses, but the MSR '26 study is still unidentified and the cited findings are unverified.

Engineering review (2026-09-22)

Who this is for. The builder, and anyone implementing codeboost. What it is for. It checks this design before code is written, and records each decision with your answer. Plain language per ISO 24495-1:2023.

Target: this document, docs/designs/codeboost-plan-indexed-review.md. Priority: check the 17 round-2 fixes, which no independent reviewer had checked.

Evidence from probes (run 2026-09-22)

What the design assumes How we checked What we found
node:sqlite is experimental and needs a fallback node -e "require('node:sqlite')" on Node v26.7.0 Loads with no warning
GitHub rulesets need only read access gh api repos/codeabovelab/codeboost/rules/branches/main Works. Returns an org ruleset copilot_code_review with review_on_push: true
Classic branch protection gh api .../branches/main/protection 404 "Branch not protected"
A scratch HOME keeps agents signed in codex exec --help: "auth still uses CODEX_HOME" (default ~/.codex); ~/.claude/.credentials.json does not exist (Claude uses the keychain and ~/.claude.json) Moving HOME moves where both tools look for sign-in data
Claude Code has a sandbox mode claude --help (v2.1.278) No sandbox flag. Sandboxing is set through --settings JSON. --disallowedTools and --strict-mcp-config exist
Codex has a sandbox codex exec --help (v0.153.4) -s/--sandbox <mode> exists

Scope record

  • Feature answers: no cuts proposed. The 9 steps stay; the cancelled go/no-go experiment no longer gates them under the superseding product decision.
  • Structure: B, Smaller arrangement (answer D1). One npm package, 6 modules: core (plan format and linking engine, no I/O), git (worktree, commit, diff walk, rebase), agents (adapter interface, claude, codex, permission profiles), runner (one task state machine: run, review rounds, queue, schedule, recovery), github (gh wrapper), web (server and screen).
  • Accepted scope: all features in this document, in the 6-module layout.
  • Storage access lives inside runner (runner/store), which alone writes task state; web reads and sends commands through runner. The command-line entry lives in web (web/cli). Answer D9 (R8).
  • Pending remedies: R1 to R8, T1.

Findings

Format: [severity] (confidence) location — finding. P1 blocks building; P2 should be fixed in the same build step; P3 can follow later.

Checking the 17 fixes

Fix Holds? Note
R2-1 sandbox and approval pause Partly See R1 and R2
R2-2 credential reads No See R1: a scratch HOME breaks sign-in
R2-3 comments Yes
R2-4 own PR excluded Yes
R2-5 pre-merge sequence Partly See R6: repos with no CI
R2-6 rebase conflicts Partly See R5: commits with no trailer
R2-7 partial edits Yes
R2-8 segments Yes
R2-9 carried-forward assignments Partly See R4: identical segments collide
R2-10 whitespace Yes
R2-11 checks Yes
R2-12 merge gate Yes
R2-13 stopping Yes
R2-14 PR description Yes
R2-15 planted change No See R3: the plant always lands in Unplanned, so the test is too easy
R2-16 citations Yes
R2-17 storage and branch rules Partly Branch rules confirmed by probe. See R7: the sql.js fallback is not needed

Section 1. Architecture

  1. [P1] (8/10) Keeping unattended runs safe, "Invocations run with HOME set to a per-task scratch directory" — Codex reads sign-in from CODEX_HOME (default ~/.codex) and Claude reads ~/.claude.json. A scratch HOME signs both tools out, so every unattended run fails. → R1
  2. [P1] (7/10) Keeping unattended runs safe, "the network is off" — The OS sandbox covers shell commands. Claude's WebFetch and WebSearch tools and any MCP servers run outside it, so issue text could still make the agent send data out. → R2
  3. [P1] (8/10) How we will know it works, "adds one out-of-scope change at a random place" — The plant script's commit has no trailer, so it always lands in the red Unplanned row. The test never checks the hard cases: an agent's unrelated edit inside a plan item's commit, in a declared or undeclared file. Neither signal can catch an unrelated edit inside a declared file. The Summary does not say so. → R3
  4. [P3] (8/10) Probe — The org ruleset runs Copilot code review on every push. Each rebase push starts a new Copilot review on the PR. It does not block merging. No decision needed. It is noted under Failure modes.

Section 2. Code quality 5. [P2] (7/10) Assigning ambiguous or unplanned changes, "codeboost remembers your choice by file and exact content" — Two identical segments in one file (such as two } lines) share one key, so one decision silently applies to both. → R4 6. [P2] (7/10) How rebasing works, "Every commit belongs to exactly one plan item" — A commit pushed by someone else has no trailer. The conflict protocol does not say what to do when git stops on it. → R5 7. [P2] (7/10) Approving and merging, step 4 "codeboost waits for GitHub's required checks" — In a repo with no CI, gh pr checks reports no checks, and the design does not say whether that passes or waits 30 minutes. → R6 8. [P2] (7/10) Tools and storage, "sql.js instead" — Probe: node:sqlite loads with no warning on Node 26. sql.js keeps the database in memory and rewrites the whole file on save, which weakens the crash recovery the design depends on. → R7 9. [P3] (9/10) Scope record — D1 did not place storage access or the command-line entry. → R8

Section 3. Tests

No test framework exists yet (the repo holds only LICENSE, CLAUDE.md, and this document). Every path below is planned, not built, so every path is a gap today. The diagram lists the tests each planned path needs.

CODE PATHS (planned)                                  USER FLOWS (planned)
[+] core: plan format + linking engine                [+] Review one plan item
  ├── parse/validate plan         [GAP] unit            ├── [GAP] [→E2E] select item → its segments
  ├── per-commit diff walk        [GAP] unit+real git   ├── [GAP] [→E2E] Hunk n of m keyboard nav
  │   ├── added / removed / deletion-only             ├── [GAP] [→E2E] stale item opens "changed since"
  │   └── multi-item line → Ambiguous                 └── [GAP] [→E2E] ask a question, get answer
  ├── segment split + 12-cell table [GAP] unit (all 12 cells)
  ├── approval snapshot (CRLF only) [GAP] unit          [+] Approve & merge
  └── assign key (R4 occurrence)    [GAP] unit          ├── [GAP] [→E2E] gate lists unmet conditions
[+] git: worktree, commit, rebase                       ├── [GAP] [→E2E] merge anyway → recorded
  ├── commit with trailers          [GAP] real git      └── [GAP] [→E2E] merge blocked shows gh error
  ├── clean rebase keeps approvals  [GAP] real git
  ├── conflict on Px commit         [GAP] real git      [+] Reject with feedback
  ├── conflict on foreign commit (R5)[GAP] real git     └── [GAP] [→E2E] r+1 changes only that item
  └── abort on crash mid-rebase     [GAP] real git
[+] agents: adapters + container (R1, R2)               [+] Unattended run
  ├── claude / codex arg building   [GAP] unit          ├── [GAP] [→E2E] 3 tasks in a window
  ├── output parsing                [GAP] recorded transcripts ├── [GAP] soft stop finishes task
  ├── container mounts only /work + sign-in [GAP] [→E2E] real Docker ├── [GAP] hard stop resets worktree
  ├── network: vendor host OK, other host blocked [GAP] [→E2E] real Docker └── [GAP] laptop sleep → recovery
  └── prompts: issue text in data block [GAP] [→EVAL]
[+] runner: one task state machine                      [+] Error states the user sees
  ├── every state transition        [GAP] unit          ├── [GAP] Docker missing → clear message
  ├── scope escape → reset + amendment [GAP] unit       ├── [GAP] Node too old → upgrade message (R7)
  ├── review rounds stop at 3       [GAP] unit          └── [GAP] agent signed out → clear message
  ├── needs approval (deps/scripts) [GAP] unit
  └── restart recovery from store   [GAP] integration
[+] github: gh wrapper
  ├── superseded check excl. own PR [GAP] recorded gh output
  ├── required checks from rules (R6) [GAP] recorded gh output, zero-checks case
  └── plan section between markers  [GAP] unit
[+] web: screen + cli
  └── cli requirement checks        [GAP] unit

LLM: [GAP] [→EVAL] executor, review, and conflict prompts (does the agent ignore instructions hidden in issue text?)
LLM: [GAP] [→EVAL] lesson distilling (are lessons faithful to your feedback and not too broad?) (L1)
COVERAGE: 0/40 paths tested (0%): greenfield, all planned
GAPS: 40 (14 E2E, 1 eval)

Legend: ★★★ behavior + edge + error, ★★ happy path, ★ smoke check. [→E2E] needs an integration or end-to-end test. [→EVAL] needs an LLM evaluation.

No existing behavior is at risk (greenfield), so the regression rule does not apply yet.

Section 4. Performance

No issues found that need a decision. The diff walk runs once per task head, and a task has tens of commits, not thousands. Caching the linking result per head commit is an ordinary build detail.

Decision ledger

R1: How agents stay signed in while credential folders stay protected

Finding: 1, P1, confidence 8/10, "Keeping unattended runs safe" (HOME line), reviewer: Claude (plan-eng-review) Plan baseline: the agent process runs with HOME set to a per-task empty folder (resolution of R2-2, not independently approved) Runtime evidence: Codex reads sign-in from CODEX_HOME (default ~/.codex, per codex exec --help). Claude has no ~/.claude/.credentials.json and uses the keychain plus ~/.claude.json. Unknown: whether each vendor sandbox can block reads of chosen folders. Comparison grid:

Choice Current A B C
Agent process HOME scratch folder real HOME; CODEX_HOME and Claude config set explicitly real HOME inside a container that mounts only the worktree and agent sign-in scratch folder
HOME for shell commands the agent runs scratch folder scratch folder (set in the sandbox) container's own HOME scratch folder
Blocking reads of credential folders claimed as enforced enforced where the vendor sandbox allows it; a start-up self-test tries to read ~/.ssh, ~/.config/gh, ~/.npmrc, ~/.aws, ~/.docker inside the sandbox; any readable folder is listed as a known limit that you accept once before unattended runs enforced by the container claimed as enforced
New dependency none none Docker or Podman none
Agents stay signed in no yes yes no

Question D2: D2 — How should agents stay signed in while your credential folders stay protected? Project/branch/task: codeboost main, engineering review of the design doc, finding 1 (P1). ELI10: The design gives each agent run an empty home folder so it cannot read your SSH keys or GitHub login. But Codex and Claude keep their own sign-in in your home folder, so an empty one signs them out and every unattended run would fail. We need a different way to protect your secrets. Stakes if we pick wrong: pick C and every run fails. Pick a weaker option without a self-test and you may believe secrets are protected when they are not. Recommendation: A, because it keeps one-command install, keeps agents signed in, and uses a start-up test to show you exactly which folders are really protected instead of assuming. Completeness: A=8/10, B=10/10, C=2/10 Net: honest protection with no new dependency (A), strongest protection with Docker (B), or a design that does not run (C). Header: Agent sign-in Options: A) Real HOME + self-test (recommended) Agent process keeps your real HOME with CODEX_HOME and Claude config set explicitly; shell commands get an empty HOME inside the sandbox. A start-up self-test tries to read ~/.ssh, ~/.config/gh, ~/.npmrc, ~/.aws, ~/.docker from inside the sandbox; any readable folder is shown as a known limit you accept once before unattended runs. ✅ No new dependency, agents stay signed in. ✅ You see real protection, not claimed protection. ❌ Codex may allow reading some folders, which stays a known limit. (human: ~1 day / CC: ~20 min) B) Container isolation Each agent run happens in a Docker or Podman container that mounts only the task worktree and the agent's sign-in files. ✅ Strongest protection: other folders are simply not there. ✅ Same on macOS and Linux. ❌ Adds Docker or Podman as a requirement, which breaks one-command install. (human: ~3 days / CC: ~1 hour) C) Keep the empty HOME Leave the design as written. ✅ No change to the document. ✅ Nothing new to build. ❌ Both agent tools lose their sign-in, so every unattended run fails. (human: 0 / CC: 0)

State: approved Actual answer: B) Container isolation (answer to D2, 2026-09-22) Accepted scope: every agent invocation runs in a Docker or Podman container that mounts only the task worktree (writable) and the agent's own sign-in (Codex auth.json read-only; Claude via a claude setup-token token in an environment variable, because macOS keeps Claude's sign-in in the keychain). Docker or Podman becomes an install requirement. Tested claude and codex versions are pinned in the image. The vendor-sandbox self-test in option A is not adopted. Container network access is left to R2. Design sections amended: Summary, Terms used, Limits, Keeping unattended runs safe, Known limits, How people will install it. History: none

R2: What the agent container can reach on the network

Finding: 2, P1, confidence 7/10, "Keeping unattended runs safe" ("the network is off"), reviewer: Claude (plan-eng-review) Plan baseline: "the network is off" during agent runs (resolution of R2-1, not independently approved). R1 (approved, D2: B) puts the agent tool itself inside the container. Runtime evidence: the agent tool must call its vendor's model API to work, so a fully offline container cannot run it. claude --help lists --disallowedTools and --strict-mcp-config. Claude's WebFetch and WebSearch tools and MCP servers are separate ways to reach the internet. Unknown: the exact API host list each CLI version needs (to be pinned with the image). Comparison grid:

Choice Current A B C
Container network "off" (agent cannot work) internal network; an egress proxy allows only the agent vendor's API hosts, pinned per image version open internet "off"
Web and MCP tools not addressed also turned off: Claude --disallowedTools WebFetch,WebSearch and --strict-mcp-config with no servers; Codex web search off turned off (same flags) not addressed
Dependency installs codeboost step with network on, after approval unchanged unchanged unchanged
R1 container isolation approved (D2: B) unchanged unchanged unchanged

Question D3: D3 — What should the agent's container be allowed to reach on the network? Project/branch/task: codeboost main, engineering review of the design doc, finding 2 (P1). ELI10: The design says the network is off while an agent works. But the agent itself now runs in the container and must talk to Claude's or OpenAI's servers to think, so fully off means it cannot work. Issue text can be written by strangers and could try to make the agent send your code somewhere, so we want the smallest opening that still works. Stakes if we pick wrong: open internet lets a hostile issue send your code out. Fully off means nothing runs. Recommendation: A, because only the vendor's own API is reachable, and turning off the web tools as well gives two layers instead of one. Completeness: A=9/10, B=5/10, C=2/10 Net: vendor-only network with tools off (A), tools off but open network (B), or a container that cannot run (C). Header: Agent network Options: A) Vendor API only (recommended) The container sits on an internal network. A small proxy lets it reach only the agent vendor's API hosts, pinned per image version. Claude's WebFetch, WebSearch and MCP servers and Codex's web search are also turned off. ✅ A hostile issue cannot send code to an outside server. ✅ Two layers: network rule plus tools off. ❌ The host list must be updated when a CLI version changes. (human: ~1 day / CC: ~30 min) B) Tools off, network open Turn off the web and MCP tools with CLI flags, but leave the container on the open internet. ✅ Simple, no proxy to run. ✅ Blocks the obvious web tools. ❌ A shell command such as curl inside the container can still send code anywhere. (human: ~2 hours / CC: ~10 min) C) Keep "network off" Leave the design as written. ✅ No change to the document. ✅ Nothing new to build. ❌ The agent cannot reach its own model API, so no task can run. (human: 0 / CC: 0)

State: approved Actual answer: A) Vendor API only (answer to D3, 2026-09-22) Accepted scope: agent containers run on an internal network; an egress proxy allows only the agent vendor's API hosts, pinned per image version. Claude runs with --disallowedTools WebFetch,WebSearch and --strict-mcp-config with no servers; Codex runs with web search off. Applies to all phases. Dependency installs stay a separate codeboost step with network on, after approval. Design sections amended: Keeping unattended runs safe (network paragraph, permissions table). History: none

R3: Making the go/no-go test measure the hard case

Finding: 3, P1, confidence 8/10, "How we will know it works" (real-PR test, step 3), reviewer: Claude (plan-eng-review) Plan baseline: scripts/plant.ts adds one out-of-scope change at a random place in each PR (resolution of R2-15, not independently approved). The Summary says codeboost "checks each change against the files the plan item said it would touch." Runtime evidence: by the design's own table, a commit with no Plan-Item trailer always goes to the Unplanned row, so a scripted plant is always caught. An unrelated edit inside a plan item's commit and inside a declared file is "attributed" and "in scope" by construction. Only the review agent and the human can catch it. Unknown: how often agents make such edits. Comparison grid:

Choice Current A B C
How the plant enters the PR its own commit, no trailer amended into a randomly chosen plan item's commit, keeping that item's trailer unchanged unchanged
Where the plant goes random place half in an undeclared file, half in a declared file unchanged unchanged
How the gate reports results one pass or fail two catch rates: undeclared-file plants and declared-file plants, each compared with raw-diff review unchanged unchanged
Summary and assumptions state the blind spot no yes: "An unrelated edit inside a declared file is caught only by the review agent and by you." yes (same sentence) no

Question D4: D4 — Should the go/no-go test plant changes where they are hard to catch? Project/branch/task: codeboost main, engineering review of the design doc, finding 3 (P1). ELI10: The go/no-go test hides one out-of-place change in each PR to see if you catch it. But the script adds it as its own commit with no plan-item label, and codeboost puts every unlabeled change in the red Unplanned row, so codeboost always wins. Real agents slip unrelated edits inside a labeled commit, sometimes in a file the plan allowed, and codeboost's two checks cannot see those. Stakes if we pick wrong: the go/no-go check passes on the easy case, and you build weeks of agent-running code on a result that proves little. Recommendation: A, because it tests both the case codeboost catches and the case only reading catches, and it states the blind spot honestly. Completeness: A=10/10, B=6/10, C=3/10 Net: an honest test and honest docs (A), honest docs only (B), or an easy test (C). Header: Plant test Options: A) Hard plants + two scores (recommended) The plant script amends each plant into a randomly chosen plan item's commit, keeping its trailer. Half the plants go in an undeclared file, half in a declared file. The gate reports two catch rates against raw-diff review. The Summary and assumption 2 state that an unrelated edit inside a declared file is caught only by the review agent and by you. ✅ Tests the case agents actually produce. ✅ Shows where codeboost helps and where it cannot. ❌ Needs more gate PRs for two useful rates. (human: ~4 hours / CC: ~15 min) B) State the blind spot only Add the blind-spot sentence to the Summary and assumption 2, but keep the plant as its own commit. ✅ The docs become honest. ✅ No test change. ❌ The go/no-go check still measures only the easy case. (human: ~15 min / CC: ~2 min) C) Keep as written Leave the plant script and Summary as they are. ✅ No change. ✅ The gate is quick to run. ❌ The gate always passes and the blind spot stays hidden. (human: 0 / CC: 0)

State: approved Actual answer: A) Hard plants + two scores (answer to D4, 2026-09-22) Accepted scope: scripts/plant.ts puts two plants in each gate PR, one in an undeclared file and one in a declared file, each amended into a randomly chosen plan item's commit with its trailer kept, locations sealed until after review. The gate reports two catch rates against raw-diff review, passes only if codeboost catches each kind at least as often, and repeats with more PR pairs if two are too few. The Summary and assumption 2 state that an unrelated edit inside a declared file is caught only by the review agent and by you. Design sections amended: Summary, Assumptions we agreed on, How we will know it works. History: none

R4: Telling apart two identical segments in one file

Finding: 5, P2, confidence 7/10, "Assigning ambiguous or unplanned changes" ("codeboost remembers your choice by file and exact content"), reviewer: Claude (plan-eng-review) Plan baseline: a choice is keyed by file path plus the segment's exact content (resolution of R2-9, not independently approved) Runtime evidence: none; this is a design-level collision. Two segments with the same content in one file (for example two lone } lines) produce the same key. Comparison grid:

Choice Current A B C
Key for an assign or accept choice file + content file + content + occurrence number among identical segments in that file, in file order file + content + the 3 unchanged lines before and after file + content
When the choice lapses content changes content changes, or the occurrence number changes (safe: you decide again) content changes, or its neighbouring lines change content changes
One choice applies to two segments yes (bug) no no yes (bug)

Question D5: D5 — How should codeboost tell apart two identical changes in the same file? Project/branch/task: codeboost main, engineering review of the design doc, finding 5 (P2). ELI10: When you assign or accept an unplanned change, codeboost remembers that choice by file name and the changed text. If the same file has two identical changes, such as two lone closing braces, one choice silently applies to both. You could accept one and unknowingly accept the other. Stakes if we pick wrong: a change you never looked at gets accepted and can be merged. Recommendation: A, because counting which copy it is (first, second) is simple, and when the count shifts codeboost just asks you again, which is the safe failure. Completeness: A=9/10, B=8/10, C=4/10 Net: simple and safe (A), survives reordering but lapses more often (B), or a silent bug (C). Header: Segment key Options: A) Add occurrence number (recommended) Key each choice by file, content, and which copy it is among identical segments in that file (1st, 2nd, …). If the count changes, the choice lapses and you decide again. ✅ Simple to build and test. ✅ Fails safe: you are asked again, never silently approved. ❌ Adding an identical segment above makes you re-decide. (human: ~2 hours / CC: ~10 min) B) Add surrounding lines Key each choice by file, content, and the 3 unchanged lines before and after it. ✅ Survives segments moving around. ✅ Still tells copies apart when their neighbours differ. ❌ Lapses whenever nearby code changes, and identical neighbours can still collide. (human: ~3 hours / CC: ~15 min) C) Keep as written Key by file and content only. ✅ Simplest. ✅ No change to the design. ❌ One choice silently covers every identical copy in the file. (human: 0 / CC: 0)

State: approved Actual answer: A) Add occurrence number (answer to D5, 2026-09-22) Accepted scope: assign and accept choices are keyed by file path, the segment's exact content, and its occurrence number among identical segments in that file (file order). A choice lapses when any of the three changes, and you decide again. Add a test case: two identical segments in one file, accept only one, and the other stays in its row. Design sections amended: Assigning ambiguous or unplanned changes. History: none

R5: What happens when a rebase stops on a commit codeboost did not make

Finding: 6, P2, confidence 7/10, "How rebasing works" (step 1, "Every commit belongs to exactly one plan item"), reviewer: Claude (plan-eng-review) Plan baseline: on a conflict, git stops on one commit of plan item Px, and a sandboxed invocation for Px resolves it (resolution of R2-6, not independently approved). R1 and R2 (approved) place that invocation in the vendor-API-only container. Runtime evidence: the design's own Unplanned row exists because someone other than codeboost can push to the branch. Such a commit has no Plan-Item trailer, so "Px" does not exist for it. Comparison grid:

Choice Current A B C
Rebase stops on a commit with no trailer undefined cancel the rebase (git rebase --abort), move the task to needs human, name the commit and its author an agent resolves the conflict; the resolved lines stay in the Unplanned row undefined
Agent edits code codeboost did not make not stated never yes not stated
Conflicts on codeboost's own commits approved design text (Px protocol) unchanged unchanged unchanged

Question D6: D6 — What should happen when a rebase conflict hits a commit that codeboost did not make? Project/branch/task: codeboost main, engineering review of the design doc, finding 6 (P2). ELI10: Before review and before merging, codeboost moves the PR onto the latest main. If that causes a conflict, it asks the agent for the plan item that made the conflicting commit to fix it. But if a person pushed a commit to the PR branch, that commit belongs to no plan item, and the design does not say who fixes it. Stakes if we pick wrong: an agent could rewrite code a person wrote, with no plan item watching it, or the task could hang. Recommendation: A, because codeboost should never let an agent rewrite code that no plan covers. Stopping and asking you is rare and safe. Completeness: A=9/10, B=6/10, C=3/10 Net: stop and ask you (A), let the agent fix it and flag the result (B), or undefined (C). Header: Foreign conflict Options: A) Stop and ask you (recommended) Cancel the rebase so the branch is unchanged, move the task to needs human, and show the commit and its author. ✅ No agent ever edits code that no plan item covers. ✅ Simple, and the branch is always left as it was. ❌ You resolve that conflict yourself. (human: ~1 hour / CC: ~5 min) B) Agent fixes, result flagged Let a conflict-resolution invocation fix it; the resolved lines stay in the Unplanned row for you to review. ✅ No waiting on you. ✅ The result is still visible in the Unplanned row. ❌ An agent rewrites a person's code with no plan item to judge it against. (human: ~3 hours / CC: ~15 min) C) Keep as written Leave the case undefined. ✅ No change. ✅ Nothing to build now. ❌ Behavior is unknown: the task may hang or fail silently. (human: 0 / CC: 0)

State: approved Actual answer: B) Agent fixes, result flagged (answer to D6, 2026-09-22) Accepted scope: when a rebase stops on a commit with no Plan-Item trailer, codeboost runs a conflict-resolution invocation (same container and network rule as R1 and R2), limited to the conflicting files. The resolved commit keeps its original author and gets no trailer, so its lines stay in the Unplanned row, labeled "conflict resolved by agent." If the fix needs another file or fails, codeboost aborts the rebase and moves the task to needs human. Add a test case for this path. Design sections amended: How rebasing works. History: none

R6: What "required checks pass" means when a repo has no required checks

Finding: 7, P2, confidence 7/10, "Approving and merging" (pre-merge step 4, "codeboost waits for GitHub's required checks"), reviewer: Claude (plan-eng-review) Plan baseline: wait for required checks on the new head, 30-minute timeout, then "approved, merge blocked" (resolution of R2-5, not independently approved) Runtime evidence: probe of codeabovelab/codeboost main: no classic protection (404) and one org ruleset, copilot_code_review, which requires no status checks. So this repo has zero required checks. Unknown: the exact gh output for a PR with zero checks (no PR exists yet to probe). Comparison grid:

Choice Current A B C
Source of "required" not stated the branch's rules (all applicable rulesets plus classic protection, unioned; unreadable sources block), read at merge time every check reported on the PR, required or not not stated
Zero required checks undefined (may wait 30 min, then block) passes immediately passes if no checks are reported at all undefined
Copilot code review (a review, not a check) not stated ignored by the merge gate ignored by the merge gate not stated

Question D7: D7 — What should the merge step do when a repo has no required checks? Project/branch/task: codeboost main, engineering review of the design doc, finding 7 (P2). ELI10: Before merging, codeboost waits until GitHub's required checks pass. Many small repos, including codeboost itself today, have no required checks at all. The design does not say whether "none" counts as passing, so codeboost might wait 30 minutes and then refuse to merge. Stakes if we pick wrong: every merge in a repo without CI gets stuck, or codeboost waits on optional checks you never asked for. Recommendation: A, because GitHub's own rules decide what is required, and zero required checks means nothing to wait for. Completeness: A=9/10, B=7/10, C=3/10 Net: follow the branch rules (A), wait on every reported check (B), or undefined (C). Header: No CI checks Options: A) Follow branch rules (recommended) Read the branch's required checks from its rules at merge time. If there are none, the check condition passes at once. Copilot review is a review, not a check, so it is ignored. ✅ Matches what GitHub itself would enforce. ✅ Repos without CI merge without waiting. ❌ Optional checks that fail will not block the merge. (human: ~2 hours / CC: ~10 min) B) Wait on every check Wait for every check reported on the PR, required or not; zero checks passes. ✅ Stricter: even optional failing checks block. ✅ Simple rule to explain. ❌ Flaky optional checks can block merges GitHub would allow. (human: ~1 hour / CC: ~5 min) C) Keep as written Leave "required checks" undefined. ✅ No change. ✅ Nothing to build now. ❌ A repo with no CI may wait 30 minutes and then block every merge. (human: 0 / CC: 0)

State: approved Actual answer: A) Follow branch rules (answer to D7, 2026-09-22) Accepted scope: at merge time, codeboost reads the branch's required checks from its rules (all applicable rulesets plus classic protection, unioned; unreadable sources block). Zero required checks passes immediately. Reviews such as Copilot code review are not checks and are ignored by the merge gate. Optional checks do not block. Add test cases: zero required checks, one required check pending then passing, and a timeout. Design sections amended: Approving and merging, pre-merge step 4. History: none

R7: Whether to keep the sql.js storage fallback

Finding: 8, P2, confidence 7/10, "Tools and storage" ("If it is missing or fails a start-up check, codeboost uses sql.js instead"), reviewer: Claude (plan-eng-review) Plan baseline: node:sqlite by default on Node 22.13 or later, with sql.js as a fallback (resolution of R2-17, not independently approved) Runtime evidence: node -e "require('node:sqlite')" on Node v26.7.0 loads with no warning, and an in-memory table can be created. sql.js holds the whole database in memory and writes the whole file when saving. Unknown: which Node 24 and 25 releases still print an experimental warning (not probed here). Comparison grid:

Choice Current A B C
Storage engine node:sqlite, sql.js fallback node:sqlite only node:sqlite only unchanged
Minimum Node version 22.13 the oldest version CI proves loads node:sqlite with no warning (26 confirmed today); older versions refused with a clear message 22.13, warning hidden 22.13
Crash safety of the task state weaker under sql.js full SQLite journaling on every supported version full SQLite journaling weaker under sql.js
Storage module wrapper yes yes (unchanged) yes (unchanged) yes

Question D8: D8 — Should codeboost drop the sql.js storage fallback? Project/branch/task: codeboost main, engineering review of the design doc, finding 8 (P2). ELI10: codeboost stores its task state in SQLite, which is built into Node. The design adds a backup engine, sql.js, in case the built-in one is missing. On Node 26 the built-in engine works with no warning. The backup keeps the whole database in memory and saves it all at once, so a crash can lose recent task state, which the recovery design depends on. Stakes if we pick wrong: keep the fallback and crash recovery can silently lose work on some computers. Pick the wrong minimum version and some users cannot start codeboost. Recommendation: A, because one storage engine with real crash safety is simpler, and a clear "please upgrade Node" message beats a weaker hidden backup. Completeness: A=9/10, B=7/10, C=6/10 Net: one safe engine on newer Node (A), one engine on older Node with a hidden warning (B), or two engines (C). Header: Storage engine Options: A) Drop it, CI-proven Node (recommended) Use only node:sqlite. Require the oldest Node version that CI proves loads it with no warning (Node 26 confirmed today); older Node gets a clear upgrade message. ✅ One engine, full crash safety everywhere. ✅ Less code to test. ❌ Users on older Node must upgrade first. (human: ~1 hour / CC: ~5 min) B) Drop it, keep Node 22.13 Use only node:sqlite from Node 22.13, hiding its experimental warning. ✅ Works on more Node versions. ✅ One engine. ❌ Relies on an API marked experimental in older versions, which may change. (human: ~1 hour / CC: ~5 min) C) Keep the fallback Keep node:sqlite with sql.js as a fallback, as written. ✅ Starts on almost any Node version. ✅ No change. ❌ Two engines to test, and the fallback weakens crash recovery. (human: 0 / CC: 0)

State: approved Actual answer: A) Drop it, CI-proven Node (answer to D8, 2026-09-22) Accepted scope: node:sqlite is the only storage engine; sql.js is removed. The minimum Node version is the oldest one CI proves loads node:sqlite with no warning (Node 26 confirmed on 2026-09-22); older Node stops at start-up with an upgrade message. The thin storage wrapper stays. CI runs a start-up test that fails if node:sqlite prints any warning. Design sections amended: Tools and storage, How people will install it. History: none

R8: Where storage access and the command-line entry live

Finding: 9, P3, confidence 9/10, Scope record ("Not placed by D1"), reviewer: Claude (plan-eng-review) Plan baseline: D1 (answer: B) approved 6 modules: core, git, agents, runner, github, web. The option text did not place storage access or the command-line entry. Runtime evidence: none needed; this is a layout gap in the approved answer. Comparison grid:

Choice Current A B C
Storage access unplaced inside runner (runner/store); only runner writes task state; web reads and sends commands through runner's interface its own store module, used by both runner and web unplaced
Command-line entry unplaced inside web (web/cli), which checks requirements and starts the server its own cli module unplaced
Module count 6 (D1) 6 (unchanged) 8 6
Features and approved rules (R1 to R7) approved unchanged unchanged unchanged

Question D9: D9 — Where should storage access and the command-line entry live? Project/branch/task: codeboost main, engineering review of the design doc, finding 9 (P3). ELI10: You chose 6 modules. But the option did not say where the database code or the npx codeboost starting point goes. If both the runner and the web screen write task state directly, they can disagree about a task, which is the problem the 6-module layout was meant to avoid. Stakes if we pick wrong: two writers of task state can leave a task half-updated after a crash. Recommendation: A, because one module writing task state matches why you chose 6 modules. Note: options differ in kind, not coverage — no completeness score. Net: keep 6 modules with one writer (A), or 8 modules with shared storage (B), or leave it open (C). Header: Store and CLI Options: A) Inside runner and web (recommended) Storage lives in runner, which alone writes task state; the web screen reads and sends commands through runner. The command-line entry lives in web and starts the server. ✅ One writer of task state, as D1 intended. ✅ Stays at 6 modules. ❌ The web screen must go through runner even to read. (human: ~same / CC: ~same) B) Two new modules Add a store module used by runner and web, and a cli module. ✅ Each concern has its own home. ✅ The web screen can read the database directly. ❌ Two writers of task state become possible, and the layout grows to 8 modules. (human: ~same / CC: ~same) C) Leave it open Decide during building. ✅ No decision now. ✅ Keeps options open. ❌ The first builder picks by accident, and task state may get two writers. (human: 0 / CC: 0)

State: approved Actual answer: A) Inside runner and web (answer to D9, 2026-09-22) Accepted scope: storage access lives in runner/store; only runner writes task state; web reads state and sends commands through runner's interface. The command-line entry lives in web/cli, checks requirements, and starts the server. Module count stays at 6. Design sections amended: Scope record. History: none

T1: How codeboost is tested

Finding: Section 3, no test framework and 40 planned paths untested, reviewer: Claude (plan-eng-review) Plan baseline: the design lists fixture test cases (build step 1) and the real-PR test, but names no framework and no way to test containers, git, gh, or prompts. Runtime evidence: no framework or test files in the repo. Comparison grid:

Choice Current A B
Framework none Vitest for unit and integration; Playwright for the review screen Vitest only
git behavior not stated real git in temporary folders, no git mocks mocked git
gh behavior not stated recorded gh outputs replayed (including zero-checks and superseded cases) mocked gh
Agent adapters not stated recorded CLI transcripts for parsing; arguments checked by unit tests mocked adapters
Container and network (R1, R2) not stated real-Docker end-to-end suite in CI: only /work and sign-in are visible; a vendor host is reachable; another host is blocked not tested
Prompts (issue text as data) not stated a small eval set of hostile issue texts; the agent must not follow them not tested
Test cases already approved (build step 1 list, R4, R5, R6, R7 cases) approved included included

Question D10: D10 — How thoroughly should codeboost be tested? Project/branch/task: codeboost main, engineering review of the design doc, Section 3 (Tests). ELI10: codeboost's promises are about safety and trust: the container really hides your files, the network rule really blocks strangers, and every changed line lands in the right row. Mock tests can pass while those promises are broken. Real git, real Docker, and a small test of hostile issue text check the promises themselves. Stakes if we pick wrong: with mocks only, a broken container or network rule ships while all tests pass, and a hostile issue could send your code out. Recommendation: A, because the safety and linking promises can only be proven against real git and real Docker, and with AI the extra tests cost minutes. Completeness: A=10/10, B=5/10 Net: tests that prove the promises (A), or fast tests that can pass while the promises are broken (B). Header: Test depth Options: A) Real git, Docker, evals (recommended) Vitest with real git in temporary folders, recorded gh outputs and CLI transcripts, a real-Docker suite in CI for the container and network rules, Playwright for the review screen, and a small eval of hostile issue texts. ✅ Tests fail when a safety promise breaks. ✅ Covers all 40 planned paths. ❌ CI needs Docker and runs slower. (human: ~2 weeks / CC: ~3 hours) B) Mocks only Vitest unit tests with git, gh, Docker, and agents mocked. ✅ Fast and simple CI. ✅ Easy to write. ❌ Container, network, and prompt safety are never actually tested, so they can break silently. (human: ~4 days / CC: ~1 hour)

State: approved Actual answer: A) Real git, Docker, evals (answer to D10, 2026-09-22) Accepted scope: Vitest for unit and integration tests; real git in temporary folders (no git mocks); recorded gh outputs and agent CLI transcripts; a real-Docker end-to-end suite in CI proving the container shows only /work and sign-in, a vendor host is reachable, and another host is blocked; Playwright for the review screen flows; a small eval set of hostile issue texts that the agent must not follow. Includes all previously approved test cases (build step 1 list, R4 to R7 cases). CI needs Docker. Include an agent that changes and immediately executes an allowed script: containment must still block host and disallowed network access, and codeboost must require approval before its own later invocation of that changed script. History: none

O1: Duplicate-segment choices after a copy is removed (reopens R4)

Finding: outside voice 1, P1, confidence 8/10, "Assigning ambiguous or unplanned changes" (R4 key), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: R4 approved (D5: A): key = file + content + occurrence number; a choice lapses when content or copy number changes. Runtime evidence: design reasoning, confirmed: accept copy 1 of two identical segments, then a revision deletes copy 1; old copy 2 becomes copy 1 and matches the saved key, so the acceptance moves to a segment you never judged. Comparison grid:

Choice Current (R4) A B C D
Duplicate-segment choice lapses when content or copy number changes content, copy number, or the count of identical segments in that file changes unchanged unchanged, investigate first unchanged, deferred
Choices on non-duplicate segments unchanged unchanged unchanged unchanged unchanged

Question D11: D11 — Should a choice on a repeated change lapse whenever the number of copies changes? Project/branch/task: codeboost main, engineering review, outside voice finding 1 (reopens your R4 answer). ELI10: You chose to tell identical changes apart by their copy number (1st, 2nd). Codex found a hole: if you accept copy 1 and a later revision deletes it, the old copy 2 becomes copy 1 and inherits your acceptance, even though you never looked at it. The fix is to forget such choices whenever the number of copies changes. Stakes if we pick wrong: a change you never judged is treated as accepted and can be merged. Recommendation: A, because it closes the hole with one extra condition, and the cost is only re-deciding a rare repeated change. Completeness: A=10/10, B=6/10, C=6/10, D=6/10 Net: close the hole now (A), keep R4 as is (B), look into it first (C), or leave it for later (D). Header: Copy count Options: A) Apply this change (recommended) A choice on a repeated change also lapses when the number of identical copies in that file changes. Add a test: accept copy 1, delete it, and copy 2 is back in its row. ✅ No acceptance can move to a change you did not see. ✅ One extra condition to build. ❌ You re-decide repeated changes more often. (human: ~1 hour / CC: ~5 min) B) Keep this row's current value Keep R4 exactly as approved. ✅ No change. ✅ Fewer re-decisions. ❌ An acceptance can silently move to a copy you never judged. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour checking how often repeated segments occur in real agent PRs; R4 stays as approved until then. ✅ Decision based on data. ✅ Nothing changes yet. ❌ The hole stays open while you look. (human: ~1 hour / CC: ~15 min) D) Defer this proposed change only Leave this finding unresolved and R4 unchanged; it is listed as an open decision. ✅ No work now. ✅ Stays visible in the report. ❌ The hole is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D11, 2026-09-22) Accepted scope: a choice on a duplicated segment also lapses when the count of identical segments in that file changes. Test case: accept copy 1 of two, delete copy 1, and the remaining copy is back in its row, undecided. Design sections amended: Assigning ambiguous or unplanned changes. History: R4 (D5: A) keyed by file + content + occurrence number; reopened because deleting an accepted copy transferred its acceptance to another copy.

O2: What an approval is bound to besides the changed lines

Finding: outside voice 2, P1, confidence 8/10, "What an approval records", reviewer: Codex (outside voice), confirmed by Claude Plan baseline: an approval stores, per file, the ordered added and removed lines, normalized only for line endings (R2-10 resolution; line-number-free per R2-5). Runtime evidence: design reasoning, confirmed: editing a plan item's intent, acceptance, declared files, or dependencies leaves its diff unchanged, so the approval stays fresh. The same lines moved into another function also keep the same snapshot. Comparison grid:

Choice Current A B C D
Plan item definition in the approval no yes: a hash of title, intent, changes, declared files, acceptance, depends_on; any change makes it stale no no, investigate no, deferred
Code location in the approval no yes: each segment's enclosing function name from git's hunk header (not line numbers) no no no
Dependencies not stated if a plan item goes stale, items that list it in depends_on go stale too not stated not stated not stated
Line-number-free rebases (R2-5) kept kept kept kept kept

Question D12: D12 — Should an approval also cover the plan item's text, its code location, and its dependencies? Project/branch/task: codeboost main, engineering review, outside voice finding 2. ELI10: Today an approval remembers only which lines changed. If someone edits what the plan item is supposed to do, or its tests, the approval stays green even though you approved a different promise. The same lines moved into a different function also stay green. And if an item this one depends on changes, nothing tells you. Stakes if we pick wrong: you merge code under an approval you gave for a different plan or a different place in the code. Recommendation: A, because an approval should mean "this code, doing this job, in this place", and function names from git's hunk header survive rebases. Completeness: A=10/10, B=5/10, C=5/10, D=5/10 Net: approvals that match what you actually agreed to (A), text-only approvals (B), look first (C), or later (D). Header: Approval scope Options: A) Apply this change (recommended) Approval also hashes the plan item's definition and records each segment's enclosing function from git's hunk header; changing either makes it stale, and staleness spreads to items that depend on it. ✅ Approval matches the job and place you agreed to. ✅ Still survives line shifts and clean rebases. ❌ More re-reviews when plans or dependencies change. (human: ~4 hours / CC: ~20 min) B) Keep this row's current value Approval stays tied to changed lines only. ✅ No change. ✅ Fewest re-reviews. ❌ A changed plan or moved code keeps a green approval. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 2 hours testing how stable git's function context is across rebases on real repos; approvals stay as designed meanwhile. ✅ Checks the location idea before relying on it. ✅ No design change yet. ❌ The gap stays open while you look. (human: ~2 hours / CC: ~20 min) D) Defer this proposed change only Leave this finding open; approvals stay as designed. ✅ No work now. ✅ Listed as an open decision. ❌ The gap is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D12, 2026-09-22) Accepted scope: an approval also stores a hash of the plan item definition (title, intent, changes, declared files, acceptance, depends_on) and each segment's enclosing function name from git's hunk header; a change to either makes it stale. Staleness propagates to every item that lists the stale item in depends_on. Line-number-free rebase tolerance is kept. Test cases: edit an item's acceptance only (stale); move identical lines into another function (stale); dependency goes stale (dependent stale); line shift only (fresh). Design sections amended: How codeboost links code to plan items. History: none

O3: Re-running acceptance commands after a rebase

Finding: outside voice 3, P1, confidence 8/10, "Approving and merging" (pre-merge sequence), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: the pre-merge sequence rebases, pushes, waits for required GitHub checks (R6: zero required checks pass at once), re-checks "already fixed", then merges. The "tested" sub-signal is computed "on the latest code" in the merge gate, but the sequence never re-runs cmd: checks after the rebase. Runtime evidence: design reasoning, confirmed: a clean rebase can change behavior (a dependency changed on main) without changing any plan item's diff, so approvals stay fresh and old test results are reused. Comparison grid:

Choice Current A B C D
cmd: checks after a rebase not re-run re-run on the rebased head, in the container (R1, R2), before merging; any failure blocks merge and returns to review not re-run not re-run, investigate not re-run, deferred
Test results bound to unstated the head commit they ran on; results for any other head are shown as out of date unstated unstated unstated
Approvals unchanged unchanged (a test failure does not by itself make an approval stale) unchanged unchanged unchanged

Question D13: D13 — Should codeboost re-run each plan item's test commands after moving the PR onto the latest main? Project/branch/task: codeboost main, engineering review, outside voice finding 3. ELI10: Just before merging, codeboost moves the PR onto the latest main. That can break things even when the PR's own lines did not change, for example when someone changed a function the PR calls. Today codeboost re-checks GitHub's checks but not the plan's own test commands, and in a repo with no CI nothing is re-tested at all. Stakes if we pick wrong: codeboost merges code that fails its own tests on the current main. Recommendation: A, because tests only mean something for the exact code being merged. Completeness: A=10/10, B=5/10, C=5/10, D=5/10 Net: merge only freshly tested code (A), trust old results (B), look first (C), or later (D). Header: Retest on rebase Options: A) Apply this change (recommended) After a rebase, re-run every plan item's cmd: checks on the new head in the container before merging; a failure blocks merge and sends you back to review. Test results are tied to the head they ran on. ✅ Only freshly tested code merges. ✅ Works in repos with no CI. ❌ Merging takes as long as the test run. (human: ~3 hours / CC: ~15 min) B) Keep this row's current value Reuse earlier test results after a rebase. ✅ Faster merges. ✅ No change. ❌ Code that breaks on the current main can merge. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour measuring how long typical cmd: checks take, to judge merge delay; nothing changes meanwhile. ✅ Know the cost first. ✅ No design change yet. ❌ The gap stays open while you look. (human: ~1 hour / CC: ~10 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The gap is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D13, 2026-09-22) Accepted scope: after any rebase in the pre-merge sequence, codeboost re-runs every plan item's cmd: checks on the rebased head in the container (R1, R2) before merging; any failure blocks merge and returns the task to review. Test results are bound to the head commit they ran on; results for other heads display as out of date. Approvals are not made stale by a test failure alone. Test case: rebase onto a main that breaks a dependency without changing item diffs; merge blocks. Design sections amended: Approving and merging, pre-merge step 3. History: none

O4: Binding the merge to the exact commit you reviewed

Finding: outside voice 4, P1, confidence 9/10, "Approving and merging" (pre-merge step 5, gh pr merge), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: step 5 re-runs the "already fixed" check, then runs gh pr merge. Nothing ties the merge to the head commit that was reviewed and tested. Runtime evidence: gh pr merge --help lists --match-head-commit SHA Commit SHA that the pull request head must match to allow merge. A person can push to the branch between codeboost's checks and the merge. Comparison grid:

Choice Current A B C D
Merge command gh pr merge gh pr merge --match-head-commit <sha>, where sha is the head whose approvals, cmd: results (O3), and required checks all passed unchanged unchanged, investigate unchanged, deferred
Head moved before merge merges the new head GitHub refuses; codeboost reloads the PR, recomputes links, and returns to review with changed items stale merges the new head merges the new head merges the new head

Question D14: D14 — Should the merge only go through if the PR still points at the exact commit you reviewed? Project/branch/task: codeboost main, engineering review, outside voice finding 4. ELI10: Between codeboost's last check and the moment it presses merge, someone could push a new commit to the PR. Today codeboost would merge that new commit without anyone reviewing or testing it. GitHub's CLI can refuse the merge unless the PR is still at a given commit. Stakes if we pick wrong: code nobody reviewed or tested lands on main. Recommendation: A, because it is one flag that GitHub enforces for us, and it closes the gap completely. Completeness: A=10/10, B=4/10, C=4/10, D=4/10 Net: an exact-commit merge (A), or a small window where unreviewed code can merge (B, C, D). Header: Exact-head merge Options: A) Apply this change (recommended) Merge with gh pr merge --match-head-commit set to the commit that passed approvals, tests and checks. If the PR moved, GitHub refuses, and codeboost reloads it and returns to review with changed items stale. ✅ GitHub itself enforces the guarantee. ✅ One flag plus a reload path. ❌ A late push forces another review round. (human: ~2 hours / CC: ~10 min) B) Keep this row's current value Merge with plain gh pr merge. ✅ No change. ✅ Late pushes never interrupt a merge. ❌ A commit pushed after the last check merges unreviewed and untested. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 30 minutes checking how --match-head-commit behaves with merge commits and squash; nothing changes meanwhile. ✅ Confirms the flag's behavior first. ✅ No design change yet. ❌ The gap stays open while you look. (human: ~30 min / CC: ~5 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The gap is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D14, 2026-09-22) Accepted scope: the merge runs as gh pr merge --match-head-commit <sha> with the head whose approvals, cmd: results (O3), and required checks passed. If GitHub refuses because the head moved, codeboost reloads the PR, recomputes links, and returns to review with changed items stale. Test case: push a commit between the last check and the merge; merge is refused and the task returns to review. Design sections amended: Approving and merging, pre-merge step 5. History: none

O5: Proving which commits codeboost made (not trusting commit messages)

Finding: outside voice 5, P1, confidence 8/10, "How codeboost links code to plan items" and "A conflict on a commit codeboost did not make" (R5), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: a segment's owner comes from the Plan-Item trailer in the commit message. R5 (D6: B) treats a commit with no trailer as foreign. R3 (D4: A) relies on this weakness on purpose: the plant script amends plants into item commits and keeps their trailers. Runtime evidence: design reasoning, confirmed: anyone with push access can amend or write a commit that carries Plan-Item: P2. Its lines would count as "attributed" to P2 and its conflicts would be handled as P2's. Comparison grid:

Choice Current A B C D
Source of truth for "codeboost made this commit" the trailer text a ledger in runner/store of every commit sha codeboost created, plus old-sha to new-sha mappings for each rebase codeboost ran the trailer text the trailer text, investigate the trailer text, deferred
A commit with a trailer but not in the ledger trusted treated as foreign: its lines go to the Unplanned row, and conflicts follow R5 trusted trusted trusted
Trailers the attribution kept as a readable label in history, not as proof unchanged unchanged unchanged
R3 plant test amended plants keep trailers the plant script also records each amended commit in the ledger, because a real agent's stray edit sits inside a commit codeboost made; so R3 still tests the hard case unchanged unchanged unchanged

Question D15: D15 — Should codeboost trust only its own record of which commits it made, rather than the commit message? Project/branch/task: codeboost main, engineering review, outside voice finding 5. ELI10: codeboost decides which plan item owns each line by reading a label in the commit message. But anyone who can push can write that label. So a person, or a buggy tool, could slip code in under a plan item's name, and codeboost would call it planned. Keeping its own list of the commits it created, and updating the list when it rebases, makes the label unforgeable. Stakes if we pick wrong: code nobody planned shows up as "attributed" and "in scope", and you approve it without knowing. Recommendation: A, because codeboost already makes every commit itself, so recording them costs little and turns the label from a claim into a fact. Completeness: A=10/10, B=5/10, C=5/10, D=5/10 Net: a ledger codeboost controls (A), or labels anyone can forge (B, C, D). Header: Commit ledger Options: A) Apply this change (recommended) Record every commit sha codeboost creates, and the old-to-new sha mapping for each rebase it runs. Only ledger entries with a non-null plan-item owner count as that item's work; explicitly unowned entries stay Unplanned; any other commit is foreign, whatever its message says. The R3 plant script also records its amended commits in the ledger, so the go/no-go test still measures the hard case. ✅ Plan-item labels can no longer be forged. ✅ Cheap, since codeboost already makes every commit. ❌ Commits rewritten outside codeboost lose their attribution. (human: ~4 hours / CC: ~20 min) B) Keep this row's current value Keep using the trailer as proof. ✅ No change. ✅ Survives any history rewriting. ❌ Anyone who can push can make code look planned. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour checking how to keep the ledger valid through GitHub-side edits (web edits, force pushes); trailers stay the proof meanwhile. ✅ Finds edge cases first. ✅ No design change yet. ❌ The forgery gap stays open while you look. (human: ~1 hour / CC: ~10 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The gap is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D15, 2026-09-22) Accepted scope: runner/store keeps a ledger of every commit sha codeboost creates and old-to-new sha mappings for every rebase it runs. Only ledger entries with a non-null plan-item owner count as that item's work; explicitly unowned entries stay Unplanned; a commit not in the ledger is foreign regardless of its trailer (lines to Unplanned, conflicts per R5). Trailers remain as readable labels. The R3 plant script records its amended commits in the ledger. Test cases: forged trailer on a pushed commit lands in Unplanned; rebased owned ledger commits keep their attribution through the mapping; a missing/null-owner conflict enters the foreign branch before any Px lookup, stays unowned through resolution, and maps to Unplanned. Design sections amended: How codeboost links code to plan items; A conflict on a commit codeboost did not make; How we will know it works (plant step). History: none

O6: Giving the container a working git without exposing your main repo

Finding: outside voice 6, P1, confidence 9/10, "Tools and storage" (Workspaces: git worktree) and R1 (container mounts only the worktree), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: each task gets its own git worktree; R1 (D2: B) mounts only that worktree into the container. Runtime evidence: probe on 2026-09-22: a linked worktree's .git is a one-line file, gitdir: …/m/.git/worktrees/wt, pointing into the main repository. Mounted alone, git inside the container cannot find its data. Mounting the main repo writable would widen the container's boundary. Comparison grid:

Choice Current A B C D
Task workspace git worktree a standalone per-task clone (git clone --local --no-hardlinks), whose .git folder is inside the task folder git worktree git worktree, investigate git worktree, deferred
What the container mounts the worktree (git broken inside) the task folder, including its own .git the worktree the worktree the worktree
Who pushes to GitHub codeboost codeboost, from outside the container (the clone's remote is a local path, unreachable inside; the network rule R2 also blocks GitHub) codeboost codeboost codeboost
Your main checkout untouched untouched, and never mounted untouched untouched untouched
Disk use shared objects independent object copies; no hard links or alternates shared shared shared

Question D16: D16 — How should each task get a working git inside its container? Project/branch/task: codeboost main, engineering review, outside voice finding 6. ELI10: codeboost gives each task a git worktree, which is a light copy that stores only a pointer to your main repository. The container can see only the task folder, not your main repository, so git inside the container breaks. Agents use git all the time to see what they changed. A full copy of the repository per task fixes this without exposing your main repository. Stakes if we pick wrong: agents cannot use git inside the container, or your main repository becomes writable by the agent. Recommendation: A, because a per-task clone keeps git working and keeps your main repository out of the container. Completeness: A=10/10, B=3/10, C=5/10, D=3/10 Net: working git and a sealed main repo (A), or broken git in the container (B, C, D). Header: Container git Options: A) Apply this change (recommended) Replace per-task worktrees with a standalone per-task clone (git clone --local --no-hardlinks) that the container mounts, .git included. codeboost pushes from outside the container. ✅ Git works normally inside the container. ✅ Your main repository is never mounted or writable. ❌ Uses more disk per task because objects are copied. (human: ~3 hours / CC: ~15 min) B) Keep this row's current value Keep git worktree and mount only the worktree. ✅ No change. ✅ Least disk use. ❌ Git does not work inside the container, so agents cannot inspect their own changes. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour trying other layouts (read-only mount of the main .git, runner-supplied diffs) on a real agent task; worktrees stay meanwhile. ✅ Compares options on a real task. ✅ No design change yet. ❌ Container git stays broken while you look. (human: ~1 hour / CC: ~15 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The first agent run in a container will fail at git. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D16, 2026-09-22) Accepted scope: each task uses a standalone clone (git clone --local --no-hardlinks) with its own .git inside the task folder; the container mounts that folder as /work; codeboost pushes from outside the container; the main checkout is never mounted. Objects are copied, never hard-linked or borrowed through alternates. Test case: inside the container, git status and git diff work, and the main repository path is absent. In disposable repositories, modifying an object in the task clone must leave the source object unchanged. Design sections amended: Tools and storage (Workspaces), Keeping unattended runs safe (container contents). History: PR #1 review found that --local alone shares object inodes with the source. The corrected command uses --no-hardlinks; a local probe reproduced source-object corruption without it.

O7: Changes that have no text lines

Finding: outside voice 7, P1, confidence 8/10, "How codeboost links code to plan items" (segments are runs of changed lines), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: the linking engine, the classification table, and approval snapshots all work on changed text lines. Runtime evidence: design reasoning, confirmed: git reports binary content changes, file mode changes (such as the executable bit), empty files added or deleted, renames with no content change, symlink changes, and submodule pointer changes without any text lines. None of these can become a segment today, so they could bypass the rows and the merge gate. Comparison grid:

Choice Current A B C D
Binary, mode, empty-file, rename, symlink, submodule changes not represented each becomes a "file change" segment, owned through the commit ledger (O5) and placed by the same classification table not represented not represented, investigate not represented, deferred
Approval snapshot for a file change none old and new path, old and new mode, and old and new typed object ID (blob for files/links, commit for gitlinks) none none none
Review screen nothing shown a file-change card: "binary changed (size a → b)", "made executable", "renamed from x", and so on nothing shown nothing shown nothing shown
Merge gate ignores them treats them like any other segment ignores them ignores them ignores them

Question D17: D17 — How should codeboost handle changes that have no text lines, like images, permission changes, and renames? Project/branch/task: codeboost main, engineering review, outside voice finding 7. ELI10: codeboost reviews changes line by line. But some changes have no lines: an image replaced, a script made executable, a file renamed, an empty file added. Right now these do not appear in any row, so they could slip past the review and the merge rules entirely. Stakes if we pick wrong: a binary or a newly executable script merges without anyone seeing it. Recommendation: A, because every change must land in some row, and a small "file change" card covers all six kinds with the same rules. Completeness: A=10/10, B=3/10, C=5/10, D=3/10 Net: every change visible and gated (A), or some changes invisible (B, C, D). Header: Non-text changes Options: A) Apply this change (recommended) Treat binary, mode, empty-file, rename, symlink and submodule changes as "file change" segments, placed by the same table, approved by path, mode and typed object ID, and shown as a card on the review screen. ✅ No change can bypass review or the merge gate. ✅ Reuses the existing rules. ❌ One more segment kind to build and test. (human: ~1 day / CC: ~30 min) B) Keep this row's current value Leave non-text changes out of the model. ✅ No change. ✅ Simpler engine. ❌ Binary and permission changes merge unseen. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour listing which non-text changes agents actually produce in real PRs; nothing changes meanwhile. ✅ Build only what occurs. ✅ No design change yet. ❌ The gap stays open while you look. (human: ~1 hour / CC: ~10 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The gap is open when building starts. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D17, 2026-09-22) Accepted scope: binary, mode, empty-file, rename, symlink, and submodule changes become file-change segments, owned via the commit ledger (O5), placed by the classification table, approved by old/new path, mode, and typed object ID (blob for files/links, commit for gitlinks), shown as cards, and gated like any segment. Test cases: one of each of the six kinds lands in the correct row and blocks merge until approved. Design sections amended: How codeboost links code to plan items. History: none

O8: Narrowing build step 2 to a read-only review screen

Finding: outside voice 8 (part 1), P2, confidence 7/10, "Build order and the go/no-go check" (step 2 includes merging), reviewer: Codex (outside voice), confirmed by Claude Plan baseline: build step 2 = review screen covering steps 7 to 9, including the merge rules and merging through gh. Runtime evidence: design reasoning, confirmed: the merge path now depends on later pieces (container runs for cmd: re-tests O3, conflict resolution R5, commit ledger O5), so building it before the go/no-go check front-loads work the check may cancel. Comparison grid:

Choice Current A B C D
Build step 2 scope review screen plus merge gate and gh merge read-only review screen: rows, segments, checks, approvals, conversation; no merging unchanged unchanged, investigate unchanged, deferred
When merge gate and merging are built step 2 a new step right after the go/no-go check passes, before running agents step 2 step 2 step 2
Experiment design (O9) pending pending pending pending pending

Question D18: D18 — Should build step 2 be a read-only review screen, with merging built only after the go/no-go check? Project/branch/task: codeboost main, engineering review, outside voice finding 8 (part 1). ELI10: Build step 2 currently includes merging, which now depends on the container, re-running tests, and the commit ledger. That is a lot to build before learning whether reviewing by plan item even helps. A read-only screen is enough for the go/no-go check. Stakes if we pick wrong: days of merge work get built for an idea the check might reject. Recommendation: A, because the go/no-go check needs only the read-only screen, and merging can wait until the idea is proven. Completeness: A=10/10, B=6/10, C=6/10, D=6/10 Net: less work before proof (A), or merging built first (B, C, D). Header: Step 2 scope Options: A) Apply this change (recommended) Build step 2 becomes a read-only review screen: rows, segments, checks, approvals and conversation, no merging. The merge gate and merging become a new step right after the go/no-go check passes. ✅ Less to build before the idea is proven. ✅ The check still has everything it needs. ❌ You cannot merge from codeboost until later. (human: saves ~1 week / CC: saves ~2 hours) B) Keep this row's current value Keep the merge gate and merging in build step 2. ✅ No change. ✅ The full review loop works early. ❌ More work before the go/no-go check. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 30 minutes sizing the merge work against the rest of step 2; nothing changes meanwhile. ✅ Know the cost first. ✅ No design change yet. ❌ Step 2 scope stays unsettled. (human: ~30 min / CC: ~5 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ Building may start with the wider step 2. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D18, 2026-09-22) Accepted scope: build step 2 is a read-only review screen (rows, segments, four checks, approvals, per-item conversation; no merging). The merge gate, pre-merge sequence, and gh merge become build step 4, right after the go/no-go check. Later steps renumber: running agents 5, planning 6, queue 7, issue list 8. Design sections amended: Build order and the go/no-go check. History: an earlier draft of this record bundled the experiment design; it was split into O8 and O9 before being asked.

O9: Writing the go/no-go experiment down before running it

Finding: outside voice 8 (part 2), P2, confidence 7/10, "The real-PR test", reviewer: Codex (outside voice), confirmed by Claude Plan baseline: R3 (D4: A): two PRs, one reviewed per method; two plants per PR (declared and undeclared file); pass if codeboost catches each kind at least as often as raw review, no slower, no unexplained change; "repeat with more pairs" if two PRs are too few. Runtime evidence: design reasoning, confirmed: different PRs per method mix PR difficulty into the result; "at least as often" passes when both methods catch nothing; "repeat with more pairs" has no limit. Comparison grid:

Choice Current (R3) A B C D
Pairs and assignment 2 PRs, one per method at least 4 pairs of similar issues; within each pair one PR per method, and which PR gets which method alternates across pairs unchanged unchanged, investigate unchanged, deferred
Pass rule each plant kind caught at least as often; no slower; no unexplained change codeboost catches at least 3 of 4 undeclared-file plants and more than raw review; declared-file rate reported with no bar; median review time no slower; no unexplained change unchanged unchanged unchanged
Stopping rule "repeat with more pairs" stop at 4 pairs; if the result is within one catch of the bar, run 4 more pairs once, then decide unchanged unchanged unchanged
When the rules are written not stated committed to the repo before the first review not stated not stated not stated
Plants (R3, O5) approved unchanged unchanged unchanged unchanged

Question D19: D19 — Should the go/no-go experiment be larger and fairer, with its rules written down before you run it? Project/branch/task: codeboost main, engineering review, outside voice finding 8 (part 2). ELI10: The go/no-go test compares one PR reviewed the old way with a different PR reviewed in codeboost. If one PR is harder, the result is skewed. The pass rule also passes when both ways miss every planted change, and "add more pairs if unclear" has no end. Writing a fair setup and clear rules down first keeps you from moving the goalposts. Stakes if we pick wrong: the check says "go" on noise, and you build the rest of codeboost on an idea that was never really tested. Recommendation: A, because a few more pairs and rules fixed in advance make the result trustworthy at a small cost. Completeness: A=10/10, B=5/10, C=5/10, D=5/10 Net: a fair test with fixed rules (A), or a quick test that can pass on noise (B, C, D). Header: Experiment rules Options: A) Apply this change (recommended) At least 4 PR pairs, methods alternated across pairs; pass if codeboost catches at least 3 of 4 undeclared-file plants and more than raw review, no slower on median time, no unexplained change; declared-file rate reported; stop at 4 pairs, or 8 once if within one catch of the bar; rules committed before the first review. ✅ Result cannot pass on a tie or on PR difficulty. ✅ Clear end point. ❌ About twice as much review time as the current test. (human: ~2 days of reviewing / CC: ~10 min to write rules) B) Keep this row's current value Keep R3's two-PR test and rules. ✅ No change. ✅ Quickest to run. ❌ Can pass on a tie or because one PR was easier. (human: 0 / CC: 0) C) Investigate before choosing Spend up to 1 hour estimating how many pairs give a clear answer; R3 stays meanwhile. ✅ Pair count based on reasoning. ✅ No design change yet. ❌ The test stays weak while you look. (human: ~1 hour / CC: ~10 min) D) Defer this proposed change only Leave this finding open. ✅ No work now. ✅ Listed as an open decision. ❌ The go/no-go test may run with weak rules. (human: 0 / CC: 0)

State: approved Actual answer: A) Apply this change (answer to D19, 2026-09-22) Accepted scope: the go/no-go rules are committed before the first review; at least 4 PR pairs, one PR per method in each pair, method assignment alternated across pairs; pass if codeboost catches at least 3 of 4 undeclared-file plants and more than raw review, median time no slower, no unexplained change; declared-file rate reported for both methods with no bar; stop at 4 pairs, or run 4 more once if within one catch of the bar. Plants stay as R3 and O5. Design sections amended: How we will know it works (real-PR test). History: split from O8 before asking.

L1: How codeboost turns your feedback into learning

Finding: new requirement from you (answer to D20, 2026-09-22): "the application should learn from the user's feedback comment for continuous improvement", reviewer: Claude (plan-eng-review) Plan baseline: none. Your feedback (rejection notes, change requests, per-item questions, accept and assign choices) feeds the next revision of one task only (steps 8 and 9) and is then forgotten. Runtime evidence: none; new behavior. The agent CLIs run with your subscriptions, so fine-tuning a model is not possible. Learning has to happen through what codeboost puts in its prompts. Comparison grid:

Choice Current A B C
Feedback that counts used for one task only your rejection notes, change requests, and accept, assign, and "accepted finding" choices same none
How it becomes learning not at all after each task closes, an agent distills the feedback into short lessons (for example "In this repo, every retry change needs a test for the 5xx path"), each linked to the feedback it came from the raw feedback text is added to later prompts not at all
Where lessons are used nowhere planning, execution, and review prompts, in a clearly labeled section same nowhere
Source rule n/a only your own feedback; never issue text or comments from others same n/a
Stored in n/a runner/store (single writer, R8) same n/a
Build order n/a new step after step 7 (queue), since it needs the reject loop same n/a
Lesson approval (L2), scope (L3), measurement (L4) pending pending pending pending

Question D21: D21 — How should codeboost turn your review feedback into learning? Project/branch/task: codeboost main, engineering review, new requirement (continuous improvement from your feedback). ELI10: Today your feedback fixes one task and is then forgotten. So if you tell the agent "always add a test for error paths" on Monday, you tell it again on Friday. The agent tools cannot be retrained, so codeboost can only learn by adding what it learned to its prompts. It can either boil your feedback down into short lessons, or paste your old comments in as they are. Stakes if we pick wrong: raw comments pile up, get stale, and crowd out the plan in the prompt. No learning means you repeat yourself forever. Recommendation: A, because short lessons linked to their source stay readable, stay small in the prompt, and can be checked and removed. Completeness: A=9/10, B=5/10, C=2/10 Net: distilled lessons (A), raw comment history (B), or no learning (C). Header: Learning method Options: A) Distilled lessons (recommended) After each task closes, an agent boils your feedback down into short lessons, each linked to the comment it came from. Lessons go into planning, execution, and review prompts in a labeled section. Only your own feedback is used. ✅ Small, readable, and traceable to its source. ✅ Works with subscriptions; no retraining needed. ❌ The distilling agent can phrase a lesson wrongly (L2 decides who checks). (human: ~1 week / CC: ~1 hour) B) Raw feedback history Paste your earlier feedback comments into later prompts as they are. ✅ Nothing is lost or reworded. ✅ Simpler to build. ❌ Grows without limit, goes stale, and crowds out the plan in the prompt. (human: ~2 days / CC: ~20 min) C) No learning Keep feedback per task only, as designed. ✅ No new work. ✅ Smallest product. ❌ Does not meet your new requirement; you repeat the same feedback. (human: 0 / CC: 0)

State: approved Actual answer: A) Distilled lessons (answer to D21, 2026-09-22) Accepted scope: after each task closes, an agent distills your feedback (rejection notes, change requests, accept, assign, and accepted-finding choices) into short lessons, each linked to its source feedback. Lessons are stored in runner/store and added in a labeled section to planning, execution, and review prompts. Only your own feedback is used, never issue text or others' comments. Built as a new step after step 7. Approval of lessons (L2), scope (L3), and measurement (L4) are decided separately. History: none

L2: Who checks a lesson before codeboost uses it

Finding: new requirement, part 2, reviewer: Claude (plan-eng-review) Plan baseline: L1 approved (D21: A): an agent distills your feedback into lessons that go into later prompts. Runtime evidence: none; new behavior. Lessons steer unattended runs, and the distilling agent can phrase a lesson too broadly (for example "never touch config files"). Comparison grid:

Choice Current A B
When a new lesson is used pending only after you approve it in a Lessons inbox; you can edit the wording first right away
Your controls afterwards pending edit, turn off, or delete any lesson; each shows the feedback it came from edit, turn off, or delete any lesson; each shows the feedback it came from
Which prompts used a lesson pending recorded per invocation, visible on the task recorded per invocation, visible on the task
L1 method approved (D21: A) unchanged unchanged
Scope (L3), measurement (L4) pending pending pending

Question D22: D22 — Should each new lesson wait for your approval before codeboost uses it? Project/branch/task: codeboost main, engineering review, new requirement (learning), part 2. ELI10: After a task, codeboost writes short lessons from your feedback. Those lessons then steer agents that run while you are away. If a lesson is worded too broadly, say "never change config files", it could quietly block good work in every later task. You can check each lesson before it is used, or let it apply at once and clean up later. Stakes if we pick wrong: a wrong lesson silently steers every unattended run until you notice. Recommendation: A, because a one-click approval is cheap, and it keeps you in control of what the agents are told. Completeness: A=9/10, B=6/10 Net: you approve each lesson first (A), or lessons apply at once and you fix them later (B). Header: Lesson approval Options: A) You approve first (recommended) New lessons wait in a Lessons inbox; you approve, edit, or discard each one before it is used. Every lesson shows its source feedback, and each task shows which lessons it used. ✅ No lesson steers an agent without your OK. ✅ You can fix the wording first. ❌ Lessons wait until you check the inbox. (human: ~1 day / CC: ~20 min) B) Use at once New lessons apply immediately; you can edit, turn off, or delete them later. Each shows its source, and each task shows which lessons it used. ✅ Learning takes effect on the next task. ✅ No inbox to manage. ❌ A badly worded lesson steers runs until you notice it. (human: ~4 hours / CC: ~10 min)

State: approved Actual answer: A) You approve first (answer to D22, 2026-09-22) Accepted scope: new lessons wait in a Lessons inbox and are not used until you approve them; you can edit the wording before approving, and edit, turn off, or delete any lesson later. Each lesson shows its source feedback; each task records which lessons its invocations used. Test cases: an unapproved lesson never appears in a prompt; a turned-off lesson stops appearing. History: none

L3: Which repos a lesson applies to

Finding: new requirement, part 3, reviewer: Claude (plan-eng-review) Plan baseline: L1 (D21: A) distilled lessons; L2 (D22: A) you approve each lesson first. Scope not yet decided. Runtime evidence: none; new behavior. Some feedback is about one codebase ("use our retry helper"), some is about how you like to work ("always add an error-path test"). Comparison grid:

Choice Current A B C
Default scope of a new lesson pending the repo it came from all your repos the repo it came from
Sharing across repos pending you can mark a lesson "all my repos" when approving or later automatic not possible
L1, L2 approved unchanged unchanged unchanged
Measurement (L4) pending pending pending pending

Question D23: D23 — Which repos should a lesson apply to? Project/branch/task: codeboost main, engineering review, new requirement (learning), part 3. ELI10: Some of your feedback is about one codebase, like "use our retry helper". Some is about how you like to work anywhere, like "always test the error path". A lesson can stay in the repo it came from, apply everywhere, or start in one repo and be shared when you say so. Stakes if we pick wrong: repo-specific rules leak into other projects and confuse the agent, or good general habits have to be re-learned in every repo. Recommendation: A, because it keeps lessons local by default and lets you share the general ones with one click. Note: options differ in kind, not coverage — no completeness score. Net: local by default with opt-in sharing (A), everywhere (B), or local only (C). Header: Lesson scope Options: A) Repo first, share on request (recommended) A lesson applies to the repo it came from. When you approve it, or later, you can mark it "all my repos". ✅ Repo-specific rules never leak elsewhere. ✅ General habits can still be shared. ❌ One more choice per lesson. (human: ~4 hours / CC: ~10 min) B) All repos Every lesson applies to every repo you use with codeboost. ✅ Learns once, applies everywhere. ✅ Simplest. ❌ Repo-specific rules confuse agents in other projects. (human: ~2 hours / CC: ~5 min) C) This repo only Lessons never leave the repo they came from. ✅ No leaking at all. ✅ Simple. ❌ General habits must be re-learned in each repo. (human: ~2 hours / CC: ~5 min)

State: approved Actual answer: A) Repo first, share on request (answer to D23, 2026-09-22) Accepted scope: a lesson applies by default to the repo it came from; when approving it or later, you can mark it "all my repos". Test case: a repo-scoped lesson never appears in another repo's prompts; a shared lesson does. History: none

L4: How to tell whether learning is working

Finding: new requirement, part 4, reviewer: Claude (plan-eng-review) Plan baseline: L1 (D21: A), L2 (D22: A), L3 (D23: A) approved. No measurement defined. Runtime evidence: none; new behavior. Without numbers, lessons could pile up with no effect, or make things worse, and nobody would know. Comparison grid:

Choice Current A B
What is tracked, per repo nothing rejections per task, review rounds per task, and repeated feedback (new feedback the distilling agent matches to an existing approved lesson) nothing
Where you see it n/a a small Learning screen with the numbers over time n/a
Lessons that are not working n/a a lesson whose feedback keeps repeating is flagged for rewording or removal n/a
L1 to L3 approved unchanged unchanged

Question D24: D24 — Should codeboost measure whether its learning actually reduces repeat feedback? Project/branch/task: codeboost main, engineering review, new requirement (learning), part 4. ELI10: The point of learning is that you give the same feedback less often. codeboost can count, per repo, how often you reject tasks, how many review rounds they take, and how often you repeat feedback that an approved lesson should already cover. A lesson that keeps getting repeated is not working and gets flagged. Stakes if we pick wrong: without numbers, you cannot tell whether lessons help, and useless lessons keep filling the prompts. Recommendation: A, because a few counts show whether the feature works and point at lessons to fix. Completeness: A=9/10, B=4/10 Net: measured learning with flags for weak lessons (A), or learning you have to take on faith (B). Header: Learning metrics Options: A) Track and flag (recommended) Per repo, track rejections per task, review rounds per task, and repeated feedback; show them on a Learning screen over time; flag lessons whose feedback keeps repeating. ✅ You can see whether learning helps. ✅ Weak lessons surface on their own. ❌ Matching feedback to lessons uses an agent and can be wrong. (human: ~2 days / CC: ~30 min) B) No measurement Learn and apply lessons without tracking results. ✅ Less to build. ✅ No extra screen. ❌ No way to know if lessons help or hurt. (human: 0 / CC: 0)

State: approved Actual answer: A) Track and flag (answer to D24, 2026-09-22) Accepted scope: per repo, codeboost tracks rejections per task, review rounds per task, and repeated feedback (new feedback the distilling agent matches to an approved lesson); a Learning screen shows these over time; a lesson whose feedback keeps repeating is flagged for rewording or removal. Test cases: repeated feedback matching an approved lesson increments its repeat count and flags it after a set number of repeats. History: none

P1: One plan schema for drafting, importing, and suggestions

Finding: request from you (2026-09-22): "Codex or Claude should be able to generate plans. Should we create a template for them to follow and that we can directly import from", reviewer: Claude (after the design review) Plan baseline: "The plan format" showed a YAML example with free-text changes for all files of an item and untyped cmd: / check: lines. Nothing defined which fields are required, how an agent's answer is parsed, or how a hand-written plan is imported. Runtime evidence (probed 2026-09-22):

  • claude --help (Claude Code 2.1.278) lists --json-schema <schema>; codex exec --help (Codex CLI 0.153.4) lists --output-schema <FILE>.
  • Both CLIs returned a plan for a test issue that passed schema/plan.schema.json, and a suggested edit that passed schema/plan-edit.schema.json.
  • Claude Code rejected the schema while it had a $schema line for draft 2020-12 ("no schema with key or ref"), and accepted it without that line.
  • codex exec waits on stdin when stdin is not a terminal; it must run with stdin closed. Comparison grid:
Choice Current A B C
How agents answer not defined JSON that must match one schema, enforced by the CLI flag Markdown or YAML text that codeboost parses free text that a second agent converts
Importing a plan file not possible YAML or JSON, checked by the same schema YAML only, with a hand-written parser not possible
Plan assistant suggestions not defined typed edit operations (second schema); Apply is exact free text; the person edits by hand free text; an agent applies it
Checks after the schema none unique IDs, earlier-only dependencies, safe paths, valid projected source/destination state; failures block approval same same
Versioning none schema_version in every plan none none

Question: asked in conversation, not as a numbered question. Claude recommended A. State: approved Actual answer: yes, add it to the design doc and create them (2026-09-22) Accepted scope: one versioned plan schema (schema/plan.schema.json) and one edit schema (schema/plan-edit.schema.json), both strict-mode compatible and without a $schema line; YAML and JSON with the same structure; a plain-language guide (docs/plan-format.md); one prompt template for both agents (prompts/plan-author.md); worked examples in schema/examples/; import on the Plans screen as the next draft revision; checks after import as listed in the guide. Test cases: both examples pass; broken plans (no acceptance, extra field, bad ID, absolute path, unknown kind, no files, wrong version, missing field) fail; the edit schema's copied definitions match the plan schema's; a recorded Claude answer and a recorded Codex answer both pass. History: none

Approval readiness: PASS (re-checked after the learning requirement). Checked L1 (D21: A), L2 (D22: A), L3 (D23: A), L4 (D24: A), D1 (scope, structure B), R1 (D2: B), R2 (D3: A), R3 (D4: A), R4 (D5: A), R5 (D6: B), R6 (D7: A), R7 (D8: A), R8 (D9: A), T1 (D10: A), O1 (D11: A), O2 (D12: A), O3 (D13: A), O4 (D14: A), O5 (D15: A), O6 (D16: A), O7 (D17: A), O8 (D18: A), O9 (D19: A). Every accepted change cites its own answer. No TODO proposals were raised by this review; the design's existing Open questions stay as written.

Outside voice

Codex (outside voice, completed, 2026-09-22) raised 8 findings. Claude checked each: 2 by probe (gh pr merge --match-head-commit exists; a worktree's .git is only a pointer), 6 by design reasoning. Finding 8 held two independent choices and was split into O8 and O9. All 9 records were answered, all with A. Agreement between the two reviewers was treated as evidence, not approval.

Not in scope

  • Issue ranking weights, parallel tasks, and a different agent per phase. These stay in Open questions and do not affect the review idea. The cancelled experiment is not a phase boundary.
  • Reusing AgentDiff code. Decided: read, not reused (docs/implementation/build-step-1.md).
  • Windows support. The container and sign-in design was checked for macOS and Linux only.

What already exists

  • git already provides worktrees, clone --local --no-hardlinks, rebase, and per-commit diffs. The plan uses these rather than writing its own.
  • gh already provides rulesets, checks, and pr merge --match-head-commit. The plan uses these rather than calling the API directly.
  • Docker is installed on this machine. The plan runs agents in containers instead of relying on vendor sandboxes.
  • Claude CLI already provides --disallowedTools, --strict-mcp-config, and setup-token. Used for the network and sign-in rules.
  • Codex CLI already provides --sandbox and CODEX_HOME. Used for the sign-in mount.
  • Node 26 has node:sqlite built in. Used as the only storage engine.
  • Claude CLI and Codex CLI both take a JSON Schema for their final answer: claude -p --json-schema and codex exec --output-schema. Used for plan drafting and plan suggestions (P1). Tested on 2026-09-22 with Claude Code 2.1.278 and Codex CLI 0.153.4.

Nothing in the repo is rebuilt.

Diagrams

Task state flow, owned by runner (single writer, R8):

queued ──start (in run window)──> running ──all items done──> reviewing-rounds
  ^                                  │  scope escape               │ clean / 3 rounds
  │                                  v                             v
  │                           needs amendment              pr-open / needs human
  │                                  │ you approve r+1             │
  └──────────────────────────────────┘                             v
  ^                                                         in review (you)
  │   reject with feedback (r+1)                                    │ approve & merge
  └─────────────────────────────────────────────────────────────────┤
                                                                    v
                            pre-merge: fetch → rebase? → re-run cmd: (O3) → required checks (R6)
                                   → already-fixed check → merge --match-head-commit (O4)
                                   │ head moved / test fails            │ ok
                                   v                                    v
                               in review                              merged

Linking pipeline (core, pure; inputs from git and the commit ledger in runner/store):

base..head commits ──filter by ledger (O5)──> ledger commits  |  foreign commits
        │                                           │                 │
   per-commit diff walk (added, removed, file-change O7)             │
        │                                                             │
   line provenance ──> segments (split at owner change) ──> table ──> rows
                                                              │
                              approvals = lines + item fingerprint + function (O2)
                              choices   = file + content + copy no. + copy count (R4, O1)

Files that need inline diagrams when built: runner state machine, core segment classifier, git rebase and ledger mapping.

Failure modes

New path Realistic failure Test Handling What the user sees
Container start Docker not running yes (T1) refuse to run agents clear message
Agent sign-in Claude token expired yes (T1) task to needs human clear message
Network rule vendor adds a new API host after a CLI update yes (real-Docker suite) image pins CLI and hosts together agent error, then needs human
Rebase conflict on a foreign commit yes (R5) agent fixes, lines stay Unplanned flagged row
Pre-merge a person pushes during merge yes (O4) GitHub refuses the merge back to review
Pre-merge tests break after rebase yes (O3) merge blocked back to review
Linking forged trailer yes (O5) treated as foreign Unplanned row
Linking binary or mode change yes (O7) file-change card visible card
Learning a lesson is worded too broadly yes (L2) waits in the Lessons inbox until you approve it inbox item with its source feedback
Learning a lesson has no effect yes (L4) repeated feedback flags the lesson flagged on the Learning screen
Copilot review on every push (org ruleset) review comments after each rebase push none needed not a check, ignored by the gate comments on the PR

Critical gaps (no test, no handling, and silent): 0.

Parallel build lanes

Scheduling decision (2026-09-24). Run up to three implementation tasks concurrently in separate feature branches and worktrees. The foundation and review screen are the baseline, not new assignments. Recheck current main, open PRs, and existing implementations before taking a lane; unchecked historical T-items are not proof that their code is missing. These lanes authorize a development schedule, not simultaneous task execution in the shipped runner.

Current state. The lane plans below record the original schedule. B0 and lanes C, D, E, G, H and K are done, so their rows and handoff steps describe past work, not current owners or blockers. For the current state of each lane, see the lane table in docs/architecture.md. Before editing a shared file, follow "Task resumption and ownership" in AGENTS.md.

Lane status (checked 2026-09-26, after #55)

This table is a snapshot from 2026-09-26 and is not kept current. For the current state of each lane, see the lane table in docs/architecture.md. This table records merged and open PRs only. A lane is complete only when every step meets its acceptance criteria on main.

Lane Merged Open PRs Next
B0 — foundation verification Evidence recorded under Implementation Tasks: T4, T5, T10, T13, T14 met; E's subset in docs/implementation/planning-audit.md — T3 rebase part moves to F3
C — guarded merge gate C1–C4 (PR #23) — Done. Remaining build step 4 work belongs to F (#22)
D — agent isolation D1 (#31), D2 (#40), D3 (#44), D4 (#47), D5 (#50); gate in docs/implementation/agent-isolation.md — Done. F, G4 and live planning may now use the boundary; Ask already does
E — planning logic E1 (#30), E2 (#32), E3 (#35), suggestion lifecycle bindings (#43) E4 #45 (draft; replaces #37) Finish E4 with real recordings
F — runner F1 contract (#49, docs/implementation/runner-lifecycle.md); Ask in the agent container (#54), which ends the interim R1 exception F1a #53 (Store lifecycle), F1b #56 (coordinator), F1c #57 (shutdown wiring, /api/runner), F1d #59 (startup recovery, single-runner lock), F1e #60 (planning API for G4, feedback events) Land F1a–F1e in stack order, then F2. The F1 stack must not merge as a whole until #51's pre-F1 D items land
G — planning screen — — G1 after E4
H — issue prioritization H1–H3 (#39), trust fix #42 (issue #41), H4a Issues screen (#55) — H4b: the "trust this issue" action, which needs Store persistence through F after F1a. H4a holds the web files until G1 starts. Follow-up #58 (disconnect concern)
I, J — — After F6
K — merge-queue compatibility K1 (#38), K2–K3 (#46, closes #24); see docs/implementation/merge-queue.md — Done

Task assignment and sequential order

Read each row left to right: finish and validate step 1 before step 2 within that lane. Different rows may proceed concurrently when their prerequisites are met, with at most three active implementation tasks. A lane is a workstream, not necessarily one PR. Split large steps into reviewable PRs without changing the dependency order.

Lane Ordered task sequence Prerequisites / handoff
B0 — foundation verification 1. Inspect existing T14 module/writer boundaries and T13 SQLite/runtime checks. 2. Verify existing T3 ledger attribution, T4 approval staleness, T5 file-change segments and T10 duplicate-choice semantics against their acceptance criteria. 3. Reconcile gaps with #6 and record evidence; schedule only missing behavior. Read-only baseline check before a dependent lane relies on these contracts. This is not a foundation rebuild or a claim that all historical checkboxes are complete. Any required fix gets its own owner and must land before the consuming step.
C — guarded merge gate C1. Required-check and branch-rule reads (T12). C2. Snapshot/evidence blockers, with unavailable T6 execution evidence blocking merge. C3. Head-pinned, base-protected merge and refusal handling (T7). C4. Review UI, race regressions and final #21 / PR #23 review. Before C1, record B0 evidence for the foundation contracts C consumes; existing work must supply that evidence before C4 completion. Continue existing work rather than restarting implemented steps. Release shared runner/UI files after C4 merges.
D — agent isolation D1. Invocation contract and isolated task clone (T1). D2. Pinned, restricted container and startup self-test (T1). D3. Vendor-only egress and phase/tool enforcement (T2). D4. Claude/Codex adapters, cancellation settlement and bounded output. D5. Full real-Docker and hostile-input gate for this boundary (T9). Can run alongside C and E. F requires D5 merged; G's production invocation requires D5. Add regressions with each step; D5 integrates them rather than postponing testing.
E — planning logic E1. Audit existing T18 schema/parser/prompt behavior and remaining #6 gaps. E2. Read-only authoring-provider contract and safe prompt/response handling. E3. Identity/revision-bound suggestion orchestration using the existing store interface. E4. Import, replay, malformed-response and hostile-input acceptance fixtures (T18). Can run alongside C and D with injected providers. G consumes E4; live invocation waits for D5. Shared schema/store fixes must go through the assigned integration owner.
F — runner and pre-merge automation F1. Before implementation, publish and review the lifecycle/state-holder contract: pending, running, completed, failed, cancelled, stale and closing; legal transitions; ownership and settlement for persisted records, in-memory jobs, subprocesses, admitted HTTP requests and rendered UI; guarded retry; reject-admission → drain requests → cancel/await jobs → close storage. Then implement it and the feedback-event contract under the AGENTS.md async rules. F2. Per-item execution, review/reject rounds, pre-PR already-fixed checks, PR opening and hostile-issue eval (build step 5; T9). F3. Trusted rebase and ledger mapping (remaining T3). F4. Foreign-commit conflict handling (T11). F5. Post-rebase attribution/approval refresh and head-bound command execution (T6). F6. Required-check refresh, already-fixed check, guarded merge handoff and #22 integration regressions. F owns common CI after C: integrate every T9 suite (Docker, adapter, hostile-input/issue, recorded-output, unit and browser) into required CI, coordinating D's dedicated workflow. T9 remains incomplete until the combined head demonstrably runs and passes every suite. F6c status: complete on 2026-10-19. The workflows are in place (docs/implementation/ci.md), test and real-docker are required on main and passed on the combined head ba8294d (before the ruleset existed), and a Live probes run passed, so T9 is ticked. Starts after C4 and D5 merge and B0 evidence is handed off for F's consumed contracts. Recheck that evidence against merged main before F1; existing T4/T5/T10 behavior is reused rather than rebuilt. F1 owns planning persistence/API additions needed by G. F2's working reject loop supplies the learning dependency. Ask already uses D's invocation contract (runner/question-container.ts), so F reuses that path rather than adding a second one.
G — planning screen G1. Import and plan display UI. G2. Authoring and suggestion cards. G3. Revision-bound Apply and draft/attachment preservation. G4. Real provider/store integration and complete T18 browser/adapter acceptance. G1 starts after E4 and C4 merge; G1–G3 may use fixtures. G4 waits for D5 and F1's production planning API/persistence contract. Release shared web files after G4.
H — issue prioritization H1. Decide and record ranking policy. H2. Issue retrieval/normalization. H3. Deterministic ranking with reasons and failure/stale states. H4. Issue-list UI and end-to-end checks (build step 8). H1–H3 can run alongside F/G after the issue-access contract is inspected. H4 waits for G4 to release shared web files. No existing T-ID covers this entire milestone.
I — queue, schedule and recovery I1. Queue admission and persisted transitions. I2. Run-window scheduling and cancellation. I3. Restart recovery, stale attempts and shutdown draining. I4. UI integration and controlled race acceptance (build step 7). Starts after F6; owns shared runner/store files. UI work waits for G/H to release its exact files. No existing T-ID covers this entire milestone.
J — lessons and learning J1. Source-linked feedback distillation and quality fixtures (T15). J2. Approved-only lesson persistence and prompt injection (T15). J3. Lessons inbox controls and repository scope (T16). J4. Metrics, repeated-feedback flags and Learning screen (T17). Starts after F6, using F2's reject loop. J1 can run alongside I with injected storage. J2 shared wiring waits for I's storage ownership handoff; J3/J4 wait for the web owner. End-to-end reject → lesson → approval → injection is required.
K — merge-queue compatibility K1. Queued/removed/failed/merged adapter contract and fixtures. K2. Persisted lifecycle and retry guards. K3. Complete #24 acceptance: preserve the exact reviewed head, disable the action while queued, await confirmed MERGED or removal/failure, surface the terminal reason, and test enqueue success, delayed merge, queue removal, head replacement and retry. Enqueue success never completes the merge; a replaced head requires fresh review before retry. K1 can use a free slot after C4. K2/K3 wait for the runner/web owners to release their exact files; no concurrent edits to F/I or G/H/J integration files. Queue merging stayed disabled until K3 passed; K2 and K3 are complete (#46), and queue merging is enabled for an adapter that implements the K1 observation contract.

Complete T-ID mapping: T1 → D1–D2; T2 → D3; T3 → B0 verification then F3; T4 → B0 (consumed by C/F); T5 → B0 (consumed by C/F); T6 → C2's blocking subset then F5–F6; T7 → C3; T8 → cancelled, no implementation lane (fresh optional validation only in #19); T9 → F6 (common-CI integration and all-suite completion gate; complete 2026-10-19), D5 (Docker and adapter probes), C1/C3 (recorded GitHub outputs), E4 (recorded authoring outputs), F2 (hostile-issue eval), and each lane's applicable unit/browser suites; T10 → B0 (consumed by C/F); T11 → F4; T12 → C1 then F6 revalidation; T13 → B0; T14 → B0; T15 → J1–J2; T16 → J3; T17 → J4; T18 → E1–E4 then G1–G4. Shared requirements are complete only after all assigned slices meet the original acceptance criteria.

Default dispatch order: first C, D and E. As their prerequisites land, fill available slots with F, G and H; do not wait for unrelated lanes to finish. After F6, start I and J, retaining H if unfinished. K uses a free slot when its file dependencies permit. B0 is a short prerequisite inspection inside the relevant consuming task, not an extra concurrent implementation slot. Optional #19 and schema follow-ups #5/#7 are outside this default queue.

Wave 1: independent work now

Lane Scope and requirement mapping Owned files Start condition and completion check
C — guarded merge gate Build step 4 increment 1; parts of T6, T7, T12. Merged in PR #23 on 2026-09-24. github/, runner/merge.ts, merge tests; temporary integration ownership of shared review/UI files already changed by PR #23 Done (PR #23). Was: complete issue #21 acceptance, exact-head validation, and the review loop. Missing execution evidence continues to block merge.
D — agent isolation Build step 5 foundation; T1, T2 and the isolation portion of T9. Task clones, pinned container, vendor egress, phase permissions, cancellation and process settlement. New agents/ modules, a dedicated clone helper under git/, dedicated container/adapter tests and new .github/workflows/agent-isolation.yml only (explicit exception to common-CI ownership) Done: D1–D5 merged (#31, #40, #44, #47, #50). Real-Docker tests prove filesystem/network isolation and phase restrictions; controlled tests prove cancellation keeps ownership until the process terminates. No runner/store or existing question-provider rewiring in this lane.
E — planning logic Build step 6 preparation; remaining T18 authoring/import/suggestion requirements. Reuse existing schema/parser/store behavior; add missing prompt construction, response validation, and revision-bound suggestion orchestration. Dedicated new planning modules under core/, prompts/plan-author.md, planning fixtures and dedicated tests E1 (#30), E2 (#32) and E3 (#35) merged; E4 #45 open. Tests cover plan identity, revision and replay guards, hostile input, and invalid responses. Production agent invocation and UI Apply remain blocked until integration; fake-provider tests do not satisfy live adapter acceptance.

Before the first edit in D or E: record the assigned owner, branch, exact file list, done-when command, and interface contract in that lane's issue or PR. New module paths above are proposed ownership boundaries, not claims that those files exist. Compare the assignment against C's current diff. If a shared file is needed, request its integration owner to make the edit or queue it after that owner's PR lands.

Contracts between lanes

  • D exposes invocation input containing the task-clone identity, phase, approved argv, deadline and attempt ID. Results preserve exit status and the original timeout/cancellation reason. Cancellation requests and subprocess termination are separate events; the caller may not reuse a slot before termination. The interface must not grant arbitrary command execution to planning/questions. Before retry admission and again before publishing a result, F validates the current snapshot, plan revision, assignment and referenced code against the captured context; any mismatch disables retry and requires a new request. A locally active invocation blocks retry even if its persisted lease expired or the clock changed. Controlled regressions must change the assignment/snapshot before retry and exercise an expired lease while the original invocation still runs. At settlement, F must atomically compare the returned attempt ID and captured state version with the still-current persisted attempt before publishing any result; late results cannot overwrite a retry or newer state. D keeps the invocation tracked until termination even when that result is discarded. D/F completion requires a controlled old-attempt-after-retry regression asserting both durable state and visible status, as required by AGENTS.md “Async jobs and polling” and “Required race regressions.”
  • E takes a read-only provider abstraction and captures repository/task/plan identity plus revision and request ID with every suggestion. Persistence and Apply use the existing runner/store authority and compare-and-swap rules; E cannot create a second writer or bypass validation.
  • C accepts only trusted evidence bound to the reviewed base/head and current plan. D's process result alone is not approval evidence: the integration owner validates context and persists acceptance results before C consumes them.
  • Publish shared TypeScript contracts and representative fixtures in a small prerequisite change before another lane imports them. Until that change lands, lanes may use injected local test interfaces. Changes to an agreed contract require updating its consumers and contract tests before integration.

Wave 2: integrate after prerequisites land

Lane Prerequisites Scope / ownership Completion check
F — runner and pre-merge automation C and D merged; invocation contract available Build step 5 runner plus #22 / remaining build step 4; T3, T6, T11. Own runner/, rebase helpers and shared acceptance persistence during this wave. Preserve ledger attribution through rebase; recompute approval staleness; execute and persist head-bound checks; cover timeout, cancellation, shutdown and collaborator-push races; complete #22 acceptance.
G — planning screen Done: G1–G4 (#145; PRs #148, #150, #151, #152) Build step 6 UI and T18 integration. During this wave G owned the shared screen files web/public/index.html, app.js and style.css and the Plans browser tests, and released them after G4. web/server.ts is F's server contract; G3 changed it once (PR #151) (see docs/implementation/planning-screen.md). Done. Import, generation and Apply preserve user drafts and attachments and reject stale/replayed suggestions. G4 (PR #152) met the final condition: real D-backed invocation and integration with F/store, not fixtures alone.
H — issue prioritization Done: access contract and ranking policy (H1); retrieval/ranking (#39, #42); Issues screen (#55); author-bound trust, runner/publish guards, prompt comment evidence, and trust controls (#108, PR #139) Build step 8: issue retrieval, normalization, ranking, and trust enforcement with dedicated unit, integration, and browser tests. Done. Stable ranking has visible reasons and explicit unavailable/stale states; H4b persists trust, fails closed at runner and publishing boundaries, controls comment inclusion, records delivered comment evidence, and works in demo mode.

F, G and H ran together within these ownership boundaries. G and H are done; for the current state of each lane, see docs/architecture.md. If two lanes need an incompatible shared storage/API change, land that small prerequisite first; neither edits the other's files in parallel. Merge independent backend modules first, then their shared integration, and rerun checks on the combined head.

Wave 3: lifecycle features and learning

  • Queue, scheduling and recovery (build step 7): starts after F establishes persisted task lifecycle and shutdown ownership. One owner controls the runner/store changes and recovery regressions.
  • Lessons pipeline (build step 9; T15): can proceed alongside queue work after F's reject-loop and feedback-event contract lands. Own dedicated lesson modules and tests; inject storage/provider interfaces and queue shared schema or runner wiring behind the queue owner.
  • Lessons inbox and Learning screen (T16, T17): follow the lesson persistence/metrics contracts and G's release of shared UI ownership. Require a working reject-to-lesson-to-approved-prompt path before marking the learning milestone complete.
  • Merge queue support (#24): Done 2026-09-25 (#38, #46); queue merging is enabled only for an adapter that implements the K1 observation contract. Original plan: a separate compatibility follow-up. Its GitHub adapter/fixture work can use a free lane after C; runner/UI lifecycle integration waits for those files' owners. Queue-based merging stayed blocked until the queued, removed, failed and confirmed-merged states were implemented and tested, which #46 completed. Enqueue success is still not merge completion.
  • Optional human validation (#19): may run separately with fresh blinded packages; it is never a dependency for these lanes. Schema extensions #5 and #7 remain separate follow-ups unless a lane explicitly needs them; do not silently expand T18 or duplicate #6 alignment work.

Ownership and integration rules

  1. Each task uses its own branch/worktree from current remote main or a documented prerequisite branch. Record its issue, milestone, T-IDs, dependencies, owner and exact files in the PR. Delegated reviewers report findings; the implementation task's main agent owns its writes.
  2. One integration owner controls runner/store.ts, shared runner/review wiring, web/server.ts, web/cli.ts, web/public/app.js, web/public/index.html, web/public/style.css, shared browser fixtures, package manifests/lockfiles, schema registry and common CI configuration. C held this ownership first. In wave 2, lanes F, G and H each held parts of it; G released its shared screen files after G4 (#145). Before editing any of these files now, check open PRs, branches and worktrees, and name one integration owner for any overlap, as "Task resumption and ownership" in AGENTS.md requires. The wave 1 plan gave C common configuration, to hand to F before F1, and gave D exclusive ownership of the new .github/workflows/agent-isolation.yml, with D's changes to existing .github/workflows/ci.yml, package scripts or lockfiles routed through the common-configuration owner. C and D are done. Separate worktrees do not remove this constraint.
  3. Keep this plan under one documentation owner. Lane owners record detailed progress and review rounds in their own issues/PRs; the documentation owner updates milestone status after integration. Never check off a milestone because only one parallel increment landed.
  4. A blocked integration does not block disjoint modules or fixture work, but those tasks must report the missing production integration. No stub provider, skipped Docker test or mocked merge outcome counts as completed production behavior.
  5. Every lane runs its targeted acceptance checks and required regressions. After its final integration change, rerun typecheck, unit/integration tests and applicable browser/Docker checks against the exact pushed head. Complete automated review and the review-lesson audit before an authorized merge. Revalidate downstream work after prerequisite changes.
  6. Parallel development does not grant deployment or merge permission. Keep each merge subject to the existing approval and CI/review gates. Record newly discovered deferred work as issues before closing the implementing task.

Implementation Tasks

Built from this review's findings. Each task comes from a specific decision above. Run with Claude Code or Codex, and tick each one as you ship it. Effort ratios assumed: features about 30x, tests about 50x, architecture about 5x.

Status (checked against main on 2026-09-26; merge items updated 2026-10-21, lane B0). T1, T2, T4, T5, T10, T13 and T14 meet their Verify lines and are ticked, with evidence under each (T1, T2 and T14 re-checked 2026-09-26 after lane D merged). T9 was ticked on 2026-10-19 (checked against main that day), with evidence under it. T3, T7 and T11 were ticked on 2026-10-20 (checked against main at eafe2be), with evidence under each. T6 and T12 were ticked on 2026-10-20 (PR #183), with evidence under each. Lane F6 (common CI) added the workflows in docs/implementation/ci.md: test and real-docker run on every pull request with no path filter, and Live probes runs the live Claude probes nightly and by hand. The ruleset "main checks" requires test and real-docker on main, both passed on the combined head ba8294d, and a Live probes run passed with the CLAUDE_CODE_OAUTH_TOKEN secret. Ask calls the agents/ boundary from runner/question-container.ts; it has no host adapter. The planned files core/segments, core/choices and core/attribution were never created. That logic lives in core/linking.ts (segments and ledger attribution) and core/approvals.ts (approvals and duplicate-segment choices). The Files lines below now name the real files.

These T IDs are requirement identifiers, not the build-order numbers. Build step 4 (merge gate and merging) spans T3, T6, T7, T11 and T12; it is unrelated to the numbering of T4. See “Build step 4: scope and progress” for its increments and remaining criteria. An increment must not mark a broader requirement complete while any of its acceptance criteria remain deferred.

  • T1 (P1, human: ~3 days / CC: ~1 hour) — agents — Build the pinned agent container that mounts only /work (with its own .git) and the agent's sign-in

    • Surfaced by: R1 (D2: B), O6 (D16: A)
    • Files: agents/container/, git/clone
    • Verify: real-Docker test shows only /work and sign-in; writing to /, /usr/bin, or the image's tools fails; /tmp and HOME are empty in each new container; the process is not root and has no capabilities; the start-up self-test refuses a container missing any lock-down setting; git status works inside; the main repo path is absent; changing a task-clone object in disposable repos leaves the source object unchanged
    • Evidence: test/agent-container.test.ts ("runs read-only with no root capabilities, host paths, inherited secrets, or writable tools", "refuses a container missing read-only root before its command runs", "keeps Git metadata read-only, on another filesystem, and mounted against replacement"); test/agent-clone.test.ts ("copies objects, ignores dirty source changes, and has no origin or shared metadata"); lane D5 gate, docs/implementation/agent-isolation.md
  • T2 (P1, human: ~1 day / CC: ~30 min) — agents — Add the vendor-only egress proxy and turn off web and MCP tools

    • Surfaced by: R2 (D3: A)
    • Files: agents/network/, agents/claude, agents/codex
    • Verify: from inside the container, the vendor host is reachable and another host is blocked
    • Evidence: test/agent-network.test.ts ("reaches the vendor through the proxy while blocking other and direct hosts"); test/agent-policy.test.ts ("builds Claude and Codex controls with web, MCP and direct shell disabled"); lane D5 gate, PR #50
  • T3 (P1, human: ~4 hours / CC: ~20 min) — runner — Keep the commit ledger and rebase mappings; attribute only ledger commits

    • Surfaced by: O5 (D15: A)
    • Files: runner/store, git/rebase, core/linking.ts (attribution; planned as core/attribution)
    • Verify: a forged trailer lands in Unplanned; rebased ledger commits keep their owner
    • Evidence (2026-10-20): test/history.test.ts ("splits a shared hunk by ledger owner; detects out-of-scope and forged trailers"); test/store.test.ts ("preserves owned, foreign, and conflict-resolution provenance through repeated rebase mappings and restart", "feeds persisted remapped ownership into the linking engine on real Git history"); test/runner-rebase.test.ts ("replays a complete linear history one-for-one and retains only its immutable result ref")
  • T4 (P1, human: ~4 hours / CC: ~20 min) — core — Bind approvals to the item fingerprint and function context; spread staleness to dependents

    • Surfaced by: O2 (D12: A)
    • Files: core/approvals.ts
    • Verify: an acceptance-only edit goes stale; moved lines go stale; a line shift stays fresh; dependents go stale
    • Evidence: test/history.test.ts ("keeps approvals after a clean rebase … stales changed checks and dependents", "stales whitespace and function-context changes, but not line numbers")
  • T5 (P1, human: ~1 day / CC: ~30 min) — core — Add file-change segments for binary, mode, empty, rename, symlink, and submodule changes

    • Surfaced by: O7 (D17: A)
    • Files: core/linking.ts (planned as core/segments), web/public
    • Verify: one test case per kind lands in the right row and blocks merge until approved
    • Evidence: test/history.test.ts ("represents binary, executable, empty, rename, symlink and submodule changes", "records typed object identities on real mode-change cards"); unapproved items block the merge gate (test/merge.test.ts, "lists every local review blocker before merge")
  • T6 (P1, human: ~3 hours / CC: ~15 min) — runner — Re-run cmd: checks after a pre-merge rebase; tie results to the head

    • Surfaced by: O3 (D13: A)
    • Files: runner/merge
    • Verify: a rebase onto a breaking main blocks the merge; a head-only collaborator push recomputes review and reruns checks; matching SHAs still refresh both rule sources
    • Evidence (2026-10-20): a rebase onto a breaking main blocks the merge (test/pre-merge.test.ts, "fails the job when the moved base itself breaks the command check on the rewritten head": the check fails only on a head holding the base's new file, so it would pass on the reviewed head; also "blocks when a command check fails on the rewritten head" and "fails the job when a command check breaks on the rewritten head", where the failure is injected). A head-only collaborator push stops the job for review ("stops the job for review when a collaborator pushed to the pull request"). In "reruns command checks on a collaborator head after review when the base did not move", a first job passes the cmd: check on the rewritten head and GitHub refuses the merge; a collaborator then pushes on top of it, with the base unchanged. The next job recomputes the review for the new head (its lines are Unplanned and P1 is no longer approved). After the person attributes and approves them, the job after that runs the check again on the new head, rather than reusing the earlier pass, and merges or fails on its result. The checks rerun on the next job, after the person reviews the new head (docs/implementation/merge-handoff.md, Outcomes: review-required, "review the refreshed pull request, then merge again"), not automatically on the push. Matching SHAs: a fresh inspection reads both rule sources again (test/merge.test.ts, "reads both rule sources again on a fresh inspection when base and head are unchanged"), and the guarded merge reads them fresh even after a cached ready status ("refuses a guarded merge when the %s adds a failing required check after a cached ready status", for a ruleset and for classic protection). The merge job's required-check wait and its guarded merge read both rule sources again at every inspection too (test/merge-recorded.test.ts, "waits while the recorded checks are pending, then merges once they pass"). The collaborator push and GitHub are simulated
  • T7 (P1, human: ~2 hours / CC: ~10 min) — github — Merge with --match-head-commit and reload on refusal

    • Surfaced by: O4 (D14: A)
    • Files: github/merge
    • Verify: a head or base push between validation and merge is refused or revalidated by the server-side guarded merge; a backend without atomic base protection blocks automatic merge, including with zero required checks
    • Evidence (2026-10-20): test/merge.test.ts ("refuses a base or head race after the initial validation" for the head, "parses required checks from both rule sources and pins the gh merge head", "blocks the %s remote condition" row base-guard with zero required checks, "does not treat empty strict check policies as an atomic base guard"); test/merge-job.test.ts ("ends failed, leaving the task in review, when GitHub refuses because the head changed", "words the guarded merge's refusal as what merging does when the base moves after the job's last ready inspection", "decides a retried job only from its own merge attempt, never from an earlier refused one"); test/pre-merge.test.ts ("stops a retry for review when its preparation rebases after GitHub refused the merge"). GitHub's refusal of a changed head or a moved base is simulated
  • T8 (P1, historical estimate: human ~2 days / CC ~30 min) — process — Cancelled before timed results; optional future validation moved to #19

    • Surfaced by: R3 (D4: A), O5, O9 (D19: A)
    • Files: scripts/plant.ts, docs/experiments/review-protocol.md
    • Outcome: no experimental result or product claim; future work must start with a fresh protocol and fresh blinded packages
  • T9 (P1, human: ~2 weeks / CC: ~3 hours) — tests — Set up Vitest, real git, recorded gh and CLI outputs, the real-Docker CI suite, Playwright, and the hostile-issue eval

    • Surfaced by: T1 (D10: A)
    • Files: test/, .github/workflows/
    • Verify: CI runs every suite; the Docker suite fails if isolation breaks, a read-only phase can write /work, planning/questions can execute a process, or task/scratch byte and inode caps can be exceeded; hard-link and alias-write attempts from .git/config and objects into /work or scratch, and mountpoint replacement, must fail with metadata unchanged; both vendor startup probes must read the container schema and return bounded valid output through their documented file/stdout channel. Changed 2026-10-01 (#93): Codex is refused in every phase, because it cannot read files without its shell. Until #93 is revisited, only the Claude startup probes run, and tests confirm that every Codex phase is refused before anything is allocated
    • Evidence (2026-10-19): on the combined head ba8294d on main (F6c, PR #177), CI test passed (run 39115311602) and Agent isolation real-docker passed (run 39115311588); the active repository ruleset "main checks" requires test and real-docker on main (not live-probes, by design); a live-probes run started by hand on main at ba8294d passed all 4 live Claude probes (run 39206371497) with the CLAUDE_CODE_OAUTH_TOKEN secret, and nightly runs start at 06:23 UTC. Recorded Claude planning fixtures replay in test; recording them again is a manual step. The startup probes are Claude-only under the #93 change above. Details: docs/implementation/ci.md ("T9 status")
  • T10 (P2, human: ~2 hours / CC: ~10 min) — core — Duplicate-segment key: file, content, copy number, and copy count

    • Surfaced by: R4 (D5: A), O1 (D11: A)
    • Files: core/approvals.ts choiceKeys (planned as core/choices)
    • Verify: accepting copy 1 and then deleting it leaves the other copy undecided
    • Evidence: test/history.test.ts ("assignments stale the target and duplicate-copy count changes invalidate choices")
  • T11 (P2, human: ~3 hours / CC: ~15 min) — git — Resolve conflicts on foreign commits with an agent; keep the lines Unplanned

    • Surfaced by: R5 (D6: B)
    • Files: git/rebase, agents
    • Verify: conflict on a pushed commit is resolved, lines labeled "conflict resolved by agent"
    • Evidence (2026-10-20): test/runner-rebase.test.ts ("routes a missing-ledger foreign conflict to the resolver and preserves its author and provenance"); test/runner-rebase-conflict.test.ts ("allocates from the clean clone before importing the conflict snapshot, then copies back only the audited path"); test/history.test.ts ("keeps a resolved foreign conflict Unplanned and carries its visible provenance"); test/browser/review.spec.ts ("labels a resolved foreign conflict as Unplanned agent-resolved work"). Each step is tested on its own, with a fake resolver, fake container dependencies or a ledger entry written by the test; no test runs a real agent through a whole conflict
  • T12 (P2, human: ~2 hours / CC: ~10 min) — github — Read required checks from branch rules; zero checks passes; ignore reviews

    • Surfaced by: R6 (D7: A)
    • Files: github/checks
    • Verify: recorded-output tests for zero checks, pending then passing, and timeout
    • Evidence (2026-10-20): test/merge-recorded.test.ts replays GitHub's real answers, recorded with gh 2.102.0 from this repository by scripts/record-merge-gh.ts (test/fixtures/gh/). Zero checks: pull request 104, into a branch no rule covers, reads as an empty required set with the rules known. Pending then passing: pull request 183 at one head, read while test and real-docker ran and after they passed. Through the merge job, the wait sees both checks pending, then merges once they pass; at the time limit with the checks still pending, the job ends blocked. For the job, the recorded ruleset is changed in one field, its strict policy, because the repository's ruleset is not strict, so a job against it stops at once for the missing atomic base guard (T7), which is also tested ("ends the job for a person, before waiting, against the repository's real non-strict ruleset"). Zero checks pass a job only with an atomic base guard, and with no required checks only a merge queue gives one (a strict policy guards only a non-empty set). That job case is tested with injected states: a merge queue and no required checks (test/merge-job.test.ts, "ends queued when the merge queue accepted the head"). The recordings found two bugs, fixed in PR #183: a ruleset check with no integration_id and a ruleset-only branch's 404 "Branch not protected" both made the rules unknown, so a branch whose required checks come only from a ruleset (this repository's main among them) blocked merging. The 404 was recorded with a token with admin rights; a token without them may get "Not Found" instead, which still blocks merging as unknown rules. Reviews are not checks: required approving reviews in a ruleset or classic protection are ignored, and only their required checks count (test/merge.test.ts, "ignores required reviews in both rule sources and reads only their required checks"). #176 stays open and is tracked under build step 4, not here: a required check pinned to an app always reads as missing, which fails closed (the job blocks at its time limit) rather than merging without the check (test/merge.test.ts, "reads a requirement pinned to an app as missing against gh's app-less check runs", a test the #176 fix removed; a missing check blocks the job at its time limit: test/merge-job.test.ts, "ends approved, merge blocked when required checks do not pass in time"). The PR #183 recordings have no app-pinned check. Later: a token without admin rights does get "Not Found", on ruleset-only and classic-protected branches alike; the rules are now read for it, with classic checks from the branch read, replayed from recordings of vitejs/vite, cli/cli and sveltejs/svelte (guarded-merge.md). The vite and svelte recordings have app-pinned checks, which read as missing (#176). Later (#176): for a check pinned to an app, the inspection now asks GitHub, through gh api graphql, for that app's runs of that name on the head, since gh's rollup names no app; the vite and svelte recordings were made again with that read, and their pinned checks read as passing, svelte's from a private app (test/merge-recorded.test.ts; test/merge.test.ts, "reads a required check pinned to an app from that app's run on the head, which %s", which replaces the removed test).
  • T13 (P2, human: ~1 hour / CC: ~5 min) — runner — Use node:sqlite only; enforce the minimum Node version; add a CI warning check

    • Surfaced by: R7 (D8: A)
    • Files: runner/store, web/cli
    • Verify: CI fails if node:sqlite prints a warning; old Node gets an upgrade message
    • Evidence: runner/store.ts requireSupportedNode (Node 26.7.0 or later, also engines in package.json); test/store.test.ts ("rejects unsupported Node versions and opens SQLite without warnings") runs in .github/workflows/ci.yml
  • T14 (P3, human: ~1 hour / CC: ~5 min) — layout — Create the 6 modules; runner/store is the only writer; web/cli is the entry; build step 2 is read-only

    • Surfaced by: D1 (B), R8 (D9: A), O8 (D18: A)
    • Files: package layout
    • Verify: no module other than runner writes task state
    • Evidence (2026-09-26): all 6 modules exist (agents added by lane D); only runner/store.ts writes task state; web/cli.ts is the entry.
  • T15 (P2, human: ~1 week / CC: ~1 hour) — runner, agents — Distill closed-task feedback into lessons linked to their source; inject approved lessons into prompts

    • Surfaced by: L1 (D21: A)
    • Files: runner/lessons, agents/prompts
    • Verify: a rejection note produces a lesson with a source link; only your feedback is read; the eval checks lesson quality
  • T16 (P2, human: ~1 day / CC: ~20 min) — web — Lessons inbox: approve, edit, discard, turn off, delete; scope per repo with "all my repos"

    • Surfaced by: L2 (D22: A), L3 (D23: A)
    • Files: web/lessons, runner/store
    • Verify: unapproved or turned-off lessons never reach a prompt; repo-scoped lessons stay in their repo
  • T17 (P3, human: ~2 days / CC: ~30 min) — web, runner — Learning screen: rejections and review rounds per task, repeated feedback, flags on weak lessons

    • Surfaced by: L4 (D24: A)
    • Files: web/learning, runner/metrics
    • Verify: repeated feedback matching an approved lesson raises its count and flags it
  • T18 (P2, human: ~2 days / CC: ~45 min) — core, agents, web — Plan schema: draft plans with the supported planning agent, import YAML or JSON, apply typed suggestions

    • Surfaced by: P1 (approved 2026-09-22)
    • Files: schema/, docs/plan-format.md, prompts/plan-author.md, core/plan (schema and meaning checks), agents/claude, agents/codex, web/plans (Import plan, suggestion cards)
    • Verify: both examples pass and 8 broken plans fail; JSON-compatible YAML parsing is deterministic and rejects duplicate decoded keys, anchors/aliases, merge keys, tags, non-JSON scalars, excessive depth/size, and extra documents before validation; recorded Claude answers pass, while every Codex planning request is refused before Docker or Git work under the later #75/#93 decision; an imported plan for #412 is rejected when the selected task is #413 without silently changing either issue; a declared final symlink can be deleted or safely retargeted while symlink parents and escaping targets are rejected; writes through declared links to undeclared files, directory children, or dangling targets fail the target snapshot audit before out-of-scope classification, tests, or commit; a plan with a .. path or a dependency loop cannot be approved; the edit schema's copied definitions match; dependent add → edit and rename → edit plans pass projected-state validation, while missing sources and occupied destinations fail; a new field requires a new schema version and old plans validate against the immutable registry-selected snapshot before conversion; registry paths exist, snapshot IDs are version-qualified and unique, and unversioned CLI schemas exactly match the current snapshots; directory/root declarations and children beneath a file or submodule are rejected; malformed edit payloads and invalid resulting plans cannot be applied; a delayed suggestion captured for plan A at revision 3 with P1 cannot apply to plan B with the same revision/item IDs, and B remains unchanged; applying one card increments the revision and disables all old sibling cards until the person refreshes and reviews regenerated suggestions; concurrent/replayed Apply cannot create duplicate mutations; command chains and delimiter-escape payloads are rejected or remain data; appended flags such as go test -exec do not match a shorter allowlist entry and cannot execute; hostile filenames, branch names, script-derived argv values, approved lessons, and revision feedback remain escaped JSON data in the authoring prompt and cannot break its delimiters
    • Evidence (2026-10-08): E1–E4 cover schema, parsing, prompt/response validation, recorded Claude output and Store orchestration; G1–G3 cover browser import, rendering, lifecycle and revision-bound Apply; G4's plans-production.spec.ts composes production issue description, lane D's provider boundary, F's HTTP endpoints and Store persistence through browser Apply, server restart and independent SQLite reopen. planning-provider.test.ts, planning-production.test.ts and planning-recorded.test.ts pass on the G4 head, and exact-head agent-planning.test.ts passes the real-Docker vendor-egress and cleanup gate.

Unresolved decisions

None in this review.

Completion summary

  • Step 0, Scope Challenge: scope accepted as-is (6-module layout, D1)
  • Architecture review: 4 issues found (3 decided; 1 informational)
  • Code quality review: 5 issues found (all decided)
  • Test review: diagram produced; 40 planned paths without tests, covered by the approved test plan (T1)
  • Performance review: 0 issues found
  • NOT in scope: written
  • What already exists: written
  • TODOS.md updates: 0 items proposed
  • Failure modes: 0 critical gaps flagged
  • New requirement during review: learning from your feedback, decided in 4 parts (L1 to L4)
  • Unresolved decisions: 0 in this review
  • Outside voice: Codex, completed, 8 findings (split into 9 decisions, all resolved)
  • Historical parallelization plan: 4 lanes, originally split around the go/no-go check; the cancelled experiment no longer divides or blocks roadmap work
  • Lake score: 12/20
  • Suppressed findings (appendix): none

Design review (2026-09-22)

Who this is for. The builder of the codeboost screens. What it is for. It records the design decisions made before build step 2. The rules themselves are in "Screen specifications (design review)" above. Plain language per ISO 24495-1:2023.

Numbering. D12 to D28 here are design-review questions, not the engineering review's D numbers.

Scope. Review screen, file-change cards, merge-gate header, Lessons inbox, and Learning screen. No DESIGN.md existed. Outside voices: Codex (completed, 12 findings) and a Claude subagent (completed, 12 findings). Both found no hard rejections. Both failed "scannable by headlines" and "one job per section".

Decisions made

# Decision Answer
D12 Approve one item from a button by the code, with progress 1A
D13 One shared menu from the plan; Lessons tabs 2A
D14 Compact plan-item rows and a pinned warnings strip 3A
D15 State table for every screen and waiting task state 4A
D16 Merge shows a step list with named failures 5A
D17 Stale items state their reason, with a "Since approval / Full change" switch 6A
D18 Learning: metric definitions, 5-task minimum, task-number axis, 3-repeat flag rule 7A
D19 Separate "Ask" and "Request change" tabs; pending changes block merging 8A
D20 Blockers link to their fixes. Amended 2026-09-24: no "Merge anyway"; to override, merge on GitHub (matches docs/implementation/guarded-merge.md) 9A, amended
D21 "Correct" renamed to "Tests" and "AI review" 10A
D22 Run /design-consultation to create DESIGN.md before build step 2 11A
D23 Status uses icon, word, and color, with 4.5:1 contrast and screen-reader labels 12A
D24 One keyboard map; "Change n of m"; no shortcuts while typing 13A
D25 Desktop only from 1280px, with collapsing panes 14A
D26 Ambiguous row always shown; "Assign to…" and "Accept as is" with a stale warning 15A
D27 File-change evidence card 16A
D28 Lessons inbox: bulk Discard only, strict selection rules 17B

Also applied without a new decision: the Learning screen's scope labels follow L3 ("This repo / All my repos").

Scores

Pass Before After What remains
1. Information architecture 4 8 Product identity only in the menu
2. States 2 9 —
3. Journey 5 9 —
4. AI slop and labels 6 9 —
5. Design system 1 8 DESIGN.md created (D22); implementation QA remains
6. Window sizes and accessibility 2 9 —
7. Unresolved decisions — 3 resolved, 0 deferred —

Overall (the lowest pass): 1 → 8. D22 is complete: DESIGN.md defines the required tokens. This is a specification score; UI implementation QA remains.

Not in scope

  • Phone and tablet layouts. codeboost is a desktop tool (D25).
  • Queue, Plans, Issues, and Settings screens. Not reviewed here. The Plans screen (build step 6) and the Issues screen (build step 8) were built without this review; review the Queue screen and the full Settings screen (today a question-agent dialog) before they are built.
  • Motion design. None is needed for this tool.

What already exists

When this review ran, no UI code existed. Since then the review screen has been built in web/public/ (build step 2 and build step 4, increment 1). The written rules above still win over any mockup or over the current code.

TODOS.md updates

None proposed. Every fix is in the plan and in the tasks below.

Approved Mockups

Screen Mockup path Direction Notes
Review screen /Users/maxhwang/.gstack/projects/codeboost/designs/updated-after-design-review-20260922/review-screen.png Three panes: compact plan-item list, code with Approve button, and Ask / Request change conversation Highlight the current page, not Settings (D13). Earlier reference: mockup-20260922/variant-B.png
Lessons inbox /Users/maxhwang/.gstack/projects/codeboost/designs/updated-after-design-review-20260922/lessons-inbox.png Compact sortable, filterable table; rows expand in place; bulk Discard only Earlier pick: lessons-inbox-20260922/r5/variant-B.png. Menu highlight follows D13
Learning screen /Users/maxhwang/.gstack/projects/codeboost/designs/updated-after-design-review-20260922/learning-screen.png Three tiles, task-number chart, flagged-lessons table Key strip must follow D24 (there is no "Dashboard"). Menu highlight follows D13
Issues /Users/maxhwang/.gstack/projects/codeboost/designs/issues-screen-20260922/variant-A.png Triage table: score and word, rows expand to "Why it ranks", untrusted issue text, trust step for outside authors Approved 2026-09-22 (/design-shotgun). HTML: issues-screen-20260922/finalized.html
Plans (plan editor) /Users/maxhwang/.gstack/projects/codeboost/designs/plans-screen-20260922/variant-C.png Plan table with rows that expand to edit; plan assistant in a bottom drawer Approved 2026-09-22. Fields follow P1's schema. HTML: plans-screen-20260922/finalized.html
Queue /Users/maxhwang/.gstack/projects/codeboost/designs/queue-screen-20260922/variant-A.png Run-state bar, "Waiting for you" rows with one action each, reorderable "Up next" table Approved 2026-09-22, without the mockup's duplicate left list. HTML: queue-screen-20260922/finalized.html
Settings /Users/maxhwang/.gstack/projects/codeboost/designs/settings-screen-20260922/variant-C.png Health checklist first, then grouped settings Approved 2026-09-22. Values come from this document, not the mockup. HTML: settings-screen-20260922/finalized.html

Design Implementation Tasks

Built from this review's decisions. Tick each one as you ship it.

Status (checked against main on 2026-09-26; Plans entries updated after G4, PR #152). Only DT1 is complete. Most DTs are partly built. Do not tick one until its Verify line passes.

  • Built: two-tab composer and "n pending changes" tags (part of DT4); the notice below 1280px (part of DT13); the ? shortcut help (part of DT12); a blocker list from the guarded merge gate (part of DT7).

  • Missing: "Send N change requests" and the reject flow (DT4, needs build step 5's reject loop); the merge blocker list with links (DT7); D16's named failure banners that jump to the first affected item, and its current step on the Queue screen's task row (the step list and Cancel of D16 are built; the rest of D16 and DT7 is #199); menu links for Queue, Lessons and Learning, which are plain text until their screens exist (DT8, build steps 7 to 9; Issues became a link in #55 and Plans in G1, #148); the approved Plans mockup's expandable row editing (not built, #155) and bottom-drawer plan assistant (the built screen puts the assistant in a side panel); Lessons inbox and Learning screen (DT14, DT15, build step 9).

  • Not yet audited against their Verify lines: DT2, DT3, DT5, DT6, DT9, DT10, DT11.

  • File paths in the DTs (web/review, web/shell and others) are proposed names. Today all UI code is in web/public/.

  • DT1 (P1, human: ~1 day / CC: ~30 min) — design system — Create DESIGN.md with /design-consultation before build step 2

    • Surfaced by: D22 · Files: DESIGN.md · Verify: every screen's colors and fonts come from its tokens
  • DT2 (P1, human: ~1 day / CC: ~30 min) — review screen — Approve button by the code, progress count, state-only row circles

    • Surfaced by: D12 · Files: web/review · Verify: approving P1 changes only P1; the header shows "n of m approved"
  • DT3 (P1, human: ~2 days / CC: ~45 min) — all screens — Build the loading, empty, error, success, and partial states, plus the waiting-state banners

    • Surfaced by: D15, D18 · Files: web/* · Verify: Playwright case for each table row
  • DT4 (P1, human: ~1 day / CC: ~20 min) — review screen — Two-tab composer; pending-change tags; "Send N change requests" summary

    • Surfaced by: D19 · Files: web/review/composer · Verify: an Ask creates no revision; a pending request blocks merge
  • DT5 (P1, human: ~1 day / CC: ~20 min) — review screen — Stale reason text and "Since approval / Full change" switch

    • Surfaced by: D17 · Files: web/review · Verify: each of the 4 stale reasons shows its own text and before/after
  • DT6 (P1, human: ~1 day / CC: ~20 min) — all screens — Status as icon, word, and color; 4.5:1 contrast; screen-reader labels

    • Surfaced by: D21, D23 · Files: web/components/status · Verify: an automated contrast check; a screen reader reads each status
  • DT7 (P2, human: ~1 day / CC: ~20 min) — merge header — Blocker button and list with links; merge step list (no "Merge anyway…", D20 amended)

    • Surfaced by: D16, D20 (build step 4) · Files: web/public · Verify: each blocker link lands on its fix; no control merges while a blocker remains
  • DT8 (P2, human: ~4 hours / CC: ~15 min) — shell — One shared menu and Lessons tabs; remove undefined pages

    • Surfaced by: D13 · Files: web/shell · Verify: the same menu on every screen, with the current page highlighted
  • DT9 (P2, human: ~4 hours / CC: ~15 min) — review screen — Compact rows and the pinned warnings strip

    • Surfaced by: D14 · Files: web/review/list · Verify: the strip counts match the Ambiguous and Unplanned rows
  • DT10 (P2, human: ~4 hours / CC: ~15 min) — review screen — Ambiguous row; Assign to… and Accept as is; stale warning

    • Surfaced by: D26 · Files: web/review · Verify: assigning to P2 warns first, then makes P2 stale
  • DT11 (P2, human: ~4 hours / CC: ~15 min) — review screen — File-change evidence card

    • Surfaced by: D27 · Files: web/review/file-card · Verify: one card per change kind, counted in "Change n of m"
  • DT12 (P2, human: ~4 hours / CC: ~15 min) — all screens — One keyboard map; no shortcuts while typing; Tab order and focus rings

    • Surfaced by: D24 · Files: web/keys · Verify: pressing a inside the composer types the letter and approves nothing
  • DT13 (P2, human: ~4 hours / CC: ~15 min) — shell — Desktop layout from 1280px; resizable, collapsible panes; narrow-window notice

    • Surfaced by: D25 · Files: web/shell · Verify: Playwright runs at 1280px and 1440px
  • DT14 (P2, human: ~4 hours / CC: ~15 min) — Lessons inbox — Bulk Discard only; selection rules

    • Surfaced by: D28 · Files: web/lessons · Verify: changing a filter clears the selection; no bulk approve exists
  • DT15 (P3, human: ~4 hours / CC: ~15 min) — Learning screen — Metric info tips, 5-task minimum, task-number axis, direct line labels, flag rule

    • Surfaced by: D18 · Files: web/learning · Verify: with 4 tasks, the tiles show "Not enough tasks yet"

Unresolved decisions

None from this design review.

GSTACK REVIEW REPORT

Review Trigger Why Runs Status Findings
CEO Review /plan-ceo-review Scope & strategy 0 — —
Outside Review Codex (eng outside voice; design outside voice) Independent 2nd opinion 2 completed Eng: 8 findings, all resolved. Design: 12 findings, merged into D12 to D28
Eng Review /plan-eng-review Architecture & tests (required) 2 ISSUES OPEN (PLAN) 10 issues, 0 critical gaps; all decided; learning added (L1 to L4)
Design Review /plan-design-review UI/UX gaps 1 ISSUES OPEN (FULL) score: 1/10 → 8/10 after D22, 17 decisions
DX Review /plan-devex-review Developer experience gaps 0 — —
  • OUTSIDE COVERAGE: Codex plan-review phase, completed on 5036e0f, 8 findings, all resolved. Codex design phase, completed on 5036e0f, 12 findings. A Claude subagent (in-host, design phase) completed with 12 findings. Both design voices found no hard rejections. The learning requirement (L1 to L4) has not had an outside review.
  • CROSS-MODEL: In the design phase, Codex and the Claude subagent agreed on 9 of their top findings: per-item approve, stale reasons, the composer modes, merge blockers, inconsistent menus, scope labels, file-change evidence, keyboard wording, and missing tokens. Only the subagent raised the merge step list and the thin-data rule. Only Codex raised the "Correct" label.
  • VERDICT: No review is CLEAR yet. Eng review: every decision is made and mapped to tasks. Design review: 8/10 after DESIGN.md was added (D22); UI implementation QA remains. eng review required.

NO UNRESOLVED DECISIONS