@mrciphersmith/keryx 0.3.117 → 0.3.118

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.
Files changed (29) hide show
  1. package/dist/cli.js +4991 -2874
  2. package/dist/core.js +718 -9
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +1 -1
  5. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +1 -1
  6. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +1 -1
  7. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +1 -1
  8. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +1 -1
  9. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +1 -1
  10. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +1 -1
  11. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +1 -1
  12. package/src/gdskills/bundled/skills/review/review-jev-comments/SKILL.md +1 -1
  13. package/src/gdskills/bundled/skills/review/review-jev-contract/SKILL.md +1 -1
  14. package/src/gdskills/bundled/skills/review/review-jev-docs/SKILL.md +1 -1
  15. package/src/gdskills/bundled/skills/review/review-jev-risk/SKILL.md +1 -1
  16. package/src/gdskills/bundled/skills/review/review-jev-rules/SKILL.md +1 -1
  17. package/src/gdskills/bundled/skills/review/review-jev-scenarios/SKILL.md +1 -1
  18. package/src/gdskills/bundled/skills/review/review-layout/SKILL.md +1 -1
  19. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +1 -1
  20. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +95 -10
  21. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +37 -37
  22. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +1 -1
  23. package/src/gdskills/bundled/skills/review/review-pr-contract/SKILL.md +1 -1
  24. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +1 -1
  25. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +1 -1
  26. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +1 -1
  27. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +1 -1
  28. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +1 -1
  29. package/src/gdskills/bundled/skills/review/review-verifier/SKILL.md +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.117",
3
+ "version": "0.3.118",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -26,7 +26,7 @@ license: "MIT"
26
26
 
27
27
  Specialized reviewer for **architectural patterns and structural decisions**.
28
28
  Reviews only changes introduced in the current branch (merge-base to HEAD).
29
- Focuses exclusively on verifiable structural violations — not style opinions or hypothetical concerns.
29
+ Focuses exclusively on verifiable structural violations — not style opinions or hypothetical concerns. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
30
30
 
31
31
  ---
32
32
 
@@ -26,7 +26,7 @@ license: "MIT"
26
26
 
27
27
  Focused backend reviewer covering NestJS patterns, REST API design, database access patterns,
28
28
  and TypeScript correctness for service-layer code. This skill does NOT duplicate security or
29
- performance checks — those belong to `review-security-code` and `review-performance`.
29
+ performance checks — those belong to `review-security-code` and `review-performance`. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
30
30
 
31
31
  ---
32
32
 
@@ -27,7 +27,7 @@ license: "MIT"
27
27
  # Review: Clean Code + SOLID
28
28
 
29
29
  Specialized reviewer for **Clean Code principles** (Robert C. Martin) and **SOLID** at the
30
- function and class level. Focuses on code in the current branch diff only.
30
+ function and class level. Focuses on code in the current branch diff only. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
31
31
 
32
32
  The goal is not stylistic nitpicking — every finding here points to a concrete
33
33
  maintainability, readability, or extensibility problem that will cause friction
@@ -24,7 +24,7 @@ license: "MIT"
24
24
  # Review — Core Boundaries
25
25
 
26
26
  Reviewer for shared infrastructure modules. A core module should provide stable foundations
27
- used by feature modules; it should not accumulate feature-specific behaviour.
27
+ used by feature modules; it should not accumulate feature-specific behaviour. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
28
28
 
29
29
  ---
30
30
 
@@ -24,7 +24,7 @@ license: "MIT"
24
24
  # Review — Flow Graph Abstractions
25
25
 
26
26
  Reviewer for reusable ReactFlow/graph integration layers. Use it when a repository has a shared
27
- graph surface consumed by domain modules.
27
+ graph surface consumed by domain modules. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
28
28
 
29
29
  ---
30
30
 
@@ -21,7 +21,7 @@ license: "MIT"
21
21
 
22
22
  ## Purpose
23
23
 
