feat(trekexecute): every MAJOR answered before merge, fixed runs the fix loop
This commit is contained in:
parent
635003e8aa
commit
9e7e8d1516
15 changed files with 376 additions and 30 deletions
|
|
@ -2286,11 +2286,16 @@ never typed by the operator, in this order (Cherny's):
|
|||
`--repo .` checks that an ALLOW/WARN review is of the commit being merged:
|
||||
its `scope_sha_end` is HEAD, or an ancestor of HEAD whose later commits
|
||||
change only the review lessons and the `CLAUDE.md` pointer (step 3's
|
||||
commit). Record `review = {round, path, gate_exit, verdict}`. Exit 0
|
||||
commit), or only append the review answer records (K2 `review` records,
|
||||
`/trekreview` Phase 8.8) to the top-level approval log. Record `review = {round, path, gate_exit, verdict}`. Exit 0
|
||||
(ALLOW/WARN) → Phase 7.5. Exit 2 (could not decide, a reviewer or engine
|
||||
that did not run, or a reason that starts `review-stale`: a review of
|
||||
another commit) → Phase 7.5 with the merge closed: never green. Exit 1
|
||||
(BLOCK) → the loop below.
|
||||
Exit 2 with a reason that starts `review-unanswered: fixed-pending` enters
|
||||
the loop below, as a BLOCK does. The loop's R-steps are then the BLOCKER
|
||||
steps plus each MAJOR answered "fixed". Any other `review-unanswered:` goes
|
||||
to Phase 7.5 with the merge closed.
|
||||
|
||||
**A BLOCK is fixed by new plan steps, in a bounded loop.** The review writes
|
||||
every BLOCKER as a numbered `### Step R<n>` under `## Remediation Steps`
|
||||
|
|
@ -2332,8 +2337,9 @@ the run is `stopped`, and the merge stays closed.
|
|||
steps ({first error code}) and that the way on is a re-plan from the review,
|
||||
`/trekplan --brief {project_dir}/review.md`.
|
||||
4. The plan changed, so its approval is stale (Phase 1). Ask for it again in
|
||||
one question, `AskUserQuestion`: **"The review blocked: {N} BLOCKER(s),
|
||||
added as steps {list}. Approve the plan as it is now?"** Options:
|
||||
one question, `AskUserQuestion`: **"The review asked for fixes: {N}
|
||||
BLOCKER(s) and {M} MAJOR(s) answered "fixed", added as steps {list}.
|
||||
Approve the plan as it is now?"** Options:
|
||||
**Approve** / **Not yet**. Check the answer with
|
||||
`approval-log.mjs answer` (stdin) exactly as `/trekplan` Phase 11 does;
|
||||
exit 0 → `approval-log.mjs append --kind plan --subject "{plan_path}" --sha256-of "{plan_path}"`
|
||||
|
|
@ -2353,8 +2359,10 @@ reviews per run (the first and two fix loops), read with
|
|||
`node ${CLAUDE_PLUGIN_ROOT}/lib/review/review-rounds.mjs --cap`; `/trekreview`
|
||||
reads the same constant and refuses a fourth round.
|
||||
A review at the cap with BLOCKERs or MAJORs answered "fixed" still open goes to the operator: stop, and the report names every one.
|
||||
Each loop also takes 1 from `iterations_remaining`, which
|
||||
bounds it a second time (the completion gate's clause 3 counts it).
|
||||
Each loop, WARN or BLOCK, takes 1 from `iterations_remaining`, which bounds
|
||||
it a second time (the completion gate's clause 3 counts it), and the next
|
||||
`/trekreview` is a new round counted against the cap, not a new remediation
|
||||
round (decision 101).
|
||||
|
||||
Borrowed: the order (run the thing, simplify, review) is Cherny's; a verdict in
|
||||
a file that a command gates on, and the bounded fix-and-review loop, are
|
||||
|
|
@ -2383,7 +2391,8 @@ produces an independent truth based on objective state, not self-narrative.
|
|||
number of steps with `status=completed` (excludes Step 0 if sandbox_preflight)
|
||||
+ the run's own process commits, and only these: the simplify commit
|
||||
(`refactor: simplify pass (trekexecute)`, when `simplify = "applied"`), each
|
||||
review-lessons commit (`docs(voyage): review lessons (round R)`) and each
|
||||
review-lessons commit (`docs(voyage): review lessons (round R)`), each
|
||||
review-answers commit (`docs(voyage): review answers (round {R})`) and each
|
||||
plan approval the review loop committed (`docs(voyage): approve plan …`),
|
||||
all from Phase 7.2. Each is named in the audit, never folded in silently.
|
||||
(A remediation step's commit is a completed step like any other; the
|
||||
|
|
@ -2615,7 +2624,7 @@ exit 2 without the call.
|
|||
|
||||
| Exit | Verdict | Merge |
|
||||
|------|---------|-------|
|
||||
| 0 | ALLOW / WARN | open, when the run's result is `completed` (Phase 7.5) |
|
||||
| 0 | ALLOW / WARN (every counting MAJOR answered) | open, when the run's result is `completed` (Phase 7.5) |
|
||||
| 1 | BLOCK | closed |
|
||||
| 2 | not measured | closed: a review that could not decide is never green |
|
||||
|
||||
|
|
@ -2623,19 +2632,23 @@ exit 2 without the call.
|
|||
Exit 2 with a reason that starts `review-stale` is closed with the decline
|
||||
reason `review-stale` and the line "re-run /trekreview on this commit": the
|
||||
review is of another commit than this one, or something other than the
|
||||
review lessons and the `CLAUDE.md` pointer changed after it. Any other exit 2
|
||||
is `review-not-measured`. Exit 2 with a reason that starts `review-not-measured:`
|
||||
review lessons and the `CLAUDE.md` pointer changed after it. Exit 2 with a
|
||||
reason that starts `review-unanswered:` is closed with the decline reason
|
||||
`review-unanswered`: a MAJOR has no answer, or an answer "fixed" no later round
|
||||
has confirmed. Any other exit 2 that does not start `review-stale` or
|
||||
`review-unanswered:` is `review-not-measured`. Exit 2 with a reason that starts `review-not-measured:`
|
||||
(the `--repo` path is missing, it is no git repository, or a git call failed)
|
||||
is reported as "not measured", never green, and the merge stays locked with
|
||||
the decline reason `review-not-measured`.
|
||||
|
||||
The merge runs only on exit 0 and a `completed` result. **Closed:** emit
|
||||
`main-merge-declined` with the reason `review-block`, `review-stale`,
|
||||
`review-not-measured` or `run-not-completed`. Nothing is finalized: a `completed` result becomes
|
||||
`review-unanswered`, `review-not-measured` or `run-not-completed`. Nothing is finalized: a `completed` result becomes
|
||||
`partial` (`failed` and `stopped` stay), and the commits stay where they are
|
||||
for review. Say in one line why it is closed and what opens it: the
|
||||
BLOCKERs fixed through Phase 7.2's loop, a review that runs in full, a review
|
||||
of this commit, or a run that completes.
|
||||
of this commit, an answer per MAJOR (`/trekreview --answers --project {project_dir}`,
|
||||
no new round) or a review round that finds it fixed, or a run that completes.
|
||||
|
||||
**2. Open: the merge, and the one question.** Find the run's branch and where
|
||||
main is checked out, in a Bash call of its own:
|
||||
|
|
@ -2739,7 +2752,7 @@ JSON
|
|||
```
|
||||
|
||||
The reason is one of the literal words above (`review-block`,
|
||||
`review-stale`, `review-not-measured`, `run-not-completed`, `no-main-branch`, `hold-for-review`,
|
||||
`review-stale`, `review-unanswered`, `review-not-measured`, `run-not-completed`, `no-main-branch`, `hold-for-review`,
|
||||
`merge-conflict`, `merge-refused`), never the operator's free text (free text breaks the JSON).
|
||||
|
||||
On decline, nothing is cleared: the merged-waves record is kept.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ description: |
|
|||
Independent post-hoc review of delivered code against the brief. Produces
|
||||
review.md with severity-tagged findings (BLOCKER/MAJOR/MINOR/SUGGESTION)
|
||||
per Handover 6 (review → plan).
|
||||
argument-hint: "--project <dir> [--since <ref>] [--quick] [--validate] [--dry-run]"
|
||||
argument-hint: "--project <dir> [--since <ref>] [--quick] [--validate] [--dry-run] [--answers]"
|
||||
allowed-tools: Agent, Read, Glob, Grep, Write, Edit, Bash, AskUserQuestion, Skill
|
||||
---
|
||||
|
||||
|
|
@ -33,8 +33,9 @@ inference across files is forbidden in v1.0 (Judge Agent pattern).
|
|||
Claude Code's own `/code-review` and `/security-review` are the engine
|
||||
(Phase 4.7); Voyage's control against the brief runs after them and is the
|
||||
part that stops (Phase 5–6); the verdict is written in `review.md` and one
|
||||
command decides on it (`lib/review/verdict-gate.mjs`, Phase 8: 0 = ALLOW/WARN,
|
||||
1 = BLOCK, 2 = could not decide, never green). No finding is struck for
|
||||
command decides on it (`lib/review/verdict-gate.mjs`, Phase 8: 0 = ALLOW, or
|
||||
WARN with every counting MAJOR answered, 1 = BLOCK, 2 = could not decide,
|
||||
never green). No finding is struck for
|
||||
length. A finding class seen in two reviews becomes one proposal for the
|
||||
project's memory, approved line by line (Phase 8.7). Order credited to Boris
|
||||
Cherny's public workflow (engine → brief control); the gate to Kiro and Spec
|
||||
|
|
@ -69,6 +70,7 @@ FLAG_SCHEMA `trekreview` entry):
|
|||
| `--validate` | boolean | Schema-only check on existing `{project_dir}/review.md`. No LLM calls. |
|
||||
| `--dry-run` | boolean | Print the discovered scope and triage map. Skip writes. |
|
||||
| `--fg` | boolean | No-op alias (foreground is default). |
|
||||
| `--answers` | boolean | Run only Phase 8.8 (the operator's answers to the counting MAJORs) on the existing `{project_dir}/review.md`, then the Phase 8 gate line. No `prepare`, no reviewer, no write of findings: it opens no new round and counts nothing against the cap (decision 93). |
|
||||
| `--workflow` | boolean | **(opt-in, NW2)** Run Phase 5–6 on the bake-off-validated Workflow substrate (`scripts/trekreview-armB.workflow.mjs`) instead of the default prose Agent-tool path. Requires **Claude Code 2.1.154+**. Combines with `--quick`. See *§ Phase 5–6 via the Workflow substrate*. |
|
||||
|
||||
Resolution:
|
||||
|
|
@ -87,6 +89,7 @@ Resolution:
|
|||
|
||||
Set `mode`:
|
||||
- `validate` if `--validate` is set (overrides everything else; skip to Phase 8.5).
|
||||
- `answers` if `--answers` is set: skip to Phase 8.8.
|
||||
- `dry-run` if `--dry-run` is set.
|
||||
- `quick` if `--quick` is set.
|
||||
- `default` otherwise.
|
||||
|
|
@ -733,14 +736,17 @@ If validation fails:
|
|||
node ${CLAUDE_PLUGIN_ROOT}/lib/review/verdict-gate.mjs "{review_path}"
|
||||
```
|
||||
|
||||
Exit 0 = ALLOW or WARN; exit 1 = BLOCK; exit 2 = the gate could not decide
|
||||
Exit 0 = ALLOW, or WARN with every counting MAJOR answered; exit 1 = BLOCK;
|
||||
exit 2 = the gate could not decide
|
||||
(missing verdict, a verdict the file contradicts — in its JSON block, its
|
||||
`## Findings (BLOCKER)` section or its finding-id list — a JSON block that is
|
||||
not the last fence or has the wrong shape, two verdict lines, unreadable
|
||||
file) — **never green**. A WARN that exists because a reviewer or engine
|
||||
did not run (`missing-reviewer:` / `unattributable-payload` in
|
||||
`allow_blocked_by`) is also exit 2: a review not performed in full stops a
|
||||
merge (operator decision 2026-10-06). It takes exactly one file. On exit 0
|
||||
merge (operator decision 2026-10-06). An exit 2 with a reason that starts
|
||||
`review-unanswered:` before Phase 8.8 is expected: the operator's answers come
|
||||
there. It takes exactly one file. On exit 0
|
||||
with WARN, `--json` also returns `warn_reasons` (the JSON block's
|
||||
`allow_blocked_by`); print them. Capture the exit code as `gate_exit` and print it in Phase 9 exactly
|
||||
as returned. This is the command that later stops a merge or a release on
|
||||
|
|
@ -849,6 +855,67 @@ the managed block (Spec Kit `agent-context`), evidence per proposal and
|
|||
schema-check before write (Kiro), review → memory and the size budget
|
||||
(Cherny). Credits in `lib/review/recurrence.mjs`.
|
||||
|
||||
## Phase 8.8 — Answers
|
||||
|
||||
**Skipped in `dry-run` and `validate`.** Every counting MAJOR needs the
|
||||
operator's answer before a WARN opens the merge or the release; the verdict
|
||||
gate decides that, not this command. List the open ones:
|
||||
|
||||
```bash
|
||||
node ${CLAUDE_PLUGIN_ROOT}/lib/review/review-answers.mjs pending --review {project_dir}/review.md --json
|
||||
```
|
||||
|
||||
- Exit 0: nothing to ask.
|
||||
- Exit 2: say "answers not measured" in one line; the merge stays closed.
|
||||
- Exit 1: it lists the open MAJORs (`id`, `title`, `detail`, `security`,
|
||||
`fixed_pending`). Ask about each one with `AskUserQuestion`, at most four per
|
||||
call and one finding per question, in plain words with no file or function
|
||||
names. Each question gives the consequence of each option:
|
||||
- **Fix it**: a plan step is written, and the merge stays closed until a
|
||||
later review round no longer finds it.
|
||||
- **Accept: <a reason in plain words>**: the merge can open with this
|
||||
finding left as it is. Never offered for a finding `pending` marks
|
||||
`security: true`. That finding gets one option, Fix it, and its question says a security finding cannot be accepted.
|
||||
|
||||
The recommendation is the session's honest judgement per finding. It is
|
||||
never "accept" by default. The operator may type their own reason; a hollow
|
||||
answer ("sounds good", "do as you like") is not a reason.
|
||||
|
||||
For each answer, a "fixed" first gets its `### Step R<n>` under
|
||||
`## Remediation Steps`, in the form Phase 7 writes for a BLOCKER (Files,
|
||||
Source finding, Test first, Verify, On failure). Then record it, with the
|
||||
reason on stdin:
|
||||
|
||||
```bash
|
||||
node ${CLAUDE_PLUGIN_ROOT}/lib/review/review-answers.mjs record --review "{project_dir}/review.md" --finding {id} --answer {accepted|fixed} --repo . --round {R} --store {artifact_store} --trailer "Co-Authored-By: Claude {model} <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
`{R}` is this review's round (Phase 3's `{round}`), `{artifact_store}` the
|
||||
brief's `artifact_store` (absent = `local`), and `{model}` this session's model
|
||||
name. It appends a K2 `review` record, writes the `## Answers` row and commits
|
||||
the log as `docs(voyage): review answers (round {R})`; show the operator the
|
||||
stored reason it returns. On `"committed": false`, print its reason in one
|
||||
line and continue: the answer is logged but not committed. On exit 1 (a
|
||||
hollow or empty reason, a "fixed" without its R-step, an accept on a security
|
||||
finding), say the refusal in one line and ask that finding again once. A
|
||||
second refusal leaves it unanswered. On exit 2, say "answer not recorded" with
|
||||
its reason in one line.
|
||||
|
||||
Then run the Phase 8 gate line again and report its result as `gate_exit`.
|
||||
|
||||
Run on its own, outside `/trekexecute`, "fixed" leaves the finding open until a
|
||||
later `/trekreview` round marks it resolved.
|
||||
|
||||
**`--answers` mode.** `/trekreview --answers --project <dir>` runs only this
|
||||
phase on the existing `{project_dir}/review.md`, and then the Phase 8 gate
|
||||
line. It runs no `prepare`, no reviewer and no write of findings, so it opens
|
||||
no new round and counts nothing against the cap (decision 93: accepting needs
|
||||
no new review round). When `{project_dir}/review.md` is missing it stops with
|
||||
one line: "no review to answer: {project_dir}/review.md is missing". In this
|
||||
mode `--round` is the review's own `round` field (1 when absent), and
|
||||
`--store` is the brief's `artifact_store` (absent = `local`), read from the
|
||||
brief as Phase 1 finds it.
|
||||
|
||||
## Phase 9 — Present summary
|
||||
|
||||
After the write succeeds, print:
|
||||
|
|
@ -864,7 +931,7 @@ After the write succeeds, print:
|
|||
**Annotation HTML:** file://{$ANNOT_HTML}
|
||||
**Scope:** {before_sha}..{after_sha} ({reviewed_files_count} files)
|
||||
**Verdict:** {BLOCK | WARN | ALLOW}
|
||||
**Gate:** verdict-gate exit {gate_exit} ({0 = ALLOW/WARN | 1 = BLOCK | 2 = could not decide, or a control did not run — not green})
|
||||
**Gate:** verdict-gate exit {gate_exit} ({0 = ALLOW, or WARN with every counting MAJOR answered | 1 = BLOCK | 2 = could not decide, a control did not run, or a MAJOR without an answer or answered "fixed" and not yet confirmed — not green})
|
||||
**Engine:** /code-review {delivered N | not run: reason} · /security-review {delivered N | not run: reason}
|
||||
|
||||
### Counts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue