@codedology/code-forge 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +28 -2
- package/docs/reference/blocks.json +354 -1
- package/docs/reference/config.md +4 -1
- package/package.json +1 -1
- package/schema/code-forge.schema.json +10 -1
- package/skill/references/adapters/claude-code.md +1 -1
- package/skill/references/adapters/solo.md +1 -1
- package/skill/references/code.md +15 -8
- package/skill/references/ledger.md +4 -2
- package/skill/references/proof.md +1 -1
- package/skill/references/review.md +21 -7
- package/skill/references/security.md +5 -3
- package/skill/scripts/forge +1 -1
- package/src/autopilot/actions.mjs +4 -5
- package/src/cli/block.mjs +130 -31
- package/src/cli/context.mjs +3 -2
- package/src/cli/report.mjs +2 -2
- package/src/cli/review-file.mjs +67 -42
- package/src/cli/review.mjs +2 -2
- package/src/context/pack.mjs +13 -9
- package/src/doctor/index.mjs +2 -1
- package/src/doctor/local.mjs +19 -0
- package/src/doctor/worker-probe.mjs +15 -2
- package/src/ledger/export.mjs +1 -1
- package/src/ledger/report.mjs +9 -3
- package/src/ledger/spend.mjs +3 -3
- package/src/proof/lock.mjs +5 -1
- package/src/review/accept-hit.mjs +78 -0
- package/src/review/agent-waiver.mjs +201 -0
- package/src/review/gate-check.mjs +62 -28
- package/src/review/reopen.mjs +35 -14
- package/src/review/schema-fallback.mjs +3 -3
- package/src/state/config-snapshot.mjs +1 -0
- package/src/util/file-locks.mjs +118 -0
- package/src/util/forbidden.mjs +51 -2
- package/src/worker/engine.mjs +2 -2
- package/src/worker/loop.mjs +83 -33
- package/src/worker/queue.mjs +141 -33
- package/src/worker/watch.mjs +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,59 @@ waits on a second real consumer (plan §10.4, Q17).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.14.0] — 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `review-file --wait-block`: when the current content's ticket is done with a result that never counted (`stale`, `unavailable`, round-1 `split_required`), the join drops that done marker with the `--fresh` claim and the worker reviews the content once; one drop per ticket at most, kept on disk; a counted result is never dropped (B125)
|
|
14
|
+
- `block waive --yes`: a warning or nit finding can be waived without a terminal when the reason cites evidence (path:line, a test file, or an acceptance clause) and a fresh L3 judge agrees; one signed `review.waived {by: agent}` row with the verdict; refusals `waive-yes-critical`, `waive-yes-no-evidence`, `waive-yes-disagreed`; `block close` lists agent waivers and `--json` adds `agent_waivers`; `block reopen` stays human-only (B124a)
|
|
15
|
+
- `block accept-hit <id> --run --rule --line --transcript --reason`: human-only; refuses `accept-hit-no-such-hit` before any prompt; writes a signed `rule_break.accepted {block, rule, line, line_sha256, reason, by: human}` row; `block close` drops a transcript hit only on the same rule and the sha256 of that line, prints each accepted hit, and `--json` adds `accepted_hits`; the verb is on the coder forbidden list (B127)
|
|
16
|
+
- `block unwaive <id> <finding> --run --file --reason`: human-only; refuses `unwaive-no-agent-waiver` before any prompt; a signed `review.unwaived` row cancels the earlier agent waivers of that finding at the gate and the review-file pre-check; `code-forge report` gets a 15th section `agent_waivers`; new key `review.agent_waivers.require_ack` (frozen at run start): `block close` refuses `agent-waivers-not-acked` until a human `block ack-waivers <id> --run` row matches the current agent waivers (`ack-waivers-none` when there are none); both verbs are on the coder forbidden list (B124b)
|
|
17
|
+
- `block reopen <id> --file --reason --yes`: agent reopen; refuses `reopen-yes-no-evidence` without cited evidence, `reopen-yes-disagreed` when a fresh judge disagrees, and `reopen-yes-limit` after one agent reopen per block and file in a run; the row is `by: agent`; an agreed, verified agent reopen supersedes the review cap like a human reopen; `block close --json` lists `agent_reopens` (B124c)
|
|
18
|
+
- Docs: the README command table lists `--yes` on `block waive` and `block reopen` and adds `block accept-hit`, `block unwaive` and `block ack-waivers`; `docs/getting-started.md` and `skill/references/review.md` no longer say reopen has no `--yes`
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## [0.13.0] — 2026-10-14
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- The leak test in `test/worker/orphan.test.mjs` takes the current contents of the repo's `.code-forge` folder as its baseline, so `npm test` passes when that folder already holds files (B126).
|
|
26
|
+
- Close check: a `review.cap` row is superseded by a later verified human `review.reopened` row followed by a signed
|
|
27
|
+
`review.round` of the file's current content; a superseded cap row adds no ids, so old stop findings need no
|
|
28
|
+
waiver after a reopen (B123)
|
|
29
|
+
- `review-file --wait-block`: a file whose newest review left open findings and whose content changed after it is not
|
|
30
|
+
re-queued; the join answers `status: findings` with that ticket and writes one delivered marker; the next join
|
|
31
|
+
queues the latest content once, so a commit made blind to the findings never counts as a stall round (B122)
|
|
32
|
+
- Worker registry: each worker writes `<repo>/.code-forge/workers/<pid>-<start_time>.json` next to `queue/worker.json`
|
|
33
|
+
and beats both; boot counts live entries and writes its entry under one cross-process lock (limit 1); boot
|
|
34
|
+
removes dead entries (a known start-time mismatch is dead); an unreadable entry blocks the boot and `doctor`
|
|
35
|
+
lists it; `liveWorker` keeps the B30 fresh-heartbeat rule (B106)
|
|
36
|
+
- Watch mode holds rechecks: a commit of a file that already has a ticket gets no ticket, only a `watch.held`
|
|
37
|
+
row; `review-file --wait-block` queues one ticket for the latest content; older pending tickets are still
|
|
38
|
+
superseded (B121)
|
|
39
|
+
- Locks now hold across processes (`src/util/file-locks.mjs`, `~/.code-forge/locks`): ticket claims, the per-file and
|
|
40
|
+
block locks, the budget row, schema fallback and autopilot actions; a dead owner's lock (pid + start time) is broken
|
|
41
|
+
under a per-key break mutex; `doctor` lists bad locks and crashed break mutexes (B105)
|
|
42
|
+
- New opt-in key `review.fair_share` (boolean, default `false`): the worker pool gives each free slot to the
|
|
43
|
+
pending ticket whose block has the fewest running tickets; ties stay oldest first (B101)
|
|
44
|
+
- `context pack` with no `context` key writes a pack with the block header and the built-in proof rule (300-line cap)
|
|
45
|
+
instead of refusing; a bad `context` value still refuses (B118)
|
|
46
|
+
- `block close` prints `WARN block <id>: no green gates run for this block; …` when `gates.test` is set and the block's
|
|
47
|
+
last gate row is not a green `gate.done`; it still closes (B118)
|
|
48
|
+
- `block close --transcript` reads a Codex JSON log (`codex exec --json`) by its commands and file writes only;
|
|
49
|
+
agent messages, reasoning, command output and non-item events are skipped; other logs are scanned as before (B119)
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- `block open` refuses an `--owned` or `--tests` entry that contains whitespace and names no existing file or directory
|
|
54
|
+
(a shell quoting slip), naming the entry; nothing is written (B118)
|
|
55
|
+
- `npm test -- --test-name-pattern=<p>` exits 0: six test files no longer call `rm(undefined)` in cleanup when
|
|
56
|
+
their setup was skipped by the pattern (B116, built with `code-forge run` itself)
|
|
57
|
+
- The close reason names each transcript rule break once (`rule_break transcript line <n>: <id>`, at most 5,
|
|
58
|
+
then `+<k> more rule_break`) instead of repeating a bare `rule_break` (B119)
|
|
59
|
+
- `gates run --run <r> --block <id>` with plain gates (no `{test_files}`, no `--changed`) writes its `gate.done` and
|
|
60
|
+
`gate.red` rows to the run's project ledger; before, it wrote none, so the B118 close warning fired after a green run (B120)
|
|
61
|
+
|
|
9
62
|
## [0.12.0] — 2026-10-14
|
|
10
63
|
|
|
11
64
|
### Added
|
package/README.md
CHANGED
|
@@ -8,10 +8,36 @@ for cross-model, parallel, evidence-gated feature delivery — on Claude Code, C
|
|
|
8
8
|
> `examples/` have all landed (`docs/reference/blocks.json` lists every build block). What changed
|
|
9
9
|
> in each version is in [CHANGELOG.md](CHANGELOG.md).
|
|
10
10
|
|
|
11
|
-
## What's new in 0.
|
|
11
|
+
## What's new in 0.14
|
|
12
12
|
|
|
13
13
|
In the next release:
|
|
14
14
|
|
|
15
|
+
In 0.14.0:
|
|
16
|
+
|
|
17
|
+
- **A stale review no longer counts as done (B125).** When a file changed during its review and came back to the same content, `review-file --wait-block` now reviews it once more by itself. No `--fresh` by hand.
|
|
18
|
+
- **Agent waivers with proof (B124a).** `block waive --yes` now works for a warning or nit finding. The reason must name evidence: a `path:line`, a test file, or an acceptance clause. A fresh judge must agree. The row is marked `by: agent`, and `block close` lists it. A critical finding and `block reopen` stay human-only.
|
|
19
|
+
- **Accept a false rule hit (B127).** `block accept-hit <id> --run <r> --rule <rule-id> --line <n> --transcript <path> --reason <text>` lets a human accept one false transcript hit, after a yes in their own terminal. The close then skips that hit only when the rule and the exact line text match. The close lists each accepted hit, and `--json` adds `accepted_hits`. A coder can never run this verb.
|
|
20
|
+
- **Undo and check agent waivers (B124b).** `block unwaive <id> <finding> --run <r> --file <path> --reason <text>` lets a human undo one agent waiver. The finding is then open again. `code-forge report` has a new `agent_waivers` section. Set `review.agent_waivers.require_ack: true`, and `block close` waits until a human runs `block ack-waivers <id> --run <r>` and says yes to the list. Both verbs are human-only.
|
|
21
|
+
- **Agent reopen with evidence (B124c).** `block reopen <id> --file <path> --reason <text> --yes` lets the orchestrator reopen a stopped file without you. The reason must cite evidence, a fresh judge must agree, and only one agent reopen per block and file is allowed in a run. The row says `by: agent`. `block close --json` lists them in `agent_reopens`. Without `--yes`, a human still confirms.
|
|
22
|
+
|
|
23
|
+
## What's new in 0.13
|
|
24
|
+
|
|
25
|
+
In 0.13.0:
|
|
26
|
+
|
|
27
|
+
- **Every block gets the proof rule, with or without a `context` key (B118).** `code-forge context pack` no longer refuses a config with no `context` key. The pack then holds the block header and the proof rule.
|
|
28
|
+
- **Safer block open and close (B118).** `block open` refuses an owned or test path that has spaces and names no file, a common shell quoting slip. `block close` warns when the block has no green gates run.
|
|
29
|
+
- **Clean rule checks on Codex logs (B119).** Run `codex exec --json` and pass the log to `block close --transcript`. code-forge then checks only the commands Codex ran and the files it wrote. Agent messages, reasoning and command output no longer give false rule breaks. The close reason names each rule break once.
|
|
30
|
+
- **Gate results are recorded again (B120).** `gates run --run <r> --block <id>` now writes its `gate.done` row also when no gate uses `{test_files}`. Before, the row was missing, so `block close` warned after a green run and `status` showed no gate result.
|
|
31
|
+
- **Fair share between blocks (B101).** Set `review.fair_share: true` and each free review slot goes to the block with the fewest running reviews. A block with many queued files no longer makes another block wait. Without the key, the order stays oldest first.
|
|
32
|
+
- **Locks hold across processes (B105).** Ticket claims and the locks for files, blocks and the budget row now work across worker processes. Lock files live in `~/.code-forge/locks`. A lock of a dead process is taken over safely. A bad lock, or a break lock left by a crashed process, blocks its key until you remove it, and `code-forge doctor` names it.
|
|
33
|
+
- **Watch waits for the whole fix (B121).** In watch mode, a file's first commit is reviewed at once. A later commit of a file that already has a review is held, and a `watch.held` row records it. `review-file --wait-block` then queues one review for the file's latest content. A half-done fix commit no longer uses up the file's review rounds.
|
|
34
|
+
- **One registry file per worker (B106).** Each worker writes its own file in `.code-forge/workers/` and keeps it fresh with its heartbeat. A new worker starts only when the live count is under the limit, which is 1 for now. The count and the new file are written under one lock, so two workers that start at the same time cannot both run. A file of a dead worker is removed at the next start. A file that cannot be read blocks the start, and `code-forge doctor` names it.
|
|
35
|
+
- **The join shows findings before it rechecks (B122).** Sometimes the coder commits again before reading the last review. At `review-file --wait-block`, such a file is not reviewed again yet. The join answers `findings` with the old ticket, so the coder reads and fixes them first. The next join rechecks the latest content once. A blind commit no longer counts as a stall round.
|
|
36
|
+
- **A reopen clears old stop findings (B123).** After `block reopen` and a fresh review of the new content, the close no longer asks you to waive the findings of the old stop. Only the fresh review's findings count.
|
|
37
|
+
- **The test suite passes on machines that use code-forge on itself (B126).** A leak test no longer counts files that were already in the repo's `.code-forge` folder.
|
|
38
|
+
|
|
39
|
+
## What's new in 0.12
|
|
40
|
+
|
|
15
41
|
In 0.12.0:
|
|
16
42
|
|
|
17
43
|
- **Faster fix rounds (B99).** `code-forge gates run --run <r> --block <id> --changed` runs only the tests of files changed since the last green gate run, and `{changed_files}` passes only the changed files to lint or format gates. It falls back to the normal scope when it cannot be sure.
|
|
@@ -339,7 +365,7 @@ usage line.
|
|
|
339
365
|
| `validate` | `code-forge validate [--file <path>]` |
|
|
340
366
|
| `resolve` | `code-forge resolve <L0\|L1\|L2\|L3>` |
|
|
341
367
|
| `run` | `code-forge run start [--cwd <dir>] [--run <id>] [--engine <e>] [--worker-pid <pid>]` · `run start --reattach --run <id> [--worker-pid <pid>]` · `run status --run <id>` (with spent and budget USD) · `run reload --run <id>` (re-read `.code-forge.yml` mid-run) · `run end --run <id>` |
|
|
342
|
-
| `block` | `code-forge block open <id> --run <r> [--level L<n>] --owned <paths…> --acceptance <file> [--brief <file>] [--attempt <n>] [--base <sha>] [--lines <n>] [--kind code\|docs\|contract]` · `block attempt\|rebase <id> --run <r>` · `block close <id> --run <r> [--transcript <file>] [--report <file>] [--no-require-reviews]` · `block claim <id> <path> --run <r>` · `block stop <id> --run <r> --reason <text>` · `block waive <id> <finding-id> --run <r> --file <path> --reason <text
|
|
368
|
+
| `block` | `code-forge block open <id> --run <r> [--level L<n>] --owned <paths…> --acceptance <file> [--brief <file>] [--attempt <n>] [--base <sha>] [--lines <n>] [--kind code\|docs\|contract]` · `block attempt\|rebase <id> --run <r>` · `block close <id> --run <r> [--transcript <file>] [--report <file>] [--no-require-reviews]` · `block claim <id> <path> --run <r>` · `block stop <id> --run <r> --reason <text>` · `block waive <id> <finding-id> --run <r> --file <path> --reason <text> [--yes]` · `block reopen <id> --run <r> --file <path> --reason <text> [--yes]` (without `--yes` you run them in your own terminal and they ask for a yes; with `--yes` the reason must cite evidence, a fresh judge must agree, and the row is `by: agent`) · `block accept-hit <id> --run <r> --rule <rule-id> --line <n> --transcript <path> --reason <text>` · `block unwaive <id> <finding-id> --run <r> --file <path> --reason <text>` · `block ack-waivers <id> --run <r>` (these three are human-only) |
|
|
343
369
|
| `worker` | `code-forge worker --run <id> [--cwd <dir>] [--poll-ms <n>] [--once]` — started detached by `run start`, never by a coder |
|
|
344
370
|
| `review` | `code-forge review [--base <ref>] [--files <path…>] [--acceptance <file> \| --intent "<text>"] [--run <id>] [--max <seconds>] [--json] [--keep-run]` — review only: no coder, no proof, never closes a block |
|
|
345
371
|
| `review-file` | `code-forge review-file <path> --block <id> [--run <id>]` (enqueue) · `review-file --wait <ticket> [--max <seconds>s]` (poll, default 90s; still running at `--max` prints `status: pending, reason: wait_timeout`) |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"plans/code-forge-plan-v1.3.md §10.4",
|
|
5
5
|
"plans/NIGHT-LOG.md"
|
|
6
6
|
],
|
|
7
|
-
"block_count":
|
|
7
|
+
"block_count": 133,
|
|
8
8
|
"baseline_ids": ["B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8"],
|
|
9
9
|
"baseline_note": "Wave 0-1 blocks, landed before v1.3; depends_on may name them, but they have no entry under blocks.",
|
|
10
10
|
"blocks": {
|
|
@@ -1982,6 +1982,359 @@
|
|
|
1982
1982
|
"B104"
|
|
1983
1983
|
],
|
|
1984
1984
|
"note": "owner 2026-10-13: pass the proof rule to every project built with code-forge; 1 round, 3 minors not-bug; removed dead proofRequirements (mutants: held)"
|
|
1985
|
+
},
|
|
1986
|
+
"B116": {
|
|
1987
|
+
"title": "Test cleanup skips unset paths under --test-name-pattern (built with code-forge run)",
|
|
1988
|
+
"wave": 14,
|
|
1989
|
+
"level": "L1",
|
|
1990
|
+
"status": "landed",
|
|
1991
|
+
"owned": [
|
|
1992
|
+
"test/config/cli-models.test.mjs",
|
|
1993
|
+
"test/config/load.test.mjs",
|
|
1994
|
+
"test/config/refresh.test.mjs",
|
|
1995
|
+
"test/engines/isolation.test.mjs",
|
|
1996
|
+
"test/ledger/outcome.test.mjs",
|
|
1997
|
+
"test/skill/shim.test.mjs"
|
|
1998
|
+
],
|
|
1999
|
+
"depends_on": [
|
|
2000
|
+
"B117"
|
|
2001
|
+
],
|
|
2002
|
+
"note": "dogfood: brief run, review.file_loop watch, worktree isolation; ~8 min wall; 0 findings"
|
|
2003
|
+
},
|
|
2004
|
+
"B118": {
|
|
2005
|
+
"title": "Context pack without a context key; block open refuses whitespace paths that name no file; close warns without green gates",
|
|
2006
|
+
"wave": 14,
|
|
2007
|
+
"level": "L1",
|
|
2008
|
+
"status": "landed",
|
|
2009
|
+
"owned": [
|
|
2010
|
+
"docs/brief-mode.md",
|
|
2011
|
+
"skill/references/code.md",
|
|
2012
|
+
"src/cli/block.mjs",
|
|
2013
|
+
"src/cli/context.mjs",
|
|
2014
|
+
"src/context/pack.mjs",
|
|
2015
|
+
"test/cli/block-close-gates.test.mjs",
|
|
2016
|
+
"test/cli/block-open-owned.test.mjs",
|
|
2017
|
+
"test/context/pack.test.mjs",
|
|
2018
|
+
"test/proof/worktree-flow.test.mjs"
|
|
2019
|
+
],
|
|
2020
|
+
"depends_on": [
|
|
2021
|
+
"B116"
|
|
2022
|
+
],
|
|
2023
|
+
"note": "dogfood findings from B116, built with code-forge run; 0 review findings; the orchestrator updated the B62b malformed-record test for the new close warning"
|
|
2024
|
+
},
|
|
2025
|
+
"B119": {
|
|
2026
|
+
"title": "Transcript grep reads Codex JSON logs by commands only; close names each rule break once",
|
|
2027
|
+
"wave": 14,
|
|
2028
|
+
"level": "L2",
|
|
2029
|
+
"status": "landed",
|
|
2030
|
+
"owned": [
|
|
2031
|
+
"docs/brief-mode.md",
|
|
2032
|
+
"skill/references/code.md",
|
|
2033
|
+
"src/review/gate-check.mjs",
|
|
2034
|
+
"src/util/forbidden.mjs",
|
|
2035
|
+
"test/cli/block-close-rule-break.test.mjs",
|
|
2036
|
+
"test/review/external.test.mjs",
|
|
2037
|
+
"test/util/transcript-codex.test.mjs"
|
|
2038
|
+
],
|
|
2039
|
+
"depends_on": [
|
|
2040
|
+
"B118"
|
|
2041
|
+
],
|
|
2042
|
+
"note": "dogfood finding from B118, built with code-forge run; 1 review warning answered; named mutation (unknown item types fail closed) caught"
|
|
2043
|
+
},
|
|
2044
|
+
"B120": {
|
|
2045
|
+
"title": "Plain gates runs with --run --block write their gate rows",
|
|
2046
|
+
"wave": 14,
|
|
2047
|
+
"level": "L1",
|
|
2048
|
+
"status": "landed",
|
|
2049
|
+
"owned": [
|
|
2050
|
+
"src/proof/lock.mjs",
|
|
2051
|
+
"test/cli/block-close-gates.test.mjs"
|
|
2052
|
+
],
|
|
2053
|
+
"depends_on": [
|
|
2054
|
+
"B119"
|
|
2055
|
+
],
|
|
2056
|
+
"note": "dogfood finding from B119, built with code-forge run; 0 review findings; first dogfood close with no warning"
|
|
2057
|
+
},
|
|
2058
|
+
"B101": {
|
|
2059
|
+
"title": "Opt-in fair share across blocks in the worker pool (review.fair_share)",
|
|
2060
|
+
"wave": 14,
|
|
2061
|
+
"level": "L1",
|
|
2062
|
+
"status": "landed",
|
|
2063
|
+
"owned": [
|
|
2064
|
+
"docs/how-it-works.md",
|
|
2065
|
+
"docs/reference/config.md",
|
|
2066
|
+
"schema/code-forge.schema.json",
|
|
2067
|
+
"skill/references/review.md",
|
|
2068
|
+
"src/worker/loop.mjs",
|
|
2069
|
+
"test/config/schema-coverage.test.mjs",
|
|
2070
|
+
"test/worker/fair-share.test.mjs"
|
|
2071
|
+
],
|
|
2072
|
+
"depends_on": [
|
|
2073
|
+
"B120"
|
|
2074
|
+
],
|
|
2075
|
+
"note": "E4a; built with code-forge run; 0 review findings; the orchestrator re-pinned the schema path count (212 -> 213)"
|
|
2076
|
+
},
|
|
2077
|
+
"B105": {
|
|
2078
|
+
"title": "Cross-process locks for ticket claims, files, blocks and the budget row (E4b part 1)",
|
|
2079
|
+
"wave": 14,
|
|
2080
|
+
"level": "L2",
|
|
2081
|
+
"status": "landed",
|
|
2082
|
+
"owned": [
|
|
2083
|
+
"docs/how-it-works.md",
|
|
2084
|
+
"skill/references/review.md",
|
|
2085
|
+
"src/autopilot/actions.mjs",
|
|
2086
|
+
"src/doctor/index.mjs",
|
|
2087
|
+
"src/doctor/local.mjs",
|
|
2088
|
+
"src/ledger/spend.mjs",
|
|
2089
|
+
"src/review/schema-fallback.mjs",
|
|
2090
|
+
"src/util/file-locks.mjs",
|
|
2091
|
+
"src/worker/engine.mjs",
|
|
2092
|
+
"src/worker/loop.mjs",
|
|
2093
|
+
"test/util/file-locks.test.mjs",
|
|
2094
|
+
"test/worker/claim.test.mjs"
|
|
2095
|
+
],
|
|
2096
|
+
"depends_on": [
|
|
2097
|
+
"B101"
|
|
2098
|
+
],
|
|
2099
|
+
"note": "attempt 1 refused at close (coder transcript read ~/.code-forge/runs); re-run clean; two stopped reviews reopened by the owner and approved"
|
|
2100
|
+
},
|
|
2101
|
+
"B121": {
|
|
2102
|
+
"title": "Watch holds rechecks until the block join",
|
|
2103
|
+
"wave": 14,
|
|
2104
|
+
"level": "L2",
|
|
2105
|
+
"status": "landed",
|
|
2106
|
+
"owned": [
|
|
2107
|
+
"docs/how-it-works.md",
|
|
2108
|
+
"docs/reference/config.md",
|
|
2109
|
+
"schema/code-forge.schema.json",
|
|
2110
|
+
"skill/references/code.md",
|
|
2111
|
+
"skill/references/review.md",
|
|
2112
|
+
"src/worker/watch.mjs",
|
|
2113
|
+
"test/worker/watch.test.mjs"
|
|
2114
|
+
],
|
|
2115
|
+
"depends_on": [
|
|
2116
|
+
"B105"
|
|
2117
|
+
],
|
|
2118
|
+
"note": "Watch mode queues a file's first commit at once; later commits of a file that already has a ticket are held (watch.held row) until review-file --wait-block queues one ticket for the latest content. Stops a half-done fix commit from using the file's review rounds."
|
|
2119
|
+
},
|
|
2120
|
+
"B106": {
|
|
2121
|
+
"title": "Worker registry: one announcement per worker",
|
|
2122
|
+
"wave": 14,
|
|
2123
|
+
"level": "L2",
|
|
2124
|
+
"status": "landed",
|
|
2125
|
+
"owned": [
|
|
2126
|
+
"docs/how-it-works.md",
|
|
2127
|
+
"skill/references/code.md",
|
|
2128
|
+
"src/cli/review.mjs",
|
|
2129
|
+
"src/doctor/local.mjs",
|
|
2130
|
+
"src/doctor/worker-probe.mjs",
|
|
2131
|
+
"src/worker/loop.mjs",
|
|
2132
|
+
"src/worker/queue.mjs",
|
|
2133
|
+
"test/worker/registry.test.mjs"
|
|
2134
|
+
],
|
|
2135
|
+
"depends_on": [
|
|
2136
|
+
"B105"
|
|
2137
|
+
],
|
|
2138
|
+
"note": "Each worker writes <repo>/.code-forge/workers/<pid>-<start_time>.json next to worker.json and beats both; boot counts live entries and announces under one cross-process lock (limit 1); boot prunes dead entries (known start-time mismatch = dead); an unreadable entry blocks boot and doctor lists it; liveWorker keeps the B30 fresh-heartbeat rule."
|
|
2139
|
+
},
|
|
2140
|
+
"B122": {
|
|
2141
|
+
"title": "Join delivers unseen findings before a recheck",
|
|
2142
|
+
"wave": 14,
|
|
2143
|
+
"level": "L2",
|
|
2144
|
+
"status": "landed",
|
|
2145
|
+
"owned": [
|
|
2146
|
+
"docs/how-it-works.md",
|
|
2147
|
+
"skill/references/code.md",
|
|
2148
|
+
"skill/references/review.md",
|
|
2149
|
+
"src/cli/review-file.mjs",
|
|
2150
|
+
"src/worker/queue.mjs",
|
|
2151
|
+
"test/worker/wait-block.test.mjs"
|
|
2152
|
+
],
|
|
2153
|
+
"depends_on": [
|
|
2154
|
+
"B121"
|
|
2155
|
+
],
|
|
2156
|
+
"note": "At review-file --wait-block, a file whose newest review found problems and that changed after it (a commit made blind to the findings) is not rechecked: the join answers status findings with that ticket and writes one delivered marker. The next join rechecks the latest content once. Stops a blind commit from counting as a stall round."
|
|
2157
|
+
},
|
|
2158
|
+
"B123": {
|
|
2159
|
+
"title": "Reopen clears old cap ids after a fresh review",
|
|
2160
|
+
"wave": 14,
|
|
2161
|
+
"level": "L2",
|
|
2162
|
+
"status": "landed",
|
|
2163
|
+
"owned": [
|
|
2164
|
+
"docs/how-it-works.md",
|
|
2165
|
+
"skill/references/review.md",
|
|
2166
|
+
"src/review/gate-check.mjs",
|
|
2167
|
+
"test/review/gate-check-reopen-cap.test.mjs"
|
|
2168
|
+
],
|
|
2169
|
+
"depends_on": [
|
|
2170
|
+
"B122"
|
|
2171
|
+
],
|
|
2172
|
+
"note": "A review.cap row is superseded when a verified human review.reopened row comes after it and then a signed review.round of the file's current content. A superseded cap row adds no ids to the close check, so after a reopen only the fresh review's own findings need a fix, waiver or answer."
|
|
2173
|
+
},
|
|
2174
|
+
"B126": {
|
|
2175
|
+
"title": "Leak test ignores files already in the repo's .code-forge",
|
|
2176
|
+
"wave": 14,
|
|
2177
|
+
"level": "L1",
|
|
2178
|
+
"status": "landed",
|
|
2179
|
+
"owned": [
|
|
2180
|
+
"test/worker/orphan.test.mjs"
|
|
2181
|
+
],
|
|
2182
|
+
"depends_on": [
|
|
2183
|
+
"B113"
|
|
2184
|
+
],
|
|
2185
|
+
"note": "The final-check test in orphan.test.mjs forged an empty baseline, so files already in the repo's .code-forge folder (normal when code-forge builds itself) showed up as leaks and failed npm test. The test now records the folder's current contents as the baseline and still checks the exact planted leak list."
|
|
2186
|
+
},
|
|
2187
|
+
"B125": {
|
|
2188
|
+
"title": "The join reruns a stale review of the current content once",
|
|
2189
|
+
"wave": 14,
|
|
2190
|
+
"level": "L2",
|
|
2191
|
+
"status": "landed",
|
|
2192
|
+
"owned": [
|
|
2193
|
+
"docs/how-it-works.md",
|
|
2194
|
+
"skill/references/review.md",
|
|
2195
|
+
"src/cli/review-file.mjs",
|
|
2196
|
+
"src/worker/queue.mjs",
|
|
2197
|
+
"test/worker/wait-block.test.mjs"
|
|
2198
|
+
],
|
|
2199
|
+
"depends_on": [
|
|
2200
|
+
"B122"
|
|
2201
|
+
],
|
|
2202
|
+
"note": "review-file --wait-block: when the ticket of a file's current content is done with a result that never counted (stale, unavailable, round-1 split_required), the join drops that done marker with the --fresh claim and the worker reviews the content once; at most one drop per ticket, kept on disk. Counted results are never dropped."
|
|
2203
|
+
},
|
|
2204
|
+
"B124a": {
|
|
2205
|
+
"title": "block waive --yes: an evidence-backed agent waiver a fresh judge must agree with",
|
|
2206
|
+
"wave": 14,
|
|
2207
|
+
"level": "L2",
|
|
2208
|
+
"status": "landed",
|
|
2209
|
+
"owned": [
|
|
2210
|
+
"docs/concepts.md",
|
|
2211
|
+
"docs/how-it-works.md",
|
|
2212
|
+
"skill/references/adapters/claude-code.md",
|
|
2213
|
+
"skill/references/adapters/solo.md",
|
|
2214
|
+
"skill/references/code.md",
|
|
2215
|
+
"skill/references/ledger.md",
|
|
2216
|
+
"skill/references/proof.md",
|
|
2217
|
+
"skill/references/review.md",
|
|
2218
|
+
"skill/references/security.md",
|
|
2219
|
+
"src/cli/block.mjs",
|
|
2220
|
+
"src/review/agent-waiver.mjs",
|
|
2221
|
+
"src/review/gate-check.mjs",
|
|
2222
|
+
"test/cli/block-human-confirm.test.mjs",
|
|
2223
|
+
"test/cli/block-waive-yes.test.mjs",
|
|
2224
|
+
"test/skill/structure.test.mjs"
|
|
2225
|
+
],
|
|
2226
|
+
"depends_on": [
|
|
2227
|
+
"B80",
|
|
2228
|
+
"B62a",
|
|
2229
|
+
"B90",
|
|
2230
|
+
"B122",
|
|
2231
|
+
"B93",
|
|
2232
|
+
"B47"
|
|
2233
|
+
],
|
|
2234
|
+
"note": "block waive --yes skips the terminal confirm only for a finding whose signed recorded severity is warning or nit; the reason must cite evidence (path:line, a test file, or an acceptance clause); a fresh L3 judge must agree; then one signed review.waived row by: agent with the verdict. Critical or unknown severity is refused waive-yes-critical; no evidence waive-yes-no-evidence (judge not called); disagree waive-yes-disagreed. The gate counts an agreed agent waiver; block close lists agent waivers and --json adds agent_waivers. block reopen stays human-only with no --yes."
|
|
2235
|
+
},
|
|
2236
|
+
"B127": {
|
|
2237
|
+
"title": "block accept-hit: the human accepts one named false transcript hit",
|
|
2238
|
+
"wave": 14,
|
|
2239
|
+
"level": "L2",
|
|
2240
|
+
"status": "landed",
|
|
2241
|
+
"owned": [
|
|
2242
|
+
"docs/how-it-works.md",
|
|
2243
|
+
"skill/references/review.md",
|
|
2244
|
+
"skill/references/security.md",
|
|
2245
|
+
"src/cli/block.mjs",
|
|
2246
|
+
"src/review/accept-hit.mjs",
|
|
2247
|
+
"src/review/gate-check.mjs",
|
|
2248
|
+
"src/util/forbidden.mjs",
|
|
2249
|
+
"test/cli/block-accept-hit.test.mjs",
|
|
2250
|
+
"test/engines/builders/argv-snapshots.test.mjs",
|
|
2251
|
+
"test/engines/builders/forbidden-rendering.test.mjs",
|
|
2252
|
+
"test/engines/codex-home.test.mjs",
|
|
2253
|
+
"test/util/forbidden.test.mjs"
|
|
2254
|
+
],
|
|
2255
|
+
"depends_on": [
|
|
2256
|
+
"B124a",
|
|
2257
|
+
"B80",
|
|
2258
|
+
"B5"
|
|
2259
|
+
],
|
|
2260
|
+
"note": "block accept-hit <id> --run --rule --line --transcript --reason: human-only (terminal yes, no --yes); pre-checks refuse accept-hit-no-such-hit before any prompt when the transcript scan does not report that (rule, line); on yes one signed rule_break.accepted row {block, rule, line, line_sha256, reason, by: human}. block close drops a transcript hit only when a verified accepted row of the same run and block has the same rule and the sha256 of that exact line text; a rule_break ledger row is never accepted. close prints each accepted hit; --json adds accepted_hits. The verb is coder-only forbidden."
|
|
2261
|
+
},
|
|
2262
|
+
"B124b": {
|
|
2263
|
+
"title": "undo and audit agent waivers: block unwaive, report agent_waivers, require_ack + block ack-waivers",
|
|
2264
|
+
"wave": 14,
|
|
2265
|
+
"level": "L2",
|
|
2266
|
+
"status": "landed",
|
|
2267
|
+
"owned": [
|
|
2268
|
+
"docs/concepts.md",
|
|
2269
|
+
"docs/how-it-works.md",
|
|
2270
|
+
"docs/reference/config.md",
|
|
2271
|
+
"docs/tutorial-first-test.md",
|
|
2272
|
+
"schema/code-forge.schema.json",
|
|
2273
|
+
"skill/references/ledger.md",
|
|
2274
|
+
"skill/references/review.md",
|
|
2275
|
+
"skill/references/security.md",
|
|
2276
|
+
"src/cli/block.mjs",
|
|
2277
|
+
"src/cli/report.mjs",
|
|
2278
|
+
"src/ledger/export.mjs",
|
|
2279
|
+
"src/ledger/report.mjs",
|
|
2280
|
+
"src/review/agent-waiver.mjs",
|
|
2281
|
+
"src/review/gate-check.mjs",
|
|
2282
|
+
"src/state/config-snapshot.mjs",
|
|
2283
|
+
"src/util/forbidden.mjs",
|
|
2284
|
+
"test/cli/block-ack-waivers.test.mjs",
|
|
2285
|
+
"test/cli/block-unwaive.test.mjs",
|
|
2286
|
+
"test/config/schema-coverage.test.mjs",
|
|
2287
|
+
"test/engines/builders/argv-snapshots.test.mjs",
|
|
2288
|
+
"test/engines/builders/forbidden-rendering.test.mjs",
|
|
2289
|
+
"test/engines/codex-home.test.mjs",
|
|
2290
|
+
"test/first-use.test.mjs",
|
|
2291
|
+
"test/ledger/cli.test.mjs",
|
|
2292
|
+
"test/ledger/export.test.mjs",
|
|
2293
|
+
"test/ledger/report.test.mjs",
|
|
2294
|
+
"test/skill/structure.test.mjs",
|
|
2295
|
+
"test/state/brief-mode.test.mjs",
|
|
2296
|
+
"test/util/forbidden.test.mjs"
|
|
2297
|
+
],
|
|
2298
|
+
"depends_on": [
|
|
2299
|
+
"B124a",
|
|
2300
|
+
"B127",
|
|
2301
|
+
"B66",
|
|
2302
|
+
"B58"
|
|
2303
|
+
],
|
|
2304
|
+
"note": "block unwaive <id> <finding> --run --file --reason: human-only; refuses unwaive-no-agent-waiver before any prompt unless a verified by: agent waiver exists; writes a signed review.unwaived row that cancels earlier agent waivers of that (block, file, finding) on the gate and the review-file pre-check. report gets a 15th section agent_waivers {block, file, finding, severity, reason, verdict, unwaived}. review.agent_waivers.require_ack (frozen at run start): close refuses agent-waivers-not-acked until a human block ack-waivers row matches the digest of the counted agent waivers; ack-waivers-none with none. Both verbs are coder-only forbidden."
|
|
2305
|
+
},
|
|
2306
|
+
"B124c": {
|
|
2307
|
+
"title": "agent reopen: block reopen --yes with evidence, fresh judge, one per block and file per run; close audit agent_reopens",
|
|
2308
|
+
"wave": 14,
|
|
2309
|
+
"level": "L2",
|
|
2310
|
+
"status": "landed",
|
|
2311
|
+
"owned": [
|
|
2312
|
+
"docs/concepts.md",
|
|
2313
|
+
"docs/how-it-works.md",
|
|
2314
|
+
"skill/references/adapters/claude-code.md",
|
|
2315
|
+
"skill/references/adapters/solo.md",
|
|
2316
|
+
"skill/references/code.md",
|
|
2317
|
+
"skill/references/ledger.md",
|
|
2318
|
+
"skill/references/review.md",
|
|
2319
|
+
"skill/references/security.md",
|
|
2320
|
+
"src/cli/block.mjs",
|
|
2321
|
+
"src/review/agent-waiver.mjs",
|
|
2322
|
+
"src/review/gate-check.mjs",
|
|
2323
|
+
"src/review/reopen.mjs",
|
|
2324
|
+
"test/cli/block-human-confirm.test.mjs",
|
|
2325
|
+
"test/cli/block-reopen-yes.test.mjs",
|
|
2326
|
+
"test/review/gate-check-reopen-cap.test.mjs",
|
|
2327
|
+
"test/review/reopen.test.mjs",
|
|
2328
|
+
"test/skill/structure.test.mjs"
|
|
2329
|
+
],
|
|
2330
|
+
"depends_on": [
|
|
2331
|
+
"B124b",
|
|
2332
|
+
"B124a",
|
|
2333
|
+
"B72",
|
|
2334
|
+
"B80",
|
|
2335
|
+
"B123"
|
|
2336
|
+
],
|
|
2337
|
+
"note": "block reopen <id> --file --reason --yes: the reason must cite evidence (reopen-yes-no-evidence), a fresh judge must agree (reopen-yes-disagreed), at most one agent reopen per block and file per run (reopen-yes-limit); the row is by: agent. An agreed, verified agent reopen supersedes the B123 cap like a human reopen. block close --json lists agent_reopens. Without --yes the verb still needs human confirmation."
|
|
1985
2338
|
}
|
|
1986
2339
|
}
|
|
1987
2340
|
}
|
package/docs/reference/config.md
CHANGED
|
@@ -136,7 +136,10 @@ Every other key defaults as shown, or is entirely absent from a minimal file. `a
|
|
|
136
136
|
| `review.provider_concurrency.openai` | integer | | `2` | min 1 |
|
|
137
137
|
| `review.provider_concurrency.xai` | integer | | `2` | min 1 |
|
|
138
138
|
| `review.parallel_tickets` | integer | | `3` | min 1; max 16; B42: how many review tickets the worker runs at once (oldest first); 1 = one at a time. Tickets for the same file never overlap. |
|
|
139
|
-
| `review.
|
|
139
|
+
| `review.fair_share` | boolean | | `false` | Give each free ticket slot to the block with the fewest running tickets; ties stay oldest first. |
|
|
140
|
+
| `review.file_loop` | enum: `wait`, `overlap`, `watch` | | `"wait"` | After each green file, enqueue its review. wait (default): wait for its ticket before the next file. overlap: continue coding, then run review-file --wait-block <id> --run <run> before the completion sentinel; inspect findings with --wait <ticket>. watch: commit each green file instead of running review-file. A file's first commit is queued at once. Later commits of a file that already has a ticket of this block are held (a watch.held row) until --wait-block, which queues the latest content once before the sentinel. Older pending tickets are still superseded. |
|
|
141
|
+
| `review.agent_waivers` | object | | — | |
|
|
142
|
+
| `review.agent_waivers.require_ack` | boolean | | `false` | Require a verified human acknowledgement of the current counted agent waiver set before block close. Read only from the run config snapshot. New or removed waivers need a new acknowledgement. |
|
|
140
143
|
| `review.external` | object | | — | |
|
|
141
144
|
| `review.external.required` | boolean | | `false` | B58: true ⇒ block close skips the local per-file review checks (and the --report ticket check), with no terminal and under autopilot, and writes a signed gate.reviews_waived {by: config} row. Unowned changes, proof, no_changes and the transcript grep still refuse. No block may own .code-forge.yml. |
|
|
142
145
|
| `review.external.name` | string | | — | minLength 1; B58: the outside reviewer, written in the review.external and gate.reviews_waived rows. Required when required is true: run start refuses a missing or blank name. |
|
package/package.json
CHANGED
|
@@ -185,7 +185,16 @@
|
|
|
185
185
|
}
|
|
186
186
|
},
|
|
187
187
|
"parallel_tickets": { "type": "integer", "minimum": 1, "maximum": 16, "default": 3, "description": "B42: how many review tickets the worker runs at once (oldest first); 1 = one at a time. Tickets for the same file never overlap." },
|
|
188
|
-
"
|
|
188
|
+
"fair_share": { "type": "boolean", "default": false, "description": "Give each free ticket slot to the block with the fewest running tickets; ties stay oldest first." },
|
|
189
|
+
"file_loop": { "type": "string", "enum": ["wait", "overlap", "watch"], "default": "wait", "description": "After each green file, enqueue its review. wait (default): wait for its ticket before the next file. overlap: continue coding, then run review-file --wait-block <id> --run <run> before the completion sentinel; inspect findings with --wait <ticket>. watch: commit each green file instead of running review-file. A file's first commit is queued at once. Later commits of a file that already has a ticket of this block are held (a watch.held row) until --wait-block, which queues the latest content once before the sentinel. Older pending tickets are still superseded." },
|
|
190
|
+
"agent_waivers": {
|
|
191
|
+
"type": "object",
|
|
192
|
+
"additionalProperties": false,
|
|
193
|
+
"description": "Human acknowledgement of counted agent waivers. Set before run start; run reload refuses to change require_ack.",
|
|
194
|
+
"properties": {
|
|
195
|
+
"require_ack": { "type": "boolean", "default": false, "description": "Require a verified human acknowledgement of the current counted agent waiver set before block close. Read only from the run config snapshot. New or removed waivers need a new acknowledgement." }
|
|
196
|
+
}
|
|
197
|
+
},
|
|
189
198
|
"external": {
|
|
190
199
|
"type": "object",
|
|
191
200
|
"additionalProperties": false,
|
|
@@ -12,7 +12,7 @@ The harness's `Agent` tool runs the coder as a subagent; everything else — the
|
|
|
12
12
|
|
|
13
13
|
The tool return is the completion signal; the report must begin with `ACK <sha8>` and end with `===BLOCK <id> COMPLETE===` (+ test summary + `git diff --stat`) or `===BLOCK <id> FAILED: <reason>===`. A report without the sentinel is a failed block, never a partial success.
|
|
14
14
|
|
|
15
|
-
**Between completion and close come the review rounds.** The subagent ran `forge review-file <path> --block <id> --run <r>` per file and `--wait`ed on each ticket inside its turn, so most rounds happen before the sentinel; when the tool returns, first drain every `pending` ticket with `forge review-file --wait <ticket>` yourself — a pending ticket is a review in flight, not an open finding, and waiting on it costs no round. Then the open `fix_now` findings, the failing tests and the files the coder never submitted go into one fix round. Fix rounds are one per block: wait for every `review-file` ticket of the block and its tests, then send ONE fix message with every failing test and every open finding; a finding that arrives later waits for the next round (`code.md` §4). Dispatch that message as one new `Agent` call at the level the ladder says (`review.md` §5 — the coder is gone with its tool return, so the fix brief carries every failing test, every open finding and the fix history). Its brief says: in that round the coder fixes, runs the block's tests, re-runs `review-file` on every changed file, and prints its `TESTS` line. One block round is one round for each file it touched. Rounds are bounded: four rounds per file, then the L3 rung once, then `stopped: review_cap` for the human. Only when every changed file has a signed `review.approved` row do you run the re-measurement of `code.md` §5 and `forge block close <id> --run <r> --report <file>` (the subagent's final report, saved to a file) — the transcript grep reads `.code-forge/runs/<run>/<block>.log`; pass `--transcript <file>` when the harness saved the subagent's transcript elsewhere. Closing with a file still unreviewed
|
|
15
|
+
**Between completion and close come the review rounds.** The subagent ran `forge review-file <path> --block <id> --run <r>` per file and `--wait`ed on each ticket inside its turn, so most rounds happen before the sentinel; when the tool returns, first drain every `pending` ticket with `forge review-file --wait <ticket>` yourself — a pending ticket is a review in flight, not an open finding, and waiting on it costs no round. Then the open `fix_now` findings, the failing tests and the files the coder never submitted go into one fix round. Fix rounds are one per block: wait for every `review-file` ticket of the block and its tests, then send ONE fix message with every failing test and every open finding; a finding that arrives later waits for the next round (`code.md` §4). Dispatch that message as one new `Agent` call at the level the ladder says (`review.md` §5 — the coder is gone with its tool return, so the fix brief carries every failing test, every open finding and the fix history). Its brief says: in that round the coder fixes, runs the block's tests, re-runs `review-file` on every changed file, and prints its `TESTS` line. One block round is one round for each file it touched. Rounds are bounded: four rounds per file, then the L3 rung once, then `stopped: review_cap` for the human. Only when every changed file has a signed `review.approved` row do you run the re-measurement of `code.md` §5 and `forge block close <id> --run <r> --report <file>` (the subagent's final report, saved to a file) — the transcript grep reads `.code-forge/runs/<run>/<block>.log`; pass `--transcript <file>` when the harness saved the subagent's transcript elsewhere. Closing with a file still unreviewed needs an audited waiver. Use `forge block waive <id> <finding> --run <r> --file <path> --reason "<why>"` per finding. The human can also use `forge block close … --no-require-reviews` at a terminal. That path asks for a yes. An active autopilot grant refuses it. `forge block reopen <id> --file <path> --run <r> --reason "<why>"` does not close anything: it sends a fixed stopped file back to review. Without `--yes` it asks for a yes at a terminal. The orchestrator prints the command for the human paths of `block reopen` and `block waive`. The orchestrator may run `block reopen --yes` with evidence and agreement from a fresh judge, at most once per block and file in a run. The orchestrator may run `block waive --yes` only for a recorded warning or nit finding with evidence and agreement from a fresh judge. A coder never runs either verb. The prompt checks only that stdin and stdout are terminals; a pseudo-terminal passes it, so it does not prove a human (`security.md` §3).
|
|
16
16
|
|
|
17
17
|
## §2.1 Plan approval
|
|
18
18
|
|
|
@@ -22,7 +22,7 @@ Solo adds spawn, watch, timers, scratchpads, locks and `kv` on top of the CLI; i
|
|
|
22
22
|
5. **Wake channels, event-driven, never fixed polls:** record your own pid once (`whoami` → `kv_set("forge:orchestrator_pid")`); coders that can call Solo carry the push contract (post-sentinel `kv_set("block:<id>", …)` + `timer_set(1s, body, delivery_process_id=<your pid>)`); for every group arm `timer_fire_when_idle_any([coders], max_wait≈20–25 min, delivery_process_id=<your pid>)` right after the launch gate (idle-any ignores already-idle processes, so arm while they are provably running); keep one long dead-man fallback per 30–40 min with an L0 triage first. On wake: sentinel ⇒ gate; no sentinel and active again ⇒ re-arm; no sentinel and idle ⇒ parked, intervene now.
|
|
23
23
|
6. Completion = `search_output(pattern="===BLOCK <id> COMPLETE===")`, last occurrence (the `kv` key is the truncation backup). Completion is not closure.
|
|
24
24
|
7. **Review rounds, with the coder still alive.** The coder ran `forge review-file <path> --block <id> --run <r>` per file and `--wait`ed on each ticket; read the ledger (`forge ledger tail --slug <slug>`) for what is still open — a `fix_now` finding, a `pending` ticket, a file never submitted. After the coder's first COMPLETE, wait until every `review-file` ticket of the block is answered and the block's tests ran; then send ONE fix message with every failing test (name and first error line) and every open finding (by file and id). Never one finding or one file at a time. A finding that arrives after that message waits for the next round. In that round the coder fixes, runs the block's tests, re-runs `review-file` on every changed file, and prints its `TESTS` line. The message goes to the **warm coder** by `send_input`, ending in `<<<EOM>>>`; when it is over the input limit (§1), write it to a file and send its path. Round ≥ 2 re-checks only the fix hunks (`review.md` §5), and one block round is one round for each file it touched. **One ladder** (`decisions.md` §5): a stall or exhausted rounds *below L2* climbs one level — close this coder and respawn a fresh one at the higher level with the open findings and the fix history in its brief; **the respawn keeps the per-file round count**, the cap does not reset. L2 is the highest running level: a trigger at L2, or the four-round cap on a file, goes to the **L3 rung once** — a fresh L3 patch session, never this coder and never a coder at L3 — and if findings stay open after the `patch_check` round the file is `stopped: review_cap` for the human. No other path exists.
|
|
25
|
-
8. **Close** only when every changed file has a signed `review.approved` row: the re-measurement of `code.md` §5, then `forge block close <id> --run <r> --report <file>` (the coder's final report) — the transcript grep reads the Solo output. Closing with a file still unreviewed
|
|
25
|
+
8. **Close** only when every changed file has a signed `review.approved` row: the re-measurement of `code.md` §5, then `forge block close <id> --run <r> --report <file>` (the coder's final report) — the transcript grep reads the Solo output. Closing with a file still unreviewed needs an audited waiver. Use `forge block waive <id> <finding> --run <r> --file <path> --reason "<why>"` per finding. The human can also use `forge block close … --no-require-reviews` at a terminal. That path asks for a yes. An active autopilot grant refuses it. `forge block reopen <id> --file <path> --run <r> --reason "<why>"` does not close anything: it sends a fixed stopped file back to review. Without `--yes` it asks for a yes at a terminal. Under an active autopilot grant the human paths still prompt. Autopilot's own waive path, `forge autopilot waive` (`by: autopilot`), needs no terminal. The orchestrator prints the command for the human paths of `block reopen` and `block waive`. The orchestrator may run `block reopen --yes` with evidence and agreement from a fresh judge, at most once per block and file in a run. The orchestrator may run `block waive --yes` only for a recorded warning or nit finding with evidence and agreement from a fresh judge. A coder never runs either verb. The prompt checks only that stdin and stdout are terminals; a pseudo-terminal passes it, so it does not prove a human (`security.md` §3).
|
|
26
26
|
9. **Reap after the close**: `close_process` the coder and confirm `lock_status` shows no lease before the next group. Locks: a coder that can call Solo holds `lock_acquire` on its file area while editing; coders that cannot never overlap another block.
|
|
27
27
|
|
|
28
28
|
## §4 Latency overlaps (standing)
|