24
- Validates frontend-specific patterns in the changed code of the current branch. Covers React component correctness (observer wrapping, MVVM boundary, useEffect misuse, accessibility basics, key props), full MobX store patterns (structure, member ordering, accessibility modifiers, observable collections, reactions, async actions, bidirectional sync, lifecycle, API placement), and TypeScript safety.
24
+ Validates frontend-specific patterns in the changed code of the current branch. Covers React component correctness (observer wrapping, MVVM boundary, useEffect misuse, accessibility basics, key props), full MobX store patterns (structure, member ordering, accessibility modifiers, observable collections, reactions, async actions, bidirectional sync, lifecycle, API placement), and TypeScript safety. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
25
25
 
26
26
  This skill consolidates what was previously split between `code-style-review` (frontend parts) and `code-mobx-store-review`. It supersedes both for frontend changes.
27
27
 
@@ -28,7 +28,7 @@ license: "MIT"
28
28
 
29
29
  Reviewer for frontend repository conventions that are more specific than generic React/MobX
30
30
  correctness. Use it alongside `review-frontend`, `review-style`, `review-performance`, and
31
- `review-logic`.
31
+ `review-logic`. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
32
32
 
33
33
  Before reviewing, read the nearest project guide files if they exist: root `CLAUDE.md`,
34
34
  `AGENTS.md`, `.junie/guidelines.md`, `ARCHITECTURE.md`, and module-level `CLAUDE.md` files.
@@ -28,7 +28,7 @@ license: "MIT"
28
28
 
29
29
  Specialized reviewer for **code that will run under significant concurrent load**.
30
30
  Focuses on correctness under concurrency, resource contention, back-pressure, failure
31
- modes at scale, and distributed systems invariants — not general performance profiling.
31
+ modes at scale, and distributed systems invariants — not general performance profiling. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
32
32
 
33
33
  Reviews only changes introduced in the current branch (merge-base to HEAD).
34
34
 
@@ -34,7 +34,7 @@ LLM sub-agent: `review-orchestrator` never dispatches a platform-native agent
34
34
  for it, it runs `keryx review jev-comments` and reads the `--json` output.
35
35
  Every finding is composed by keryx; Jev ("System One" on OpenRouter) supplies
36
36
  only a `choice` label per comment — it never writes prose, and nothing it
37
- returns is quoted verbatim into a finding.
37
+ returns is quoted verbatim into a finding. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
38
38
 
39
39
  ---
40
40
 
@@ -35,7 +35,7 @@ An ADDITIONAL orchestrator reviewer, flow 335. It is a **keryx program**, not
35
35
  an LLM sub-agent: `review-orchestrator` never dispatches a platform-native
36
36
  agent for it, it runs `keryx review jev-contract` and reads the `--json`
37
37
  output. Every finding is composed by keryx; Jev ("System One" on OpenRouter)
38
- supplies only one `noul` probability per claim — never prose.
38
+ supplies only one `noul` probability per claim — never prose. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
39
39
 
40
40
  ---
41
41
 
@@ -35,7 +35,7 @@ LLM sub-agent: `review-orchestrator` never dispatches a platform-native agent
35
35
  for it, it runs `keryx review jev-docs` and reads the `--json` output. Every
36
36
  finding is composed by keryx; Jev ("System One" on OpenRouter) supplies only a
37
37
  `noul` staleness probability per doc section — it never writes prose, and
38
- nothing it returns is quoted verbatim into a finding.
38
+ nothing it returns is quoted verbatim into a finding. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
39
39
 
40
40
  ---
41
41
 
@@ -33,7 +33,7 @@ an LLM sub-agent: `review-orchestrator` never dispatches a platform-native
33
33
  agent for it, it runs `keryx review jev-risk` and reads the `--json` output.
34
34
  Every finding is composed by keryx; Jev ("System One" on OpenRouter) supplies
35
35
  only five `noul` probabilities per hunk — one per risk dimension — never
