diff --git a/docs/architecture.md b/docs/architecture.md index e9c90d2e..36ad852e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # codeboost architecture: a high-level overview -Status: current as of `main` at `aafd153` (2026-10-01). Open work is listed in **Build status and roadmap**. +Status: current as of `main` at `7edf36d` (2026-10-04). Open work is listed in **Build status and roadmap**. Writing standard: plain language, ISO 24495-1:2023 ## About this document @@ -40,9 +40,10 @@ Writing standard: plain language, ISO 24495-1:2023 - **The central idea.** A runner-owned **commit ledger** records which plan item each commit belongs to. The linking engine uses the ledger, not commit messages, to put every changed line on a plan item's row. Anything the ledger cannot explain goes to the Unplanned or Ambiguous row. - **The central safety rule.** Everything that comes from outside is untrusted: issue text, agent output, the browser, and the repository's own files. Only the runner decides. Agents never see your credentials, your other files, or GitHub. - **Build state.** Three levels: - - **In use:** plan and linking library, SQLite store, review screen, Ask (questions to an agent), guarded merge with merge-queue support, ranked Issues screen, agent isolation boundary, and the single-runner lock. - - **Built and tested, not yet connected:** the runner coordinator and `/api/runner`, the planning API, startup recovery, per-item execution with the post-run audit, the already-fixed check, and opening the pull request. They wait for the runner's commit in lane D (#66 part 2, PR #90) and the workspace follow-ups (#87). - - **Not built:** rebasing, running `cmd:` checks, review rounds, continuing after a scope pause (#88), and the Planning, Queue and Learning screens. + - **In use:** plan and linking library, SQLite store, review screen, Ask (questions to a Claude agent), guarded merge with merge-queue support, ranked Issues screen, agent isolation boundary, and the single-runner lock. + - **In use for a non-demo review with a `github` block:** planning. `/api/plan/suggestions` and `/api/plan/drafts` ask Claude, through lane D, for suggestion cards or a whole next plan revision (#117, #124). Nothing becomes a revision until you apply it. + - **In use with an opt-in `runner` block in `review.json`:** the whole loop after planning. `start` and `resume` on `/api/runner` run a task's plan item by item with a Claude agent (#91). When a run ends, codeboost publishes the task's pull request, a draft if the task needs a person (#103). Approve & merge merges that pull request (#121). Cancelling a task closes its pull requests (#111). These are API actions; the screen has no buttons for them yet. + - **Not built:** the "trust this issue" action and its runner guard (#108), screens for planning and the runner actions, rebasing, running `cmd:` checks, review rounds, continuing after a scope pause (#88), and the Planning, Queue and Learning screens. ## Terms used @@ -112,11 +113,12 @@ flowchart TB end subgraph runner ["runner/ — trusted coordinator"] review[review.ts
ReviewService] - questions[questions.ts + question-*.ts
Ask] + questions[questions.ts + question-*.ts
Ask; shared read-only runner] + planningsvc[planning.ts
planning agent] merge[merge.ts
merge coordinator] coord[coordinator.ts + lifecycle.ts
attempts, slots, shutdown] - exec[execution.ts
per-item execution] - publish[publish.ts
open the pull request] + exec[execution.ts, workspace.ts,
runner-repository.ts
per-item execution] + publish[publish.ts, publishing.ts,
branch-push.ts
publish the pull request] recov[recovery.ts
lock, startup recovery] store[store.ts
only SQL writer] end @@ -155,31 +157,34 @@ Dependencies point downward only. `core/` imports nothing that does input or out ### What each part owns -"In use" means production code runs it. "Not connected" means it is merged and tested, but only tests construct it so far. +"In use" means production code runs it. "In use with the `runner` block" means production runs it only when `review.json` has the opt-in `runner` block. | Part | Main files | Owns | State | |---|---|---|---| | Command line | `web/cli.ts` | Parses `--demo` or `--config`, takes the single-runner lock, starts the server, releases the lock on Ctrl+C. | In use | | HTTP server | `web/server.ts` | Binds `127.0.0.1` only. Checks the token, Host and Origin. Bounded JSON bodies. Routes `/api/review`, `/api/action`, `/api/questions`, `/api/merge`, `/api/issues`, `/api/settings`, plus `/api/runner` and `/api/plan/*` when a runner or planning provider is supplied. Ordered shutdown. | In use; `/api/plan/suggestions` and `/api/plan/drafts` run Claude through lane D for a review with a `github` block (#117, #124) | -| Browser screen | `web/public/*` | Review screen and Issues screen. Plain JavaScript with IBM Plex fonts served locally. Sends item and segment IDs and a state token, never fingerprints or ownership. | Yes | -| Review service | `runner/review.ts` | Builds the review view: reads history, links it to the plan, computes approval states and merge blockers. Applies review commands through the store. | Yes | -| Ask | `runner/questions.ts`, `runner/question-*.ts` | Answers a question about one plan item with a read-only agent. Runs lane D's synchronous setup in a worker thread so the server stays responsive. Tracks leftover containers. | Yes | -| Merge coordinator | `runner/merge.ts` | Runs the full merge gate twice, re-reads the local generation, then merges the exact reviewed head. Tracks merge-queue attempts. | Yes | -| Runner coordinator | `runner/coordinator.ts`, `runner/lifecycle.ts` | Attempt admission, concurrency slots, compare-and-swap on results, retries, shutdown order. | Not connected | -| Execution | `runner/execution.ts` | Runs plan items in order: fresh workspace, prompt, agent, post-run audit, then the runner's own commit and ledger entry. Pauses in needs amendment on an out-of-scope edit; moves to needs human on a safety violation. | Not connected; uses a test workspace until #66 part 2 and #87 | -| Publishing | `runner/publish.ts`, `runner/publishing.ts`, `runner/branch-push.ts` | Runs the already-fixed check, pushes the task head, then opens or reuses the task's pull request (a draft when the task needs a person). Records each opening before calling GitHub, so a lost outcome can be found again by a marker. `TaskPublishing` (#103) publishes when a run ends, on the `publish` runner action, and once at startup, and records the last outcome. On cancel it closes the task's PRs (#111). | With a runner block (needs `github.baseBranch`); never in a demo | -| Lock and startup recovery | `runner/recovery.ts` | One runner per database, held as an OS lock on the database file's device and inode. Startup recovery finalizes interrupted attempts and removes leftover containers and storage. | Lock in use; recovery not connected | +| Browser screen | `web/public/*` | Review screen and Issues screen. Plain JavaScript with IBM Plex fonts served locally. Sends item and segment IDs and a state token, never fingerprints or ownership. | In use | +| Review service | `runner/review.ts` | Builds the review view: reads history, links it to the plan, computes approval states and merge blockers. Applies review commands through the store. | In use | +| Ask | `runner/questions.ts`, `runner/question-*.ts` | Answers a question about one plan item with a read-only Claude agent (Codex is refused in every phase, #93). Runs lane D's setup in a worker thread so the server stays responsive. Ask and planning share one read-only container runner (`runReadOnlyAgent`, #117) but keep separate workers, owners and leftovers. Labels its Docker objects with a per-database Ask owner and recovers only its own leftovers, so reviews sharing one Docker daemon do not block each other (#95). | In use | +| Merge coordinator | `runner/merge.ts` | Runs the full merge gate twice, re-reads the local generation, then merges the exact reviewed head. Tracks merge-queue attempts. For a runner task it inspects and merges the task's own published pull request; a configured `github.pullRequest` that differs is refused (#121). | In use | +| Planning agent | `runner/planning.ts`, `web/planning.ts`, `runner/planning-provider.ts` | Runs plan suggestions and drafts with Claude in lane D's planning phase, on a read-only copy of the current head, in its own worker with its own leftovers ledger and owner token. The request and its timer share one 10-minute budget. Issue text is read with collaborators' comments only. | In use for a non-demo review with a `github` block | +| Runner coordinator | `runner/coordinator.ts`, `runner/lifecycle.ts` | Attempt admission, concurrency slots, compare-and-swap on results, retries, shutdown order. A stop made inside a user action takes effect only after that action's transaction commits (`Store.afterCommit`, #96). | In use with the opt-in `runner` block (#91) | +| Execution | `runner/execution.ts` | Runs plan items in order: fresh workspace, prompt, agent, post-run audit, then the runner's own commit and ledger entry. Before launch, D's tree check (`checkTaskTree`) must pass. Pauses in needs amendment on an out-of-scope edit. A safety violation is saved on the attempt before its terminal write, and the task moves to needs human in that same transaction; a failed run is audited too. | In use with the opt-in `runner` block; started by `start` and `resume` on `/api/runner` (#91, PR #105) | +| Workspace | `runner/workspace.ts`, `runner/runner-repository.ts` | The real lane D workspace. A runner-owned bare repository (owner-only directories) fetches base commits by ID and takes in each verified commit bundle under a per-attempt ref. Review and Ask read a task with runner commits from there, at the head the Store recorded. | In use with the opt-in `runner` block (#91) | +| Diagnostics | `runner/diagnostics.ts` | Saves the partial diff of a writable attempt that did not complete, owner-only, and keeps the folder under a size cap (256 MiB by default). | In use with the opt-in `runner` block (#91) | +| Publishing | `runner/publish.ts`, `runner/publishing.ts`, `runner/branch-push.ts` | Runs the already-fixed check, pushes the task head, then opens or reuses the task's pull request (a draft when the task needs a person). Records each opening before calling GitHub, so a lost outcome can be found again by a marker. `GitBranchPusher` pushes from the runner-owned repository through `gh auth git-credential`, only to `codeboost/` branches, and overwrites only a branch head the task's ledger owns (`--force-with-lease`). `TaskPublishing` (#103) publishes when a run ends, on the `publish` runner action, and once at startup, and records the last outcome. On cancel it closes the task's PRs (#111). | In use with the opt-in `runner` block (needs `github.baseBranch`); never in a demo | +| Lock and startup recovery | `runner/recovery.ts` | One runner per database, held as an OS lock on the database file's device and inode. Startup recovery finalizes interrupted attempts and removes leftover containers and storage. | In use. Recovery runs at start-up when the `runner` block is present; an unowned leftover Docker object blocks start-up | | Store | `runner/store.ts` | The only database handle and all SQL. Revision numbers, snapshots, ledger, approvals, choices, notes, suggestion and draft requests, tasks, attempts, user actions, feedback events, merge attempts, pull request openings, already-fixed results. | In use | -| Plan logic | `core/plan.ts`, `core/parse-v1.ts`, `schema/` | Schema validation, YAML and JSON import, meaning checks (IDs, dependencies, paths, projected file operations), literal command parsing, suggestion edits. | Yes | -| Linking engine | `core/linking.ts` | Replays each commit's line changes and assigns every final line to an owner from the ledger. Produces segments and the Unplanned and Ambiguous rows. | Yes | -| Approvals | `core/approvals.ts` | Approval fingerprints, dependency staleness, assignments, and accept-as-is choices. | Yes | -| Issue ranking | `core/issue-ranking.ts`, `github/issues.ts`, `web/issues.ts` | Deterministic, explainable issue score. Repository-scoped trust of issue authors. | Yes | -| Planning | `core/planning-author.ts`, `core/planning-suggestions.ts`, `prompts/plan-author.md` | Builds bounded planning prompts and validates plan drafts and suggestion cards. Does not run an agent itself. | In use through `/api/plan/*` (#117, #124); no screen yet | -| Execution prompt and audit | `core/execution-prompt.ts`, `core/run-audit.ts`, `prompts/execute.md` | Builds the execute and fix prompt with untrusted text only in escaped data blocks. Audits the change manifest after a run: safety violations first (Git metadata, links that leave the repository, agent commits), then scope against the declared files. | Not connected | -| Pull request text | `core/pull-request-body.ts` | Title and description with the plan. Plan and agent text go in fenced blocks, and issue references and @-mentions are neutralized, so the text cannot close other issues or notify people. | Not connected | +| Plan logic | `core/plan.ts`, `core/parse-v1.ts`, `schema/` | Schema validation, YAML and JSON import, meaning checks (IDs, dependencies, paths, projected file operations), literal command parsing, suggestion edits. | In use | +| Linking engine | `core/linking.ts` | Replays each commit's line changes and assigns every final line to an owner from the ledger. Produces segments and the Unplanned and Ambiguous rows. | In use | +| Approvals | `core/approvals.ts` | Approval fingerprints, dependency staleness, assignments, and accept-as-is choices. | In use | +| Issue ranking | `core/issue-ranking.ts`, `github/issues.ts`, `web/issues.ts` | Deterministic, explainable issue score. Repository-scoped trust of issue authors. | In use | +| Planning library | `core/planning-author.ts`, `core/planning-suggestions.ts`, `prompts/plan-author.md` | Builds bounded planning prompts and validates plan drafts and suggestion cards. Does not run an agent itself; the planning agent above does. Recorded Claude output replays through it in tests (E4, #45). | In use through `/api/plan/*` (#117, #124); no screen yet | +| Execution prompt and audit | `core/execution-prompt.ts`, `core/run-audit.ts`, `prompts/execute.md` | Builds the execute and fix prompt with untrusted text only in escaped data blocks. Audits the change manifest after a run: safety violations first (Git metadata, links that leave the repository, agent commits), then scope against the declared files. | In use with the opt-in `runner` block | +| Pull request text | `core/pull-request-body.ts` | Title and description with the plan. Plan and agent text go in fenced blocks, and issue references and @-mentions are neutralized, so the text cannot close other issues or notify people. | In use with the opt-in `runner` block | | Git adapter | `git/history.ts`, `git/clone.ts` | Bounded, hardened history reads. Standalone task clones with no links back to your repository. Every Git command runs with an allowlisted environment. | In use | -| GitHub adapter | `github/merge.ts`, `github/issues.ts`, `github/already-fixed.ts`, `github/pull-requests.ts` | Reads rules, checks, cross-references and issues through `gh`. Runs `gh pr merge --match-head-commit`. Runs the bounded already-fixed check and opens pull requests. Fails closed on anything malformed. | Merge and issues in use; already-fixed and pull requests not connected | -| Agent boundary | `agents/**` | Container image and profile, task storage with byte and inode limits, vendor-only network and proxy, phase tool policy, output supervisor, crash recovery, a bounded diff export, and task-change inspection (`snapshotDeclaredLinks`, `inspectTaskChanges`). | In use by Ask. The runner's commit (#66 part 2) is in review in PR #90 | +| GitHub adapter | `github/merge.ts`, `github/issues.ts`, `github/already-fixed.ts`, `github/pull-requests.ts` | Reads rules, checks, cross-references and issues through `gh`. Runs `gh pr merge --match-head-commit`. Runs the bounded already-fixed check and opens pull requests. Fails closed on anything malformed. | In use; opening and closing pull requests with the opt-in `runner` block | +| Agent boundary | `agents/**` | Container image and profile, task storage with byte and inode limits, vendor-only network and proxy, phase tool policy, output supervisor, owner-scoped crash recovery, a bounded diff export, task-change inspection (`snapshotDeclaredLinks`, `inspectTaskChanges`), and the runner's commit (`commitTaskChanges`, returned as a bounded `git bundle`). In planning, Claude gets the mounted schema as `--json-schema`. Before execute or fix: the pre-launch tree check (`checkTaskTree`) and a read-only tmpfs mount at every gitlink path (#100). | In use by Ask, and by plan runs with the opt-in `runner` block | ## Trust boundaries @@ -222,6 +227,8 @@ flowchart LR | Every subprocess gets an explicit allowlisted environment. Git runs with no user config, hooks or network protocols. | `git/*`, `agents/docker.ts`, `agents/process-group.ts` | | After an execute or fix run, safety violations are checked before scope. An unsafe change is never committed. | `core/run-audit.ts`, `agents/container/changes.ts` | | Plan and agent text in a pull request cannot close issues or notify people. | `core/pull-request-body.ts` | +| The runner pushes only to `codeboost/` branches, and overwrites a branch only when its current head is a commit the task's ledger owns. No token is ever in an argument or on disk. | `runner/branch-push.ts` | +| An execute or fix agent starts only after the work tree matches the recorded head plus the item's operations, with every gitlink mounted read-only. | `agents/container/changes.ts` (`checkTaskTree`), `agents/container/profile.ts` | | Nothing merges without the full gate passing twice against the same base and head, and a fresh local generation check. There is no "merge anyway". | `runner/merge.ts`, `github/merge.ts` | ## Runtime flows @@ -263,13 +270,13 @@ sequenceDiagram 1. You approve each plan item. The store saves a fingerprint of the lines, file-change metadata, the item's definition and its function context. 2. You press **Approve & merge**. The browser sends only the state token. 3. `runner/merge.ts` reloads everything itself and checks local blockers: unapproved or stale items, out-of-scope files, Ambiguous or Unplanned segments, open change requests, missing `cmd:` results. -4. `github/merge.ts` reads the pull request, rulesets, branch protection, required checks and issue cross-references. Anything unreadable or malformed blocks the merge. +4. `github/merge.ts` reads the pull request, rulesets, branch protection and required checks, and runs the same already-fixed check as the pre-PR step (`github/already-fixed.ts`). Anything unreadable or malformed blocks the merge. 5. The coordinator runs the gate a second time, confirms the same base and head, and re-reads the local generation. -6. It runs `gh pr merge --match-head-commit `. With a merge queue, it records the queue attempt and reports "merged" only when GitHub confirms it. +6. It runs `gh pr merge --match-head-commit ` on the task's own published pull request (#121), or on the configured one for a review without a runner. With a merge queue, it records the queue attempt and reports "merged" only when GitHub confirms it. -### Flow 4: carry out a plan and open the pull request (built, not connected) +### Flow 4: carry out a plan and open the pull request (in use with the `runner` block) -The code for this flow is merged, but it runs only against a test workspace. The steps marked **(pending)** need lane D's runner commit (#66 part 2, PR #90) and the workspace follow-ups (#87). +With the opt-in `runner` block, production runs the execution part of this flow: `POST /api/runner` with `start` (a task in review or queued) or `resume` (a task that stopped between items, or that recovery left to requeue) runs the plan from the first item the current revision has not completed (#91). Both refuse a closed task, a pending cancel, active work, a scope pause, and a plan revised after earlier runner commits; the last two wait for #88. When the run ends, `TaskPublishing` publishes by task status: a ready pull request when every item completed, a draft listing the problems when the task needs a person (#103). It also publishes on the `publish` action and once at start-up, and records the last outcome. The published head includes any commits that were on your branch before the runner's first commit; review shows them as Unplanned and the merge gate blocks until each is assigned or accepted (#113). ```mermaid sequenceDiagram @@ -282,21 +289,23 @@ sequenceDiagram R->>S: admit attempt (pending), capture context R->>D: prepare task clone and bounded storage R->>D: snapshotDeclaredLinks (refuse launch through a link) + R->>D: checkTaskTree (tree = head + item operations; gitlinks mounted read-only) R->>C: execute P1 with prompts/execute.md (writable /work) C-->>D: settled (agent told not to commit) R->>D: inspectTaskChanges → change manifest R->>R: auditRun: safety first, then scope - R->>D: commitTaskChanges → bounded git bundle (pending, PR #90) + R->>D: commitTaskChanges → bounded git bundle, verified and fetched into the runner repository R->>S: ledger entry owned by P1 (compare-and-swap) Note over R: repeat per plan item P->>G: already-fixed check (12 s deadline, fails closed) - P->>G: push task head (pending), open or reuse the PR + P->>G: push task head (GitBranchPusher), open or reuse the PR P->>S: record opening, then outcome; task → in review ``` Key rules for this flow, from the product design and the runner contract: -- The runner makes every commit. An agent commit or a Git metadata change makes the attempt fail closed and moves the task to **needs human**. +- The runner makes every commit. An agent commit or a Git metadata change makes the attempt fail closed and moves the task to **needs human**. The finding is saved on the attempt first, so a stop, a stale context or a crash cannot undo it, and startup recovery does not requeue that attempt. +- A writable attempt that did not complete keeps its partial diff as a diagnostic file before its storage is removed. - An edit outside the declared files is committed but stays on the plan item's row, marked out of scope. The merge gate blocks it until the plan is amended. - If a plan item needs another file, the task pauses in **needs amendment** until you approve a new plan revision. - Changes to package manifests or scripts the runner will run pause in **needs approval**. @@ -331,7 +340,7 @@ stateDiagram-v2 cancelled --> [*] ``` -The diagram shows the designed transitions. The lane F code for running, needs human, needs amendment, possibly already fixed and in review is merged but not connected; queueing, needs approval and rejecting with feedback are not built yet. A task closes only on **merged** or **cancelled**. The source of truth for the status names is `TASK_STATUSES` in `runner/lifecycle.ts`. +The diagram shows the designed transitions. With the `runner` block, running, needs human, needs amendment, possibly already fixed, in review, merged and cancelled are in use. The queue, needs approval and rejecting with feedback are not built yet. A task closes only on **merged** or **cancelled**. The source of truth for the status names is `TASK_STATUSES` in `runner/lifecycle.ts`. ### Attempt state @@ -347,15 +356,15 @@ The diagram shows the designed transitions. The lane F code for running, needs h ### Stored data -All state is in one SQLite file, opened with WAL and full synchronization. Each write takes an immediate write lock. The schema version is `PRAGMA user_version`, and migrations run in explicit steps; an unknown version fails. +All state is in one SQLite file, opened with WAL and full synchronization. Each write takes an immediate write lock. The schema version is `PRAGMA user_version`, and migrations run in explicit steps (version 11 today); an unknown version fails. | Group | Tables | Notes | |---|---|---| | Plans | `plans`, `revisions`, `requests` | SQLite allocates revision numbers. Old revisions are never changed. Suggestion and draft requests (`mode`, #124) are bound to a revision and snapshot. | | Code history | `snapshots`, `ledger`, `rewrites` | Ledger entries are immutable. Rebase mappings record which old commit became which new one; foreign stays foreign. | | Review | `approvals`, `choices`, `review_notes`, `checkpoints`, `continuations` | Stored approvals are claims about a past snapshot. Freshness is recomputed every time. | -| Runner | `tasks`, `attempts`, `user_actions`, `feedback_events`, `merge_attempts`, `app_settings` | User actions carry idempotency keys. Feedback events are append-only and feed the future learning feature. | -| Publishing | `task_pull_requests`, `already_fixed_checks` | An opening is recorded before the GitHub call, so a lost outcome is recovered, not repeated. | +| Runner | `tasks`, `attempts`, `user_actions`, `feedback_events`, `merge_attempts`, `app_settings` | User actions carry idempotency keys. Feedback events are append-only and feed the future learning feature. An attempt carries its safety finding and diagnostic reference. `app_settings` holds the runner, Ask and planning owner tokens. | +| Publishing | `task_pull_requests`, `already_fixed_checks`, `publish_outcomes` | An opening is recorded before the GitHub call, so a lost outcome is recovered, not repeated. Each task's last publish outcome is stamped with the state version that publish last saw (#114), so a later change still makes a new publish owed. | ## Deployment view @@ -398,12 +407,13 @@ These are the decisions that shape the structure. The full list, with the reason |---|---|---| | Foundation | Plan, linking, approvals, store, review screen | Done | | C, K | Guarded merge, merge queue | Done | -| D | Agent isolation boundary | Done, plus the bounded diff export (#76) and task-change inspection (#66 part 1, PR #85). Next: the runner's commit (#66 part 2, PR #90). It builds the commit in one container with both task volumes read-only and returns it as a bounded `git bundle`; this replaces the separate `exportTaskCommit` first planned. Then gitlink mounts (#81). | -| E | Planning library and suggestions | Library done. E4 fixtures are a draft PR waiting for real vendor recordings (#45). | -| F | Runner | Merged: F1a–F1e (lifecycle store, coordinator, shutdown wiring and `/api/runner`, startup recovery and the lock, planning API and feedback events), F2a (execute prompts and post-run audit), F2b (per-item execution and commit step), F2d (already-fixed check and opening the PR). Next: connect the real workspace (#87), continue after a scope pause (#88), apply a stop only after its transaction commits (#79), then rebasing and `cmd:` checks (#22). In review: the pre-merge already-fixed check reusing the pre-PR rules (F6 part, PR #89). | +| D | Agent isolation boundary | Done. Since the isolation gate: bounded diff export (#76), task-change inspection and the runner's commit as a bounded `git bundle` (#66, PRs #85 and #90), owner-scoped recovery for Ask (#95), the plan schema for Claude (#97), gitlink mounts and the pre-launch tree check (#81, #99, PR #100), and Codex refused in every phase (#93, PR #106). The runner-contract follow-ups (#51) are closed: the last one tests export and removal through a recovery handle after a real restart (PR #109). | +| E | Planning library and suggestions | Done. E4 (PR #45) added the acceptance fixtures and recorded Claude output that replays through validation and the Store. | +| F | Runner | Merged: F1 (lifecycle store, coordinator, shutdown wiring, startup recovery and the lock, planning API, feedback events, and stops that wait for their commit: #53, #74, #57, #59, #60, #96); F2a–F2b (execute prompts, audit, per-item execution, real workspace, durable safety findings: #67, #68, #92, #94, #128); F2d (already-fixed check, PR opening, branch pusher, production publishing, closing PRs on cancel: #84, #101, #110, #115, #116, #119, #123); production wiring and `start`/`resume` (#91, PRs #102, #105); planning through lane D (#117, #124, PRs #118, #120, #125); merging the task's own PR (#121, PR #126); part of F6 (#89). In review: guards for `start` and `resume` (#107, PR #130: approvals required, review version checked, earlier-commit check). Next: continue after a scope pause (#88), then rebasing and `cmd:` checks (#22). | | Hardening | Allowlisted subprocess environments | Done: every Git command (#82, #83) and every `gh` runner (#84, #86). | -| G | Planning screen | Not started (after E4) | -| H | Issue ranking and Issues screen | Done except the "trust this issue" action | +| Tests | Test suite reliability | Open: make the full suite end reliably under Docker load (#129). | +| G | Planning screen | Not started. Unblocked: E4 is done and the planning API runs Claude in production. | +| H | Issue ranking and Issues screen | Done except H4b (#108): the "trust this issue" action, plus a runner guard that refuses issues from non-collaborators that nobody trusted. Build it after #130, because both edit `runChoice` in `web/server.ts`. | | I, J | Queue and run windows; learning from feedback | Not started (after F) | ## Known limits @@ -413,7 +423,9 @@ These are the decisions that shape the structure. The full list, with the reason - The container's guarantees are those of Docker. The agent can always reach its own vendor account. - `cmd:` acceptance checks do not run yet, so any plan item with a `cmd:` check blocks merging. - One user, one machine, one runner per database. The lock refuses a second runner, and it refuses network filesystems, where OS locks are unreliable. -- No production path runs an agent that writes code yet. Execution and publishing run only in tests until #66 part 2 and #87 land. +- The runner is opt-in: it needs a `runner` block and a `github` block in `review.json`, and it is always off in the demo. It runs through the API only; the screen has no start, resume, publish or planning controls yet. Publishing also needs `github.baseBranch`. +- The runner does not check who wrote an issue yet. `start` and `resume` run a plan whose issue came from a non-collaborator (#130 adds an approval check on the plan, not on the issue author), and no attempt records which comments its prompt carried. Only collaborators' comments reach the prompt. #108 adds the guard and the record. Until then, start runs only for issues you have checked yourself. +- codeboost is Claude-only. Codex is refused in every phase (#93, PR #106), because it can read files only through its shell, which every phase turns off. `agent-isolation.md` says when to revisit this. ## Test this document with a reader