36
- prose.
36
+ prose. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
37
37
 
38
38
  ---
39
39
 
@@ -37,7 +37,7 @@ for it, it runs `keryx review jev-rules` and reads the `--json` output. Every
37
37
  finding is composed by keryx; Jev ("System One" on OpenRouter) supplies only a
38
38
  `noul` probability per `(hunk, rule clause)` pair — it never writes prose, and
39
39
  nothing it returns is quoted verbatim into a finding except the clause text
40
- keryx already had.
40
+ keryx already had. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
41
41
 
42
42
  ---
43
43
 
@@ -34,7 +34,7 @@ An ADDITIONAL orchestrator reviewer, flow 332. It is a **keryx program**, not
34
34
  an LLM sub-agent: `review-orchestrator` never dispatches a platform-native
35
35
  agent for it, it runs `keryx review jev-scenarios` and reads the `--json`
36
36
  output. Every finding is composed by keryx; Jev ("System One" on OpenRouter)
37
- supplies only one `noul` probability per scenario — never prose.
37
+ supplies only one `noul` probability per scenario — never prose. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
38
38
 
39
39
  ---
40
40
 
@@ -25,7 +25,7 @@ license: "MIT"
25
25
 
26
26
  # Review — Layout
27
27
 
28
- Reviewer for what the CSS actually renders.
28
+ Reviewer for what the CSS actually renders. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
29
29
 
30
30
  This lane exists because nobody else owns it. `review-frontend` owns React and
31
31
  MobX structure; `review-style` explicitly excludes everything but naming and
@@ -27,7 +27,7 @@ license: "MIT"
27
27
 
28
28
  Specialized reviewer for **logic correctness and algorithmic soundness**.
29
29
  Inherits from the original `code-ai-review` + `code-learned-review` correctness phases
30
- and unifies them into a single focused pass.
30
+ and unifies them into a single focused pass. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
31
31
 
32
32
  This reviewer does not care about formatting, naming, or architecture opinions.
33
33
  Every finding must describe an observable, reproducible defect or a spec gap.
@@ -326,7 +326,7 @@ model: `docs/docs/jev-in-review.md`.
326
326
  reviewer above: it never produces a `findings` array of its own, and it is
327
327
  never merged into the consolidated array. It runs AFTER the Sub-Agent Report
328
328
  Quality Gate has already validated/merged/deduplicated the round's findings
329
- (Step 9) and BEFORE Wave C verification (Step 10) — Step 9b in the Workflow
329
+ (Step 9) and BEFORE the later Wave C passes (Step 10; the early verifier pass starts first, on the findings held then) — Step 9b in the Workflow
330
330
  block — annotating the findings that already exist. It is advisory and
331
331
  annotate-only by construction: nothing it returns drops or demotes a finding,
332
332
  and no downstream step is permitted to treat its output as anything but a
@@ -353,7 +353,7 @@ differently in the report:
353
353
  |---|---|---|
354
354
  | `severity_check` | `{id, p, flagged}` per blocker/major finding — `flagged` means `p < 0.4` | Show `flagged` findings as a soft note next to their existing severity ("Jev's own trigger+outcome check scored this low"). Never change the finding's `severity` field from this alone. |
355
355
  | `merge_candidates` | `{id, a, b, reason, p}` per candidate pair | A high `p` is a suggestion to a human that `a` and `b` may be the same defect — surface it in the report as a note on both findings. Never merge, drop, or renumber either finding from this alone. |
356
- | `verify_order` | `{id, p}`, sorted lowest-`p`-first | Feed this order into Wave C's own dispatch — verify the lowest-plausibility findings first — never as a reason to skip verifying any of them. |
356
+ | `verify_order` | `{id, p}`, sorted lowest-`p`-first | Feed this order into the later Wave C passes — verify the lowest-plausibility findings first — never as a reason to skip verifying any of them. |
357
357
 
358
358
  `status` is `DONE_WITH_CONCERNS` — never `DONE` — when any `severity_check` is
359
359
  `flagged` OR any `merge_candidates` pair scores `p >= 0.5`
@@ -369,6 +369,26 @@ itself draws between a reviewer's claim (`severity`, `problem`, …) and what
369
369
  became of it (`disposition`), which a reviewer never states and this pass
370
370
  does not either.
371
371
 
372
+ ## Clean context — why, the log, the three accepted paths
373
+
374
+ A review must be reproducible from its package: the same inputs give the same context, whoever runs it and whatever that agent remembers from earlier work. So the round starts empty and every input has a named source.
375
+
376
+ **Inputs.** Only the orchestrator's context stages (scope, Review Context Pack, the memory stage, layers) and, for a reviewer, its payload. The agent's session memory, the auto-memory index (`MEMORY.md`), remembered feedback and the earlier conversation are not inputs, and neither is a second memory search made "to double-check".
377
+
378
+ **The three accepted paths** are known and kept on the operator's decision (poll 179), not leaks:
379
+
380
+ 1. `prior_findings` — findings of an earlier round of the same package enter by design from round 2 on.
381
+ 2. Review-notes and skill learning — auto-accepted output of earlier reviews reaches a later one only through the memory stage, as accepted memory.
382
+ 3. A reviewer's `memory_search` — the reviewer agents keep it as a lookup in the project's recorded lessons.
383
+
384
+ **One memory read, and the log.** The stage query is `keryx memory search "<changed modules and the concepts they touch>" --status accepted`, once. Pass the same text to `keryx review start … --memory-query "<query>"` so the manifest's `cleanContext` block holds it next to the start time. keryx writes the orchestrator log, `<package>/tool-calls/orchestrator.jsonl`, on its own: `keryx review start` and `keryx review attach` mark the package active, and every `keryx memory` command and every MCP memory tool (`memory_search`, `memory_handoff`, `memory_propose`) appends one line naming its caller. You do not write that file and must not edit it; a hand-written line is a forgery the readiness item cannot tell apart from a record. A call by a `spawn_subagent` child is recorded under the child's reviewer id and is not judged by item 10. A call from a host that names no caller is recorded as `unattributed`: it warns in the item's detail line and never blocks. Reviewer logs stay in their own files.
385
+
386
+ Item 10, `memory-outside-stage`, reads that log. Outside the stage is: a memory search with a different query, a search without `--status accepted`, any other memory command or MCP memory tool, and a stage call stamped before the round started. The same query repeated is the stage. Repair is to rerun from a session whose only memory read is the stage; only `keryx review complete <package> --waive memory-outside-stage "<operator quote>"` from a terminal lifts it. With no orchestrator log the item passes and its evidence says it could not see your reads; with a log that holds no memory call it passes and says so. Only calls that go through keryx are visible: a read through a tool keryx does not wrap is not in the log.
387
+
388
+ **Open questions.** One general rule, replacing per-fork wording: the answer is in this skill or `SKILL.detail.md`, or it is the user's. Interactive: one `AskUserQuestion`. Unattended: the whole output is one line, `STATUS: BLOCKED question — <the question>`, and you stop. A guess and a recollection are both wrong answers.
389
+
390
+ **Named limit.** An agent runtime that loads its memory before this skill starts cannot be prevented by keryx. The guarantee is instruction plus detection, not isolation, and reads of the agent's personal memory outside `keryx memory` are not visible to the log.
391
+
372
392
  ## Start questions (Step 5) — once per round, after the context pack
373
393
 
374
394
  The round asks its operator three questions, once, in one interaction, after
@@ -379,8 +399,9 @@ three questions; on any other host, the lettered prompt below. An unattended
379
399
  round (job pipeline, trigger, schedule) asks nothing, applies the defaults and
380
400
  records them under `### How this review was run`.
381
401
 
382
- 1. **Reviewers** — default `--all`: every reviewer the engine detects plus every
383
- project and convention reviewer its gates admit. Narrowing is an explicit
402
+ 1. **Reviewers** — default the set `keryx review required --depth auto` prints
403
+ (light, or the full set the engine detects plus every project and convention
404
+ reviewer its gates admit); `--all` only when the operator asks. Narrowing is an explicit
384
405
  choice (tests only, one domain, a custom list). Flags the caller passed
385
406
  answer this question and skip it. Convention reviewers are part of this
386
407
  question; the job setting `convention_reviewers` still answers it in a
@@ -450,7 +471,17 @@ selected.
450
471
  filed six real findings, every one reachable from the diff and the backend at
451
472
  a pinned SHA.
452
473
  - **Size never lowers depth below the risk class.** The budget table sizes the
453
- context, not the depth.
474
+ context, not the depth. Outside the risk class a small change does not need the
475
+ whole roster: `keryx review required --depth auto` picks the **light** round —
476
+ `review-logic`, `review-testing-practices` and the stack-conventions reviewer
477
+ only — when the diff is at most 5 files and 300 changed lines, matches no risk
478
+ path gate, and is neither `--all` nor gating. Auto needs a file list AND a line
479
+ count: `--scope <scope.json>` gives both (`review start|ingest --scope` stores
480
+ the count in `scope-files.json`, so `--package <review-dir>` has both too);
481
+ with either missing the round is full. Light is only ever granted by those auto
482
+ checks; `--all`, gating and `--depth full` force full. A light round records `Not run: mutation
483
+ (light round)` instead of the mutation gate and says so in the report. Inside the
484
+ risk class the round is full.
454
485
  - **High-risk includes a client-side mirror of a server rule** — validation,
455
486
  limits, permissions, uniqueness, reserved names — beside the triggers the main
456
487
  file lists.
@@ -616,6 +647,22 @@ nothing moved. The final round recomputes whatever the file set did — otherwis
616
647
  fix introduced in round 3 gets no regression check at all, and the round that
617
648
  certifies the flow is the one that checked the least.
618
649
 
650
+ ## Readiness — the checklist behind `completed` and behind publishing
651
+
652
+ `keryx review readiness <review-id-or-path> [--json]` reads the package and prints nine items, READY or NOT READY, each with the evidence and the command that repairs it. It writes nothing, and exits non-zero when the verdict is NOT READY. Only item 9 reaches GitHub (the PR's own file list); the TUI and `review status` read the package alone.
653
+
654
+ 1. `files-covered` — every changed file is in a wave or carries a recorded waiver.
655
+ 2. `blast-radius` — no file the blast radius cut is left unreviewed. A cut radius writes `chunks.json`; run `keryx review chunks plan`, `estimate`, `next`/`record`, `merge`. In an unattended run every wave runs without a question, up to the 25-pass ceiling; in an interactive run the operator is asked once.
656
+ 3. `reviewers` — every planned reviewer was dispatched and its result ingested.
657
+ 4. `verifier` — the verifier checked every finding it should, or the report says how many it did not.
658
+ 5. `ledger` — the ledger is READY.
659
+ 6. `coverage-md` — coverage.md does not list a reviewer as `run` that the dispatch record says did not finish. Re-run `keryx review ingest` for the package.
660
+ 7. `head` — the report's head is the PR head.
661
+ 8. `report-names` — pending mutation candidates and parity warnings are named in the report.
662
+ 9. `pr-files` — the changed-file count equals the PR's own file list. A recount more than 3x the recorded scope is refused: it came from the wrong base. Recount with `keryx review blast-radius --package <ref> --changed <the PR's files>`.
663
+
664
+ `keryx review complete` refuses status `completed` while any item fails. A failing item is waived only by the operator, in a terminal: `keryx review complete --waive <item> "<their own words>"`, repeatable; the waiver is recorded with the quote and the time. `keryx review publish` is held by the same checklist. A not-ready package goes to GitHub only through `keryx review publish --partial`, which puts a "Partial review" header on the post and never approves. The shell guard stops a publish command that runs through the keryx shell; a publisher outside it (CI, another agent, a script file) is not stopped, and that limit is named, not hidden.
665
+
619
666
  ## Fix rounds — dispositions, regressions, withdrawal
620
667
 
621
668
  ### Every prior finding leaves the round with a disposition
@@ -723,17 +770,22 @@ never closes it.
723
770
 
724
771
  A reviewer that argues a finding from a mutant writes `mutant:<id>` in the finding's `evidence`.
725
772
  After the mutation pass run `keryx review severity-audit --package <review-dir>`: a cited mutant
726
- that survived on a file the review changed raises a minor finding to major and records
727
- `severity_audit {from, to, evidence: "mutation-<n>.json#<id>"}`. A finding that cites a mutant no
773
+ that survived on a file the review changed moves a minor finding up to major only when no mutant
774
+ in that file was `killed` (or `timeout`) in any recorded pass, because then nothing in the suite
775
+ exercises the changed behaviour. It records `severity_audit {from, to, evidence: "mutation-<n>.json#<id>"}`.
776
+ When the file has a killed mutant, the suite covers the code, the survivor is a gap in covered
777
+ code, and the severity is held (see below). A survivor shows a missing assertion, not wrong
778
+ behaviour. A finding that cites a mutant no
728
779
  run executed stays minor (a major is capped at minor) and gets the label `unproven`. The audit
729
780
  never deletes a finding and never touches a blocker; it is a separate pass from the verifier,
730
781
  which can only delete. `--dry-run` prints the changes without writing `findings.json`.
731
782
 
732
783
  Each mutant in `mutants.json` carries a `kind`: `behavior` (the default, and what a record written
733
784
  before the field reads as) or `presentation` (it changes only what a reader sees: a label, a
734
- column, copy, spacing). A behavior survivor raises as above. When the only survivors a finding
735
- cites are `presentation`, the severity stays, and the finding gets
736
- `severity_audit {held: {severity, mutant, kind: "presentation", evidence, reason}}` instead of
785
+ column, copy, spacing). A behavior survivor in a file with no killed mutant raises as above. When
786
+ the only survivors a finding cites are `presentation`, or every behavior survivor sits in a file
787
+ with a killed mutant, the severity stays, and the finding gets
788
+ `severity_audit {held: {severity, mutant, kind: "presentation" | "covered", evidence, reason}}` instead of
737
789
  `{from, to}`. A held note is not a raise and not a deletion; it is the record that a survivor was
738
790
  seen and did not move the severity, so the report must say so.
739
791
 
@@ -767,3 +819,36 @@ available) and the backend pins the pull request names (refs on lines that talk
767
819
  Set `pr_context` in every reviewer payload to the `.md` path; reviewers read it before the diff.
768
820
  `keryx review dispatch-check --payload <file> --pr-context` refuses a payload without it
769
821
  (`REVIEWER_INPUT_NO_PR_CONTEXT`).
822
+
823
+ ## Preflight 4 — PR state, depth and estimate before dispatch
824
+
825
+ Two 2026-10-15 rounds took 2 h and 3.5 h. One verdict was ready at minute 55, was held to
826
+ minute 119, and the PR merged first; the other re-dispatched a finished wave and ended at 27 of
827
+ 41 slices. The operator can only act on a risk they were told about.
828
+
829
+ 1. On a PR target read merged / approved / CI (`gh pr view <n> --json state,reviewDecision,statusCheckRollup`). Say in one line what the state means for the round: an approved PR with green CI can merge any minute, and a merged PR makes the rest of the round a post-merge audit.
830
+ 2. **Later, once the package and slices exist** (after `review scope`, `review start` and `review slice`, before the first reviewer starts): `keryx review required --mode all --scope .metaproject/data/review/scope.json --depth auto [--package <review-dir>]` prints the reviewer set and the depth it chose (see "Depth floor"); auto needs the file list and a line count, else the round is full. `keryx review estimate --package <review-dir> [--manifest <slices/manifest.json>]` prints assignments, waves and a duration range; the manifest defaults to `<package>/slices/manifest.json`, then `.metaproject/data/review/slices/manifest.json`.
831
+ 3. Show the operator depth + estimate and the merge risk before the first dispatch. Attended: let them choose `full` over a light default. Unattended: record both in the report and continue.
832
+
833
+ ## Early verdict — the verdict is interim until `complete`
834
+
835
+ As soon as every reviewer result and the verifier's are on disk, save each verifier pass to `research-evidence/verifications.json` first (without it a refuted finding still counts), then run `keryx review verdict <id|path> --raw .metaproject/data/review/raw [--json]` on the shell host, or without `--raw` where the round's raw results sit in `<package>/raw`. It prints the interim verdict and writes `verdict-interim.md` into the package. Give the operator that verdict in the same message; do not hold it for the mutation pass, the ledger or `complete`.
836
+
837
+ The tail keeps running after it: the mutation pass (`keryx review mutate`), `ledger build`, `ingest`, `readiness` and `keryx review complete`. Every managed round finishes them. The round is **not done** until `complete`: the verdict you gave is interim, and the report says so and names what the tail may still change (a surviving mutant, a verifier refutation, a late reviewer result). A light round has no mutation pass: its tail is `ledger build`, `ingest`, `readiness`, `complete`.
838
+
839
+ ## Early verifier — start on the first blocker or major
840
+
841
+ Do not wait for the last reviewer. When the first `blocker` or `major` finding arrives, dispatch `review-verifier` over the findings you hold, while the other reviewers keep running. Each later blocker or major starts another verifier pass over just the new findings (each pass is its own run; Wave C overlaps A and B here, and Step 9b's `verify_order` orders the later passes), so verification finishes within minutes of the last reviewer. The verifier stays delete-only and never verifies a finding its own reviewer raised; the merge still comes from `keryx review ingest --verifications <file>`, once per pass.
842
+
843
+ ## Recovery — collect, validate, ingest, dispatch only what is missing
844
+
845
+ After a timeout, a crash or a resumed session, in this order:
846
+
847
+ 1. **Collect.** `keryx review retry-plan --manifest <slices>/manifest.json --package <input-dir> --reviewer <id> --next-wave` reads `raw/` first and collects late reviewer results; it prints `collected late: N` and never re-hands a slice that is finished.
848
+ 2. **Validate** each collected reply (a `STATUS:` line and a `REVIEW_RESULT` block matching `reviewer-finding.schema.json`), **ingest** it, and rebuild `research.json` with `ledger build`; run `ingest --research` once it prints READY.
849
+ 3. **Dispatch only what is missing:** the wave `retry-plan` prints. A wave whose results are on disk is never dispatched again.
850
+ 4. **A second timeout of the same reviewer changes the task, not only the diff size:** fewer slices per dispatch, a narrower focus (one concern or one directory), or a lighter model tier for a mechanical slice. Two results in a row with nothing new are `Not run`, as `retry-plan` prints.
851
+
852
+ ## dispatch-check on every payload
853
+
854
+ Before any mass dispatch run `keryx review dispatch-check --payload <file> --manifest <dir>/manifest.json` on every payload, on every host. It fails `REVIEWER_INPUT_PATH_MISSING` when a `skill_path` or `context_doc` names a file that is not there, and still fails a payload that names no slice, exceeds the wave ceiling or breaks `reviewer-input.schema.json`. Fix the payload; a dead path costs a whole wave of refusals. Related: `review mutate` runs in a scratch copy under the repo and prints the baseline's tail when the baseline is red; `review start --graph-timeout <s>` bounds the graph build.