@mrciphersmith/keryx 0.3.119 → 0.3.121

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 (42) hide show
  1. package/dist/cli.js +9730 -5314
  2. package/dist/core.js +1162 -812
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/install-manifest.json +2 -1
  5. package/src/gdskills/bundled/rules/core/session-plan-bridge.mdc +1 -1
  6. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.md +4 -4
  7. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +47 -59
  8. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.detail.md +70 -0
  9. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +42 -79
  10. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/orchestrator-prompt.md +1 -1
  11. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +12 -18
  12. package/src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json +25 -2
  13. package/src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json +19 -0
  14. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +6 -11
  15. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +6 -11
  16. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +6 -11
  17. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +5 -10
  18. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +5 -10
  19. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +8 -17
  20. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +8 -15
  21. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +6 -11
  22. package/src/gdskills/bundled/skills/review/review-jev-comments/SKILL.md +4 -9
  23. package/src/gdskills/bundled/skills/review/review-jev-contract/SKILL.md +4 -9
  24. package/src/gdskills/bundled/skills/review/review-jev-docs/SKILL.md +4 -9
  25. package/src/gdskills/bundled/skills/review/review-jev-risk/SKILL.md +4 -9
  26. package/src/gdskills/bundled/skills/review/review-jev-rules/SKILL.md +4 -9
  27. package/src/gdskills/bundled/skills/review/review-jev-scenarios/SKILL.md +4 -9
  28. package/src/gdskills/bundled/skills/review/review-layout/SKILL.md +8 -9
  29. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +7 -12
  30. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +39 -2
  31. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +49 -92
  32. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +13 -0
  33. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +38 -0
  34. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +6 -11
  35. package/src/gdskills/bundled/skills/review/review-pr-contract/SKILL.md +2 -2
  36. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +8 -10
  37. package/src/gdskills/bundled/skills/review/review-premise/SKILL.md +180 -0
  38. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +4 -4
  39. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +6 -11
  40. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +6 -11
  41. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +2 -2
  42. package/src/gdskills/contracts/review-finding.schema.json +88 -0
@@ -205,15 +205,10 @@ other reviewer's: same Quality Gate, same dedup, same Wave C verification.
205
205
 
206
206
  ### Shared laws (every reviewer)
207
207
 
208
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
209
- name the input, call, or condition that reaches the code, you have an
210
- observation, not a finding. Report it as `info` and say what would settle it.
211
- 2. **Never flag the theoretical.** The path you describe must exist in the code
212
- under review. Do not report a safe API because it could be misused, or a
213
- pattern because it is often wrong elsewhere.
214
- 3. **One finding per class, not one per occurrence.** When the same shape appears
215
- at several sites, report it once and list every site. Ten findings that are one
216
- finding hide the other nine problems.
208
+ 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
209
+ 2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
210
+ 3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
211
+ 4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.
217
212
 
218
213
  This reviewer already satisfies all three by construction: `evidence` always
219
214
  names the hunk and quotes it (never an unreproducible claim), a finding is
@@ -129,15 +129,10 @@ same dedup, same Wave C verification.
129
129
 
130
130
  ### Shared laws (every reviewer)
131
131
 
132
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
133
- name the input, call, or condition that reaches the code, you have an
134
- observation, not a finding. Report it as `info` and say what would settle it.
135
- 2. **Never flag the theoretical.** The path you describe must exist in the code
136
- under review. Do not report a safe API because it could be misused, or a
137
- pattern because it is often wrong elsewhere.
138
- 3. **One finding per class, not one per occurrence.** When the same shape appears
139
- at several sites, report it once and list every site. Ten findings that are one
140
- finding hide the other nine problems.
132
+ 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
133
+ 2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
134
+ 3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
135
+ 4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.
141
136
 
142
137
  This reviewer satisfies all three by construction: severity is fixed at
143
138
  `minor` — never higher — and `evidence` always names the scenario's linked
@@ -119,6 +119,10 @@ name instead.
119
119
  LTR is toward the end in RTL. State both.
120
120
  - [ ] A physical gradient, shadow, or transform in a component that otherwise uses
121
121
  logical properties does **not** flip. Name the direction it points in each.
122
+ - [ ] Some surfaces usually do **not** mirror, by platform practice (Material Bidirectionality,
123
+ Apple HIG): media playback controls and their progress or seek bar, numbers, code, phone
124
+ numbers. A forced `dir="ltr"` there is usually deliberate: read its signals (law 4) before
125
+ reporting. An event timeline, calendar row or chart axis often does mirror; judge by the product.
122
126
  - [ ] Text length differs by locale. A component sized by its own labels renders
123
127
  **different geometry for identical data** across locales. Measure with the
124
128
  longest real translation in the catalog, never the English one.
@@ -146,15 +150,10 @@ name instead.
146
150
 
147
151
  ### Shared laws (every reviewer)
148
152
 
149
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
150
- name the input, call, or condition that reaches the code, you have an
151
- observation, not a finding. Report it as `info` and say what would settle it.
152
- 2. **Never flag the theoretical.** The path you describe must exist in the code
153
- under review. Do not report a safe API because it could be misused, or a
154
- pattern because it is often wrong elsewhere.
155
- 3. **One finding per class, not one per occurrence.** When the same shape appears
156
- at several sites, report it once and list every site. Ten findings that are one
157
- finding hide the other nine problems.
153
+ 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
154
+ 2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
155
+ 3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
156
+ 4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.
158
157
 
159
158
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
160
159
  **Severity (canonical)**. This reviewer keeps no rubric of its own; below is only
@@ -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. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
30
+ and unifies them into a single focused pass. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. It runs no command unless its payload's `allowed_tools` says `run-tests`, except the read-only `git log`, `git blame` and `git show` where its host gives a read-only child git (keryx shell does not: there the payload supplies the history).
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.
@@ -69,7 +69,7 @@ See shared script: `.metaproject/skills/gdskills/shared/git-merge-base.md`
69
69
  Review scope: **changes introduced in the current branch since merge-base only**.
70
70
  Do not review unrelated files.
71
71
 
72
- **Supplied text first.** When the payload carries `slices`, `context_files`, `diff` or `file_contents`, review exactly that text: a read-only child has no shell, so run no git command and never rebuild the diff. Only with none supplied, collect it:
72
+ **Supplied text first.** When the payload carries `slices`, `context_files`, `diff` or `file_contents`, review exactly that text and never rebuild the diff. A choice's history (law 4) is read with `git log`, `git blame` and `git show` only where the host gives a read-only child git; on keryx shell a read-only child has no shell and no git tool, so read the `git log -L`/`git blame` excerpts the payload supplies, or say the history was not read. Only with none supplied, collect it:
73
73
  ```bash
74
74
  git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files --others --exclude-standard
75
75
  # explicit range: <FROM_SHA>..<TO_SHA> in place of "${BASE_SHA}"
@@ -193,7 +193,7 @@ earlier review round, because there the finding is recorded as closed and is not
193
193
 
194
194
  ## Orchestrated Review Contract
195
195
 
196
- When dispatched by `review-orchestrator`, follow the provided `reviewer-input.schema.json` payload. Return a `REVIEW_RESULT` object compatible with `.metaproject/skills/gdskills/review/review-orchestrator/reviewer-finding.schema.json`, then a concise markdown summary. Keep findings evidence-based, include concrete `suggested_fix` for every blocker/major, and return `NEEDS_CONTEXT` instead of guessing when required context is missing.
196
+ When dispatched by `review-orchestrator`, follow the provided `reviewer-input.schema.json` payload. Return a `REVIEW_RESULT` object compatible with `.metaproject/skills/gdskills/review/review-orchestrator/reviewer-finding.schema.json`, then a concise markdown summary. Keep findings evidence-based, include concrete `suggested_fix` for every blocker/major, and return `NEEDS_CONTEXT` instead of guessing when required context is missing. On a FIX slice, also return `prior_dispositions: [{id, disposition}]` for every attached finding id.
197
197
 
198
198
  ---
199
199
 
@@ -260,15 +260,10 @@ conditions land under that rubric, not a second rubric.
260
260
 
261
261
  ### Shared laws (every reviewer)
262
262
 
263
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
264
- name the input, call, or condition that reaches the code, you have an
265
- observation, not a finding. Report it as `info` and say what would settle it.
266
- 2. **Never flag the theoretical.** The path you describe must exist in the code
267
- under review. Do not report a safe API because it could be misused, or a
268
- pattern because it is often wrong elsewhere.
269
- 3. **One finding per class, not one per occurrence.** When the same shape appears
270
- at several sites, report it once and list every site. Ten findings that are one
271
- finding hide the other nine problems.
263
+ 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
264
+ 2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
265
+ 3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
266
+ 4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.
272
267
 
273
268
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
274
269
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -651,7 +651,7 @@ certifies the flow is the one that checked the least.
651
651
 
652
652
  ## Readiness — the checklist behind `completed` and behind publishing
653
653
 
654
- `keryx review readiness <review-id-or-path> [--json]` reads the package and prints ten 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.
654
+ `keryx review readiness <review-id-or-path> [--json]` reads the package and prints eleven 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.
655
655
 
656
656
  1. `files-covered` — every changed file is in a wave or carries a recorded waiver.
657
657
  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: in keryx shell call `review_chunks_answer` (a card, never a terminal); elsewhere the operator runs `keryx review chunks estimate --package <dir> --answer yes --quote "<their words>"` in their terminal; unattended, record Not run.
@@ -663,8 +663,9 @@ certifies the flow is the one that checked the least.
663
663
  8. `report-names` — pending mutation candidates and parity warnings are named in the report.
664
664
  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>`.
665
665
  10. `memory-outside-stage` — the orchestrator read memory only in its memory stage ("Clean context" above). Outside keryx shell it reads "not observable on this host" unless this session's keryx calls carry the caller token `keryx review start` printed.
666
+ 11. `premise-decisions` — every finding `review-premise` held (`challenged` or `owner-decision`) has an operator decision: in keryx shell the card `review_decide_premise`; elsewhere the operator runs `keryx review decide-premise --package <dir> --finding <global_id> --answer uphold|dismiss --reason "<why>"` in their terminal (SKILL.md "Wave D"). Not waivable: each held finding needs its own answer, and `review_waive_readiness` / `--waive` refuse this item.
666
667
 
667
- `keryx review complete` refuses status `completed` while any item fails. A failing item is waived only by the operator. In keryx shell call `review_waive_readiness` for the item: the operator answers it as a card, the waiver is recorded with the card text and the time, and then you run `keryx review complete`. Never send the operator to a terminal. Outside keryx shell the operator runs `keryx review complete --waive <item> "<their own words>"` in a terminal, repeatable. Unattended, record the item as Not run. `keryx review publish` is held by the same checklist. Publishing is the operator's decision too: in keryx shell call `review_publish` (a card shows the target and the body; never send the operator to a terminal). A not-ready package goes to GitHub only as a partial review (`review_publish` with `partial: true`, or `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.
668
+ `keryx review complete` refuses status `completed` while any item fails. A failing item other than `premise-decisions` is waived only by the operator. In keryx shell call `review_waive_readiness` for the item: the operator answers it as a card, the waiver is recorded with the card text and the time, and then you run `keryx review complete`. Never send the operator to a terminal. Outside keryx shell the operator runs `keryx review complete --waive <item> "<their own words>"` in a terminal, repeatable. Unattended, record the item as Not run. `keryx review publish` is held by the same checklist. Publishing is the operator's decision too: in keryx shell call `review_publish` (a card shows the target and the body; never send the operator to a terminal). A not-ready package goes to GitHub only as a partial review (`review_publish` with `partial: true`, or `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.
668
669
 
669
670
  ## Fix rounds — dispositions, regressions, withdrawal
670
671
 
@@ -687,6 +688,20 @@ sync as abandoned"* is a claim; the disposition is whether the branch it renamed
687
688
  is reachable and pinned. On a recorded round, two such commits asserted behaviour
688
689
  on lines no test could reach.
689
690
 
691
+ ### Delta rounds — what `review start` hands you
692
+
693
+ `keryx review start` detects the round and writes `<package>/round.json` and `<package>/prior_findings.json`. It searches every source, because the earlier round may have run on another machine: the local package, git history (tracked package files), the PR's `keryx round` block, PR comments, and the flow's packages. `round.json` carries `round`, `source`, `sourcesTried`, `previous`, `mode`, `range`, `fixHunks`, `newHunks` and `carried`.
694
+
695
+ | `mode` | `range` | Review |
696
+ |---|---|---|
697
+ | `first` | merge-base..head | A first round. `sourcesTried` records what was searched when nothing was found. |
698
+ | `delta` | previous head..head | `fix` slices (a hunk that answers a prior finding): `review-logic`, `review-regression`, the authors of the attached findings and the verifier, each with its `prior_findings`. `new` slices: round 1, with the roles the slice names. Unchanged code: not re-reviewed. `carried` findings keep their dispositions. |
699
+ | `fallback-first` | merge-base..head | The previous head is not an ancestor (force-push, rebase). Review the whole range with the prior findings attached. |
700
+
701
+ A fix hunk still has a radius: enumerate what names the thing it changed (`review_context.scope.files`), as in any fix round. The attached findings are the contract: each leaves the round with a disposition, below.
702
+
703
+ A reviewer on a FIX slice reports those dispositions itself: its `REVIEW_RESULT` carries `prior_dispositions: [{id, disposition}]` with one entry for every attached finding id (`disposition` is `closed`, `open`, `partial`, `regressed` or `withdrawn`), judged against the code. `keryx review ingest` reads the array into the ledger; an attached id with no entry stays undisposed.
704
+
690
705
  ### A fix is a change, and changes get reviewed
691
706
 
692
707
  The most expensive class in a multi-round review is **the defect the fix
@@ -903,3 +918,25 @@ Default budget guidance:
903
918
  | medium | <= 20 files or <= 2,000 changed lines | `light` | per-domain filtered diff |
904
919
  | large | > 20 files or > 2,000 changed lines | ask `full` | staged waves by domain |
905
920
  | high-risk | auth/API/core/security/data migrations | ask `full` | staged waves, verifier included |
921
+
922
+ ## Everything written to GitHub is brief
923
+
924
+ One rule, applied to every outward surface: **PR bodies, PR comments, review
925
+ replies, issue comments, and commit messages going to a PR.**
926
+
927
+ - Lead with the conclusion. No preamble, no restating the question, no apology,
928
+ no summary of the flow.
929
+ - Say what changed and where. **Link, do not paste.**
930
+ - The reasoning, the evidence, the rejected alternatives and the round history live
931
+ in the flow package — `journal.md`, `context.md`, the review artifacts — which is
932
+ durable, searchable, and costs a reader nothing to skip.
933
+ - A GitHub artifact that needs more than a short paragraph is a signal that the
934
+ detail belongs in the flow with a link out, **not** that the paragraph should
935
+ grow.
936
+ - No orchestrator-written PR comment or reply exceeds two sentences without
937
+ carrying a link to the artifact holding the detail. The reply pass enforces
938
+ this; for anything else you write outward, hold yourself to it.
939
+
940
+ This is deliberately asymmetric: **verbose in the flow, terse on GitHub.** The
941
+ flow is written for whoever resumes the work; GitHub is read by someone who did
942
+ not ask for our reasoning and is reading between other tasks.
@@ -27,7 +27,7 @@ license: "MIT"
27
27
  1. **Can it spawn?** The round needs a subagent-spawn tool (`Agent`, `spawn_subagent` or the host's equivalent) and depth budget left: Claude Code nests subagents at most 3 deep, and at the limit `Agent` is withheld. A host with no spawn tool at all (Codex and other AGENTS.md hosts) does not stop here and does not review alone: it runs the round through the autonomous runner, `keryx review run --autonomous --target pr --ref <pull request URL>` (no pull request: `--target branch --ref <base> [--head <commit>]`), and relays its verdict and exit code (see "Hosts"). Only a session that has spent the depth budget (a nested subagent) stops; its whole output is this line, with no tool calls and no review of your own:
28
28
  `STATUS: BLOCKED nested_dispatch_unavailable — run this skill in the main session`
29
29
  2. **Is a round needed?** List the files with `git diff --name-status --no-renames <base>...HEAD`, so a rename shows both paths. A diff where EVERY file is prose or machine-written data ends here with one line, `round not needed: <reason>`, and no reviewer. Prose is exactly: README or CHANGELOG at any depth; CONTRIBUTING, LICENSE, SECURITY or CODE_OF_CONDUCT at the top level; and under `docs/`, `.metaproject/wiki`, `.metaproject/reviews` or a flow's `journal.md`, a file with extension md, rst or adoc whose name holds a lowercase letter (an all-uppercase name such as AGENT or WARP is steering by convention). Machine-written data is a file under `coverage/` or `__generated__/` with extension lcov, info or map only; json, txt, html and md there are code. Steering is code wherever it sits, `docs/` included: a directory (singular or plural) named agent, skill, command, rule, prompt, instruction, persona, steering or hook, any path segment starting with a dot (`.claude`, `.cursorrules`, `.mcp.json`), a file name starting with SKILL, AGENT, CLAUDE, GEMINI, QWEN, CODEX, WARP, CRUSH, JULES, KNOWLEDGE, GUIDELINES, CONVENTIONS or copilot-instructions, ending in .local, .override, .instructions, .prompt, .agent or .chatmode before the extension, or containing prompt, instruction or system. A flow's `description.md`, `acceptance-criteria.md` and `tasks/` are gate inputs, so they are code. Every other file counts as code too, including lockfiles, committed `dist/` output, CI, auth, migrations, config JSON, and any path with `..`, a backslash, a leading `./` or `//`. `classifyRoundNeed` in `src/review/round-need.ts` is the tested reference of this rule; the host executes this text, and nothing in the CLI calls the function yet. `--all`, an explicit reviewer list or a gating round forces a round.
30
- 3. **Round ceiling.** 5 rounds (`REVIEW_ROUND_CAP`) over the same `merge-base..HEAD`. Past it: interactive, ask the operator; unattended, `STATUS: BLOCKED round_cap`.
30
+ 3. **Round ceiling.** 5 rounds (`REVIEW_ROUND_CAP`) over the same change. Past it: interactive, ask the operator; unattended, `STATUS: BLOCKED round_cap`.
31
31
  4. **PR state, shown before dispatch.** On a PR target read its state (merged, approved, CI) and tell the operator the risk that it merges before the round ends: a verdict ready at minute 55 and held to minute 119 lost the race to the merge. Depth and the estimate need the package and the slice manifest, so they come later: after `review scope`, `review start` and `review slice`, before the first reviewer starts ("Round plan" steps 5-6; `SKILL.detail.md` § "Preflight 4").
32
32
 
33
33
  ## Hosts — the same round, different tools
@@ -44,19 +44,19 @@ license: "MIT"
44
44
  - **Every host keeps the same files, per package** (`<package>` is the directory `keryx review start` created): slices in `<package>/slices/`, one reply per dispatch in `<package>/raw/<reviewer>.txt` (reviewer replies only), one driver per dispatch in `<package>/drivers/<reviewer>.json`, and `research.json` from `keryx review ledger build --package <package>` — never by hand. `retry-plan --package`, `verdict` and `ledger build` read `<package>/raw` by default; the shared `.metaproject/data/review/raw` holds other rounds' replies and is read only when named, so never write there.
45
45
  - **The result is the file, never the spawn tool's output.** keryx shell cuts a child's summary at 16000 characters and Claude Code returns only the last message: parse `<package>/raw/<reviewer>.txt`. A missing file is no result (`BLOCKED`).
46
46
  - **Caller token.** `keryx review start` prints `export KERYX_REVIEW_CALLER_TOKEN=…`; outside keryx shell export it on this session's keryx calls, or readiness item 10 reads "not observable on this host".
47
- - **Operator decisions.** In keryx shell the operator answers a card: `review_confirm_plan`, `review_waive_readiness`, `review_waive_coverage`, `review_waive_mutation`, `review_override_reviewers`, `review_chunks_answer`, `review_publish`, `review_comments_reply`. Elsewhere give the operator the exact command to run in their own terminal — `keryx review confirm-plan --package <package>`, `keryx review complete <package> --waive <item> "<their words>"` or `--waive-coverage "<their words>"`, `keryx review waive-mutation --package <package> --reason "<why>"`, `keryx review override-reviewers --package <package> --reason "<why>"`, `keryx review chunks estimate --package <package> --answer yes --quote "<their words>"`, `keryx review publish <package>`, `keryx review comments reply … --final` — and wait. You never run `--mode automatic` or `--yes`, and never write an operator quote yourself; unattended, the item is Not run.
47
+ - **Operator decisions.** In keryx shell the operator answers a card: `review_confirm_plan`, `review_waive_readiness`, `review_waive_coverage`, `review_waive_mutation`, `review_override_reviewers`, `review_chunks_answer`, `review_publish`, `review_comments_reply`, `review_decide_premise`. Elsewhere give the operator the exact command to run in their own terminal — `keryx review confirm-plan --package <package>`, `keryx review complete <package> --waive <item> "<their words>"` or `--waive-coverage "<their words>"`, `keryx review waive-mutation --package <package> --reason "<why>"`, `keryx review override-reviewers --package <package> --reason "<why>"`, `keryx review chunks estimate --package <package> --answer yes --quote "<their words>"`, `keryx review publish <package>`, `keryx review comments reply … --final`, `keryx review decide-premise --package <package> --finding <id> --answer uphold|dismiss --reason "<why>"` — and wait. You never run `--mode automatic` or `--yes`, and never write an operator quote yourself; unattended, the item is Not run.
48
48
 
49
49
  ## Round plan — the order on every host
50
50
 
51
- 1. `keryx review scope --ref <base> --json > .metaproject/data/review/scope.json` (Step 3).
52
- 2. `keryx review start --target <kind> --ref <ref> --scope .metaproject/data/review/scope.json --memory-query "<query>" --host <host>`, plus `--unattended` when nobody is at the keyboard.
51
+ 1. `keryx review plan --target <pr-url|branch> [--ref <base>] [--head <sha>] --host <host> [--memory-query "<query>"] [--unattended]` is the one command: it runs start, scope (Step 3), blast-radius (Step 3b), slice, required and estimate, writes `<package>/plan.json` and dispatches nothing. Read the round first (Step 1a), then dispatch from step 7.
52
+ 2. Without `plan`, run those stages one by one in this order: `keryx review scope --ref <base> --json > .metaproject/data/review/scope.json`, then `keryx review start --target <kind> --ref <ref> --scope .metaproject/data/review/scope.json --memory-query "<query>" --host <host>` (plus `--unattended` when nobody is at the keyboard); `start` searches every prior-round source (local package, git history, the PR's keryx round block, PR comments, flow) and writes `round.json`.
53
53
  3. `keryx review blast-radius --ref <base> --package <package> --json > blast-radius.json` (Step 3b). Reasoned omissions (`unrelated-symbol`, `hub-damped`, `text-hub`, `test-consumer`) are context, not scope; only cap drops become chunks. Run the tests in `<package>/tests-to-run.json` with the command the radius prints, instead of reading them, and hand the output to the reviewers as context.
54
54
  4. `keryx review slice --ref <base> --package <package> --host <host>`: each slice carries `roles`, `depth` (deep or light) and `audit`.
55
55
  5. `keryx review required --mode all --scope .metaproject/data/review/scope.json --depth auto --package <package>`.
56
56
  6. `keryx review estimate --package <package>`. Over threshold, the operator confirms (card `review_confirm_plan`, or `keryx review confirm-plan --package <package>` in their terminal); `dispatch-check` and `ledger build` refuse an unconfirmed plan, so never dispatch one. Unattended: report the estimate and stop with `STATUS: BLOCKED plan_over_threshold`.
57
- 7. Dispatch by slice roles: each role gets the slices that name it; a deep slice names every roster role its path gates allow, an `audit` one the whole core set. A major or worse on a light slice comes back from `retry-plan` as an escalation: dispatch the core roles on it.
58
- 8. Verifier on the first blocker or major (Step 10). It runs no command itself: run `keryx review verify-run --package <package> --finding <id> -- <command>` and hand it the saved `research-evidence/verify-<id>-<n>.txt` as context.
59
- 9. `keryx review verdict <package>` to the operator, then the tail: mutation pass, `ledger build`, `ingest`, `readiness`, `complete`.
57
+ 7. Dispatch by slice roles: each role gets the slices that name it; a deep slice names every roster role its path gates allow, an `audit` one the whole core set. A major or worse on a light slice comes back from `review next` as an `escalated` dispatch: dispatch the core roles on it.
58
+ 8. Verifier on the first blocker or major (Step 10). It runs no command itself: run `keryx review verify-run --package <package> --finding <id> -- <command>` and hand it the saved `research-evidence/verify-<id>-<n>.txt` as context. After it (no verifier ran: after the last reviewer), Wave D: `review-premise` (Step 10b).
59
+ 9. `keryx review verdict <package>` to the operator, then the tail: mutation pass, `ledger build`, `ingest` (with `--premises`), the operator's answer to each held finding (Wave D), `readiness`, `complete`.
60
60
 
61
61
  ## Clean context — the round starts empty
62
62
 
@@ -85,9 +85,10 @@ Review Orchestrator Progress:
85
85
  - [ ] Step 9: Collect reviewer-finding schema results and handle NEEDS_CONTEXT
86
86
  - [ ] Step 9b: `jev-triage` — advisory, annotate-only severity/duplicate/verify-order annotations over the consolidated findings (opt-in `review.jev.triage`)
87
87
  - [ ] Step 10: Wave C — when blockers/majors exist, `--verify` is set, or the PR is high-risk, dispatch `review-verifier` on the first blocker/major without waiting for other reviewers, then once per later pass over the findings held at that point
88
+ - [ ] Step 10b: Wave D — after the last verifier pass (none ran: after the last reviewer), dispatch `review-premise` (deep tier) over the canonical findings of severity ≥ minor (delta round: only those without a carried premise); pass its claims with `review ingest --premises <file>`; once that ingest wrote `findings.json` (the tail), ask the operator about each held finding (see "Wave D")
88
89
  - [ ] Step 11: Sort by severity, deduplicate, emit unified report
89
90
  - [ ] Step 12: Emit the machine-readable `keryx:findings` block alongside the report
90
- - [ ] Step 13: Report the stage counts: dropped by pre-filter, refuted by the verifier, retained
91
+ - [ ] Step 13: Report the stage counts: dropped by pre-filter, refuted by the verifier, downgraded and held by the premise judge, retained
91
92
  - [ ] Step 14: Managed rounds only (not `lightweight`, which is report-only), after the final round, on an open pull request at the head you reviewed — answer every external comment once with `keryx review comments reply --final` (render with `--dry-run`; the post itself is the operator's: the `review_comments_reply` card in keryx shell, else they run it in their terminal; unattended: do not publish, hand the rendered body back) — never against a pull request the dispatch named as the caller's
92
93
  ```
93
94
 
@@ -101,25 +102,26 @@ It names a model only if you gave it your session (`--session-provider`/`--sessi
101
102
 
102
103
  ### Step 6a — the plan bridge
103
104
 
104
- Publish this checklist with `plan_set` under the ids `step-0`…`step-14` once, here, when scope and dispatch are fixed (keryx shell already published it as `pending` at the start — update it with `plan_update` instead; another host uses its own plan tool, "Hosts"). Publish each of steps 0–5 that ran as `completed` and each that did not run as `skipped`; publish steps 6–14 as `pending` (`in_progress` for the one starting now). From then on move each item with `plan_update` as its step completes — see the `session-plan-bridge` rule. `completed` means the step's artifact exists: steps 8–10 become `completed` (in the plan and in the report) only after `keryx review ingest` has recorded their results, and a step whose reviewers were `BLOCKED` is `blocked`.
105
+ Publish this checklist with `plan_set` under the ids `step-0`…`step-14` and `step-10b` once, here, when scope and dispatch are fixed (keryx shell already published it as `pending` at the start — update it with `plan_update` instead; another host uses its own plan tool, "Hosts"). Publish each of steps 0–5 that ran as `completed` and each that did not run as `skipped`; publish steps 6–14 and 10b as `pending` (`in_progress` for the one starting now). From then on move each item with `plan_update` as its step completes — see the `session-plan-bridge` rule. `completed` means the step's artifact exists: steps 8–10 and 10b become `completed` (in the plan and in the report) only after `keryx review ingest` has recorded their results (10b: `--premises`), and a step whose reviewers were `BLOCKED` is `blocked`.
105
106
 
106
107
  ## How to spawn (Steps 8 and 10)
107
108
 
108
109
  - One `Agent` call per reviewer, all calls of a wave in a single message, so the wave runs in parallel.
110
+ - Reviewers are read-only: they read the diff and the files and run no command, except the read-only history commands `git log`, `git blame` and `git show` (law 4; `review-premise` too) where the host gives a read-only child git. keryx shell does not: a `spawn_subagent` child has no shell and no git tool, so you run `git log -L <start>,<end>:<file>` and `git blame -L <start>,<end> <file>` for each deliberate-looking site a reviewer must judge and pass the output in `context_files`; with neither, the reviewer says the history was not read. Only you (through `keryx review verify-run --timeout <seconds>`), the verifier and at most one testing reviewer run other commands, inside a time budget. Each payload carries `allowed_tools` (`read-only` or `run-tests`) and `exec_budget_s`.
109
111
  - Use the reviewer's exact `subagent_type`. If the runtime has no such type, use `general-purpose` and name the reviewer's `SKILL.md` path in the prompt. Neither available: that reviewer is `BLOCKED`.
110
112
  - Prompts carry pointers, not pasted files — the diff, the SHAs, the PR, the schema paths — and never paraphrase a contract. On keryx shell the slices travel in `context_files` instead (below). Run `keryx review dispatch-check --payload <file> --manifest <package>/slices/manifest.json --package <package>` on every payload before a mass dispatch; it fails `REVIEWER_INPUT_PATH_MISSING` on a missing `skill_path` or `context_doc`.
111
113
  - A reply is a result only if it starts with a `STATUS:` line and carries a `REVIEW_RESULT` block matching `reviewer-finding.schema.json`; anything else is `BLOCKED`. The one exception: a reply or dispatch error of `STATUS: RATE_LIMITED` is handled by the Rate limits rule under Control, never marked `BLOCKED`.
112
- - The model comes from `keryx review tier` (Step 6). On `spawn_subagent` pass its tier as `model_tier` on every reviewer — `review-verifier` and simple reviewers `light`, normal `standard`, complex `deep`; an omitted tier runs the child on your own model.
114
+ - The model comes from `keryx review tier` (Step 6). On `spawn_subagent` pass its tier as `model_tier` on every reviewer — `review-verifier` and simple reviewers `light`, normal `standard`, complex reviewers and `review-premise` `deep` (`keryx review tier --premise`); an omitted tier runs the child on your own model.
113
115
 
114
116
  ## Slices, waves and results — every host; keryx shell specifics marked
115
117
 
116
118
  A reviewer starts in the project root and reads project files; a path outside the project root is unreadable to it. On keryx shell its `context_files` content reaches it wrapped as DATA, and slices and measurements travel only there (never pasted or retyped); elsewhere the prompt names the slice paths. `skill_path` and `pr_context` stay payload fields. The text reaches the reviewer in slices small enough to finish.
117
119
 
118
- 0. **Publish the plan before anything else (keryx shell).** Your first tool call is `plan_set` with `step-0`…`step-14` all `pending`. A shell turn that has open plan items is continued by the host; a turn that ends on a text reply is over, and a message saying the review "cannot be honestly completed" ends the run with nothing reviewed. Never end the turn while a step is `pending` or `in_progress`: mark it `blocked` only with a cause you cannot fix with a command, and otherwise keep working. Step 6a then updates this plan rather than creating it.
120
+ 0. **Publish the plan before anything else (keryx shell).** Your first tool call is `plan_set` with `step-0`…`step-14` and `step-10b` all `pending`. A shell turn that has open plan items is continued by the host; a turn that ends on a text reply is over, and a message saying the review "cannot be honestly completed" ends the run with nothing reviewed. Never end the turn while a step is `pending` or `in_progress`: mark it `blocked` only with a cause you cannot fix with a command, and otherwise keep working. Step 6a then updates this plan rather than creating it.
119
121
  1. **Slice first.** `keryx review slice --ref <base> --package <package> --host <host>` after `keryx review start`. It writes `<package>/slices/slice-NN.diff` files of at most 150000 bytes each and a `manifest.json` carrying a wave budget (`--wave-bytes`, never below the slice ceiling; default by `--host`: 60000 on keryx-shell, 150000 elsewhere): what ONE reviewer dispatch may total, so a role owning many slices is dispatched in slice waves that each fit the child deadline. On keryx shell with a large diff pass a small `--max-bytes` (for example 18000) and `--wave-bytes` (for example 54000) so no wave outruns a reviewer's five minutes; ledgers (csv, lockfiles, snapshots, generated files) are listed under `omissions` with a reason — list them in the report as not reviewed, never as clean.
120
122
  2. **Slices travel by path; on keryx shell, only by `context_files`.** The slices sit under the project (`<package>/slices`). On keryx shell pass each reviewer its slice paths in `spawn_subagent`'s `context_files`: the host copies the text into that reviewer's task, so you never paste or retype a slice. Elsewhere name the slice paths in the prompt. Put the `slices` ids in its reviewer-input. A dispatch that names a git range but no slice leaves the reviewer with nothing to read — that is `BLOCKED`, not a review.
121
123
  3. **Check before dispatch, every payload.** `keryx review dispatch-check --payload <file> --manifest <package>/slices/manifest.json --package <package>` for the wave; exit 1 means a payload names no slice, is over the wave ceiling (dispatch fewer slices, then the next wave), names a `skill_path` or `context_doc` that does not exist (`REVIEWER_INPUT_PATH_MISSING`), belongs to an unconfirmed over-threshold plan (`REVIEWER_INPUT_PLAN_UNCONFIRMED`), or breaks `reviewer-input.schema.json`. Fix it; do not dispatch around it.
122
- 4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. On keryx shell every round reviewer's `spawn_subagent` carries `review_wave: {"package": "<package>", "pass": "round"}` (a wave outside it counts against the turn's 32 children) and a `timeout_ms` that fits its wave: the default 300000 is sized for a wave of 60000 bytes, so a larger `--wave-bytes` needs a larger `timeout_ms`. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means the next wave while it makes progress, Not run when it stalls.** Every reviewer result lists the `slices` it covered, in its `REVIEW_RESULT` object, as ids (`"slices": ["slice-01", "slice-02"]`); an object with an `id` and an optional `coverage` note (`{"id": "slice-01", "coverage": "read in full"}`) is read the same way. An object with a `status` counts only when it is DONE, COMPLETE, COVERED or OK (any case); a slice marked NOT_READ, INCOMPLETE, SKIPPED or PARTIAL is not covered, so give a slice you did not read no `status` of that kind and leave it out. An entry with no id counts for nothing. **One driver file per dispatch.** Write `<package>/drivers/<reviewer>.json` with `{"reviewer": "<name>", "slices": [<ids dispatched>], "result": "raw/<reviewer>.txt", "definition": "<path of the reviewer's SKILL.md>"}`: `ledger build` takes the reviewer's rule file from `definition` (a `skill_path` there, or inside a `payload` object, is read too) and the slices it was handed from `slices`. Only reviewer replies belong in `raw/`; a verification payload or a note filed there is reported as set aside and left in place, but it still costs a step. On `INCOMPLETE`, `BLOCKED` or `NEEDS_CONTEXT` (never accepted as a finished scope), and on a `DONE` that left slices open, `keryx review retry-plan --manifest <package>/slices/manifest.json --result <package>/raw/<reviewer>.txt --package <package>` decides and hands out the next wave of only the slices still uncovered (`--next-wave` plans one without a result). A result that covered a new slice spends no attempt; two results in a row with nothing new, or six failed rounds, print the `- **Not run:** …` line to paste into the report, and a result with nothing new first has its open slices cut in half. Dispatch each wave, save its reply, and run `retry-plan` again until it says `accepted`; after a crash or timeout run `keryx review retry-plan --manifest <package>/slices/manifest.json --package <package> --reviewer <id> --next-wave` first, which collects late results from `<package>/raw/` (per reviewer) and never re-hands a finished slice. Only the operator can accept a smaller set than that (`review_override_reviewers`, or `keryx review override-reviewers` in their terminal). An unfinished reviewer is never counted as a clean pass. **Persist every result, on every host.** On keryx shell pass each reviewer `save_result_to: <package>/raw/<reviewer>.txt`: the host writes its full final text there. Elsewhere the prompt tells the reviewer to write its whole reply to `<package>/raw/<reviewer>.txt` before it answers. Either way `review complete` has raw evidence after the transcript is cut, and you parse that file, never the tool output. Build `research.json` with `keryx review ledger build --package <package>` — never by hand: it reads the saved results, `scope-files.json` and the retry state, marks a reviewer complete only when its result is finished and its payloads cover the scope, and prints each gap with the exact next command and the waves left (a `retry-plan --next-wave` call, or a `--dispositions` entry for a raw finding). Run `keryx review ingest --research <package>/research.json` once it prints READY (exit 0). A refused `review complete` names what is missing: fix that with a command and run it again; it is never `blocked`. `--head` wants a SHA (`git rev-parse HEAD`), not `HEAD`.
124
+ 4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. On keryx shell every round reviewer's `spawn_subagent` carries `review_wave: {"package": "<package>", "pass": "round"}` (a wave outside it counts against the turn's 32 children) and a `timeout_ms` that fits its wave: the default 300000 is sized for a wave of 60000 bytes, so a larger `--wave-bytes` needs a larger `timeout_ms`. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means the next wave while it makes progress, Not run when it stalls.** Every reviewer result lists the `slices` it covered, in its `REVIEW_RESULT` object, as ids (`"slices": ["slice-01", "slice-02"]`); an object with an `id` and an optional `coverage` note (`{"id": "slice-01", "coverage": "read in full"}`) is read the same way. An object with a `status` counts only when it is DONE, COMPLETE, COVERED or OK (any case); a slice marked NOT_READ, INCOMPLETE, SKIPPED or PARTIAL is not covered, so give a slice you did not read no `status` of that kind and leave it out. An entry with no id counts for nothing. **One driver file per dispatch.** Write `<package>/drivers/<reviewer>.json` with `{"reviewer": "<name>", "slices": [<ids dispatched>], "result": "raw/<reviewer>.txt", "definition": "<path of the reviewer's SKILL.md>"}`: `ledger build` takes the reviewer's rule file from `definition` (a `skill_path` there, or inside a `payload` object, is read too) and the slices it was handed from `slices`. Only reviewer replies belong in `raw/`; a verification payload or a note filed there is reported as set aside and left in place, but it still costs a step. On `INCOMPLETE`, `BLOCKED` or `NEEDS_CONTEXT` (never accepted as a finished scope), and on a `DONE` that left slices open, `keryx review retry-plan --manifest <package>/slices/manifest.json --result <package>/raw/<reviewer>.txt --package <package>` decides and hands out the next wave of only the slices still uncovered (`--next-wave` plans one without a result). A result that covered a new slice spends no attempt; two results in a row with nothing new, or six failed rounds, print the `- **Not run:** …` line to paste into the report, and a result with nothing new first has its open slices cut in half. `keryx review slice --package <package>` already wrote one driver per reviewer x wave (`drivers/<reviewer>-w<n>.json`: slice ids, absolute slice paths, `result` path; the dispatcher adds `model`). Dispatch each wave in one batch, save each reply to its driver's `result`, and after each batch run `keryx review next --package <package>` (never `retry-plan` once per reviewer): it returns every reviewer's next wave at once, with reason `missing`, `retry`, `stalled` or `escalated`, or `done`. After a crash or timeout run it first: it collects late results from `<package>/raw/` and never re-hands a finished slice. Only the operator can accept a smaller set than that (`review_override_reviewers`, or `keryx review override-reviewers` in their terminal). An unfinished reviewer is never counted as a clean pass. **Persist every result, on every host.** On keryx shell pass each reviewer `save_result_to: <package>/raw/<reviewer>.txt`: the host writes its full final text there. Elsewhere the prompt tells the reviewer to write its whole reply to `<package>/raw/<reviewer>.txt` before it answers. Either way `review complete` has raw evidence after the transcript is cut, and you parse that file, never the tool output. Build `research.json` with `keryx review ledger build --package <package>` — never by hand: it reads the saved results, `scope-files.json` and the retry state, marks a reviewer complete only when its result is finished and its payloads cover the scope, and prints each gap with the exact next command and the waves left (a `retry-plan --next-wave` call, or a `--dispositions` entry for a raw finding). Run `keryx review ingest --research <package>/research.json` once it prints READY (exit 0). A refused `review complete` names what is missing: fix that with a command and run it again; it is never `blocked`. `--head` wants a SHA (`git rev-parse HEAD`), not `HEAD`.
123
125
  5. **Never print a scope or a slice.** The tool output of one call is cut at about 20 KB and `keryx review scope` of a large PR prints hundreds of KB. Run it as `keryx review scope --ref <base> --json > .metaproject/data/review/scope.json` and read the counts from the file (`keryx ctx read`, or `jq`); take `<base>` from `git symbolic-ref refs/remotes/origin/HEAD`, not a guessed `origin/main`. Create `.metaproject/data/review/` first (`mkdir -p`) — a missing directory is a command to run, not a blocker. **Machine artifacts by direct write.** Save slices, payloads and results by redirection or `keryx ctx run --raw -- <command>`; the summarized form of `keryx ctx run` drops the bytes a later step parses.
124
126
  6. **Write mutants whole.** A testing reviewer's `mutant_candidates` cover every changed branch, code downstream of the diff included. Write them to `research-evidence/mutants.json` unchanged; you may not narrow them, and a candidate no pass has run still blocks the coverage gate (`SKILL.detail.md`, mutation pass).
125
127
  7. **Measure before `review-layout`.** Run the browser measurements (Playwright/Storybook) yourself and pass them in its first dispatch (`context_files` on keryx shell, by path elsewhere); they count as evidence when the command and viewport are named. A second `NEEDS_CONTEXT` from one role is Not run (`layout: no engine`), not another refill (`SKILL.detail.md`).
@@ -127,11 +129,11 @@ A reviewer starts in the project root and reads project files; a path outside th
127
129
  ## Control
128
130
 
129
131
  - **Profiles.** The default is read-only: one round, no edits. `--fix` hands the findings to `flow-orchestrator` or `task-implementer`; the orchestrator never edits code. Control returns to this main session after each hand-off, which loads this skill again (never the implementer, which would nest); each re-review counts toward the ceiling (it adds 1 to the count).
130
- - **Waves.** Split by diff domain (`core` = logic, security, architecture; `domain` = frontend, backend, conventions; `support` = style, tests), in that order; A/B/C below keep their dependency order, except Wave C, which starts early and overlaps A and B (see Wave C). A full or `--all` round runs at most 10 reviewers per wave (`MAX_REVIEWERS_PER_WAVE_FULL`).
132
+ - **Waves.** Split by diff domain (`core` = logic, security, architecture; `domain` = frontend, backend, conventions; `support` = style, tests), in that order; A/B/C/D below keep their dependency order, except Wave C, which starts early and overlaps A and B (see Wave C); Wave D runs after the last verifier pass. A full or `--all` round runs at most 10 reviewers per wave (`MAX_REVIEWERS_PER_WAVE_FULL`).
131
133
  - **Rate limits.** On a reviewer dispatch that fails with a rate-limit or overloaded error (reported as `STATUS: RATE_LIMITED`, a harness signal, not a schema status), halve the wave, requeue the rest and honour `retry-after`, at most 300 seconds (`MAX_RETRY_AFTER_SECONDS`). After at most two halvings (`MAX_RATE_HALVINGS`) stop with `STATUS: BLOCKED rate_limited`, naming the queue left.
132
- - **Early verdict.** When every reviewer and the verifier are done, save every verifier pass to `research-evidence/verifications.json`, then run `keryx review verdict <package>` (it reads `<package>/raw`; the shared `.metaproject/data/review/raw` only when passed as `--raw`, which mixes in other rounds) and give the operator the verdict then; refuted findings are excluded only once `verifications.json` exists. The mutation pass, ledger and `keryx review complete` continue as the tail, and every managed round finishes them. The verdict is interim: the round is not done until `complete` (`SKILL.detail.md` § "Early verdict").
133
- - **Recovery.** After a timeout or crash: collect, validate, ingest, then dispatch only what is missing with `keryx review retry-plan --manifest <package>/slices/manifest.json --package <package> --reviewer <id> --next-wave` (it prints `collected late: N`). Never re-dispatch a wave whose results are on disk; after a second timeout of the same reviewer change the task (fewer slices, narrower focus), not only the diff size (`SKILL.detail.md` § "Recovery").
134
- - **Done when** the consolidated report and the `keryx:findings` block are emitted and the stage counts and **Not run** are stated. A managed round (not `lightweight`, which is report-only) is also done only when every dispatched reviewer's result is recorded with `keryx review ingest` and `keryx review complete` has run. `completed` means `keryx review readiness` passed, or each failing item is waived by the operator: in keryx shell call `review_waive_readiness` (a card, never a terminal), then run `keryx review complete`; elsewhere the operator runs `keryx review complete <package> --waive <item> "<their words>"` in their terminal; unattended, record Not run; publishing to GitHub is held by the same checklist, and a not-ready package goes out only through `keryx review publish --partial` (in keryx shell: `review_publish` with `partial: true`).
134
+ - **Early verdict.** When every reviewer and the verifier are done, save every verifier pass to `research-evidence/verifications.json`, then run `keryx review verdict <package>` (it reads `<package>/raw`; the shared `.metaproject/data/review/raw` only when passed as `--raw`, which mixes in other rounds) and give the operator the verdict then; refuted findings are excluded only once `verifications.json` exists, held ones only once Wave D's claims are saved to `research-evidence/premises.json`. A verdict given before Wave D ran is provisional, and you say so: it counts as open the findings the judge may still hold or lower. The mutation pass, ledger and `keryx review complete` continue as the tail, and every managed round finishes them. The verdict is interim: the round is not done until `complete` (`SKILL.detail.md` § "Early verdict").
135
+ - **Recovery.** After a timeout or crash: collect, validate, ingest, then dispatch only what is missing with `keryx review next --package <package>` (all reviewers at once). Never re-dispatch a wave whose results are on disk; after a second timeout of the same reviewer change the task (fewer slices, narrower focus), not only the diff size (`SKILL.detail.md` § "Recovery").
136
+ - **Done when** the consolidated report and the `keryx:findings` block are emitted and the stage counts and **Not run** are stated. A managed round (not `lightweight`, which is report-only) is also done only when every dispatched reviewer's result is recorded with `keryx review ingest` and `keryx review complete` has run. `completed` means `keryx review readiness` passed, or each failing item but `premise-decisions` (answered per finding, never waived) is waived by the operator: in keryx shell call `review_waive_readiness` (a card, never a terminal), then run `keryx review complete`; elsewhere the operator runs `keryx review complete <package> --waive <item> "<their words>"` in their terminal; unattended, record Not run; publishing to GitHub is held by the same checklist, and a not-ready package goes out only through `keryx review publish --partial` (in keryx shell: `review_publish` with `partial: true`).
135
137
 
136
138
  ---
137
139
 
@@ -237,7 +239,7 @@ keryx review start --target <kind> --ref <ref>
237
239
  keryx review ingest --report <path> [--flow <id>] --ref <ref>
238
240
  [--verifications <file>] [--verification-mode off|annotate|filter]
239
241
  [--scope <scope.json>] [--blast-radius <blast-radius.json>]
240
- [--refuted <file>]
242
+ [--refuted <file>] [--premises <file>]
241
243
  # --blast-radius is REQUIRED whenever this round dispatched a
242
244
  # scope-B reviewer (review-regression). See below.
243
245
  keryx review status <review-id-or-path>
@@ -480,25 +482,7 @@ Read each run's verdict (`flaky` | `regression` | `infra`) into the report: `fla
480
482
 
481
483
  ## Everything written to GitHub is brief
482
484
 
483
- One rule, applied to every outward surface: **PR bodies, PR comments, review
484
- replies, issue comments, and commit messages going to a PR.**
485
-
486
- - Lead with the conclusion. No preamble, no restating the question, no apology,
487
- no summary of the flow.
488
- - Say what changed and where. **Link, do not paste.**
489
- - The reasoning, the evidence, the rejected alternatives and the round history live
490
- in the flow package — `journal.md`, `context.md`, the review artifacts — which is
491
- durable, searchable, and costs a reader nothing to skip.
492
- - A GitHub artifact that needs more than a short paragraph is a signal that the
493
- detail belongs in the flow with a link out, **not** that the paragraph should
494
- grow.
495
- - No orchestrator-written PR comment or reply exceeds two sentences without
496
- carrying a link to the artifact holding the detail. The reply pass enforces
497
- this; for anything else you write outward, hold yourself to it.
498
-
499
- This is deliberately asymmetric: **verbose in the flow, terse on GitHub.** The
500
- flow is written for whoever resumes the work; GitHub is read by someone who did
501
- not ask for our reasoning and is reading between other tasks.
485
+ PR bodies, comments, replies and commit messages lead with the conclusion, say what changed and where, and link rather than paste; verbose in the flow, terse on GitHub (`SKILL.detail.md` § "Everything written to GitHub is brief").
502
486
 
503
487
  ## Review Context Pack
504
488
 
@@ -696,49 +680,15 @@ record `model_assignment: adaptive` with the model you chose.
696
680
 
697
681
  ### Fix round check (Step 1a)
698
682
 
699
- A **fix round** is any review of work produced to answer earlier findings. Set
700
- `is_fix_round: true` on every reviewer input, and populate `prior_findings` with
701
- the earlier findings and the disposition the fix claimed for each.
702
-
703
- **The Jev edit guard is a FIX-phase tool, not a review-round tool.** `keryx review jev-edit-guard` (a separate feature) is the recommended Jev step during the FIX phase itself — run by the author's agent as it applies fixes, before this round re-reviews them. This skill never runs it; it is not part of review-orchestrator's own dispatch.
704
-
705
- **Nothing refuses a dispatch that omits them.** `reviewer-input.schema.json`
706
- states the rule and no production TypeScript loads that schema; reviewer
707
- dispatch is an action the host agent takes, not a `keryx` invocation, so there
708
- is no point at which a malformed dispatch could be rejected. `reviewer-input` is
709
- also absent from the `CONTRACTS` registry (`src/gdskills/contracts.ts`), so
710
- `keryx skills contracts validate` cannot be pointed at it either.
711
-
712
- So this is a requirement on you, unenforced, and the only evidence it was met is
713
- the `prior_findings` array the reviewer actually receives. A reviewer that cannot
714
- see what the fix was answering cannot tell whether the fix is complete.
715
-
716
- Two scope rules apply, and they exist because breaking them is what produced
717
- seven rounds on PR #215 and four on PR #216:
718
-
719
- 1. **Review `merge-base..HEAD`, never the fix commit alone.** Narrowing to the
720
- newest commit is the intuitive move and it is wrong: it hides the blast
721
- radius. A fix that changes a guard, an instruction, a refusal or a helper
722
- makes every *other* site that names it wrong, and those sites are outside the
723
- fix commit by construction.
724
-
725
- 2. **Enumerate what NAMES the thing the fix changed.** For each guard,
726
- instruction, message, refusal or helper the fix touched, grep for its callers
727
- and for the text that recommends it, and record the result in
728
- `review_context.scope.files`. On PR #216 a round corrected one operator
729
- instruction of four; the correction silently broke the other three, and
730
- nothing looked for them because nothing was asked to.
731
-
732
- Recording the enumeration matters as much as doing it: a round that searched and
733
- found nothing is a different fact from a round that never searched, and only the
734
- recorded list distinguishes them.
735
-
736
- Every prior finding leaves the round with a disposition — `closed`, `open`, `partial`,
737
- `regressed` or `withdrawn` — one line each in the report before the new findings, checked against
738
- the code and not the commit message. A fix is new code: scope A includes it, and the report carries
739
- a `## Regressions the fixes introduced` section. A finding this round disproves is withdrawn at the
740
- top of the report with its evidence. The table, recorded shapes and rationale:
741
- `SKILL.detail.md` § "Fix rounds — dispositions, regressions, withdrawal".
683
+ `keryx review start` (or `keryx review plan`) decides the round; you never pick a range. `<package>/round.json` says round N, the mode (`first`, `delta`, `fallback-first`), the source that found the previous round and the `range`; `<package>/prior_findings.json` holds the earlier findings. "Round 1 — no previous round found (sources tried …)" is a valid outcome: review as a first round and say which sources were tried.
684
+
685
+ - **`delta` round.** A FIX slice (`kind: fix`, a hunk that answers a prior finding) gets `review-logic`, `review-regression`, the authors of the findings attached to it and the verifier. Set `is_fix_round: true` and attach those findings as `prior_findings` on each of those reviewer inputs. A NEW slice (`kind: new`) is reviewed as round 1, with the roles its slice names. Code of `merge-base..head` that did not change since the previous round gets one cheap second look: SECOND-LOOK slices (`kind: second-look`, listed in `round.json` `secondLookHunks`) are read once per round by `review-logic` and `review-security-code` only, and their findings are ordinary findings. When round.json says "previous round weak: …" (the previous round did not complete, left uncovered slices, skipped required reviewers, had "Not run" lines, or reviewed a narrower scope) that code is `kind: new` instead and gets the full round-1 treatment. `review plan` prints "second-look: N slices / M dispatches". Carried findings keep their dispositions. An empty range (base equals head: a merged pull request read against its own target branch) is refused; pass the recorded base with `review start --base` / `review plan --ref`. A reviewer on a FIX slice returns `prior_dispositions: [{id, disposition}]` in its `REVIEW_RESULT`, one entry for every attached finding id.
686
+ - **`fallback-first` round** (force-push or rebase: the previous head is not an ancestor). Review `merge-base..head` in full, with the prior findings attached.
687
+ - **Every attached prior finding leaves the round with a disposition** — `closed`, `open`, `partial`, `regressed` or `withdrawn` — one line each in the report before the new findings, checked against the code and not the commit message. A fix is new code: the report carries a `## Regressions the fixes introduced` section. A finding this round disproves is withdrawn at the top of the report with its evidence. Table, recorded shapes and rationale: `SKILL.detail.md` § "Fix rounds — dispositions, regressions, withdrawal".
688
+ - **Duplicates.** `keryx review ingest` merges duplicate findings; later waves receive `known_findings` and do not report them again.
689
+ - **Enumerate what NAMES the thing the fix changed.** For each guard, instruction, message, refusal or helper a fix hunk touched, find its callers and the text that recommends it, and record the result in `review_context.scope.files`. On PR #216 a round corrected one operator instruction of four and silently broke the other three, because nothing looked. A round that searched and found nothing is a different fact from one that never searched; only the recorded list tells them apart.
690
+
691
+ **The Jev edit guard is a FIX-phase tool.** `keryx review jev-edit-guard` runs in the author's agent while it applies fixes; this skill never runs it. Nothing refuses a dispatch that omits them (the `prior_findings`): `reviewer-input.schema.json` states the rule, no production code loads it, and the `prior_findings` array a reviewer receives is the only evidence it was met.
742
692
 
743
693
  ### Step 2: Determine Review Mode
744
694
 
@@ -932,7 +882,7 @@ Three bounds keep it from deleting coverage:
932
882
 
933
883
  - **Only path-triggered reviewers.** A reviewer selected by an explicit flag, or
934
884
  one whose scope is the whole change rather than a path set — `review-logic`,
935
- `review-regression`, `review-verifier` — is never path-gated. One exception, for project reviewers only: a flag that more than one project reviewer carries is a **family flag** (the inventory lists it in that reviewer's `familyFlags`). It selects the whole family, and each member stays path-gated — `--<family>` over a diff touching one member's paths dispatches that member, not all of them.
885
+ `review-regression`, `review-verifier`, `review-premise` — is never path-gated. One exception, for project reviewers only: a flag that more than one project reviewer carries is a **family flag** (the inventory lists it in that reviewer's `familyFlags`). It selects the whole family, and each member stays path-gated — `--<family>` over a diff touching one member's paths dispatches that member, not all of them.
936
886
  - **Scope A only.** Scope B is the blast radius; it is *supposed* to name files the
937
887
  diff never touched.
938
888
  - **Ambiguity includes.** If you cannot decide whether a path matches, dispatch.
@@ -1061,6 +1011,7 @@ Review Plan Preview must include an `Optional legacy/profile reviewers` group (e
1061
1011
  | `--pr-contract` | `review-pr-contract` |
1062
1012
  | `--all` | all reviewers above (including `review-clean-code`, `review-highload`, and project convention reviewers when local convention docs exist); never the legacy/profile reviewers, which stay flag-only |
1063
1013
  | `--verify` | `review-verifier`, started on the first blocker or major and re-run for each later one (`SKILL.detail.md` § "Early verifier"); checks the findings by running something. Delete-only. |
1014
+ | (always, Wave D) | `review-premise` after the verifier, over the canonical findings of severity ≥ minor; judges whether each is a defect at all; lowers or holds, never adds. Not a fan-out flag |
1064
1015
  | (auto) | detected from diff file extensions — see Auto-detection table |
1065
1016
 
1066
1017
  Multiple flags may be combined: `review --backend --security` dispatches `review-logic` + `review-backend` + `review-architecture` + `review-security-code`; `review --frontend --frontend-conventions` dispatches the generic frontend set plus the local frontend conventions reviewer.
@@ -1113,6 +1064,7 @@ Dispatch selected reviewers in parallel when independent — this engine dispatc
1113
1064
  1. Wave A - core correctness/risk reviewers: logic, architecture, security/highload when selected.
1114
1065
  2. Wave B - domain reviewers: frontend/backend/testing/convention reviewers filtered to relevant files. `review-jev-rules` (flow 330), `review-jev-risk`/`review-jev-scenarios` (flow 332), `review-jev-docs`/`review-jev-comments` (flow 333), `review-jev-contract` (flow 335) also run here, CLI-engine not sub-agent, `"engine": "jev"` in `keryx review reviewers --json`, gated on their own opt-in and a resolvable Jev/OpenRouter credential — measured verdicts per reviewer (keep off by default, experimental, etc.) in `SKILL.detail.md` § "CLI-engine reviewers".
1115
1066
  3. Wave C - **verification**: `review-verifier` over the findings, started on the first blocker/major while other reviewers still run and re-run for each later one (`SKILL.detail.md` § "Early verifier"), or when `--verify` is set or the PR is high-risk. Exception to the A, B, C order: Wave C overlaps A and B and gets the findings held when each pass starts; Step 9b's `verify_order` applies to the later passes; each verifier pass is its own run. See below.
1067
+ 4. Wave D - **premise**: `review-premise` after the last verifier pass (see "Wave D" below).
1116
1068
 
1117
1069
  **Execution belongs to both B and C, and they execute for opposite reasons.** Wave C runs a command to *decide the fate of a finding that exists*; it is delete-only and can produce nothing. Wave B runs commands to *make findings* — `review-testing-practices` deletes each gate the diff added and records whether the suite goes red, and `review-layout` measures rendered geometry in a real engine.
1118
1070
 
@@ -1168,6 +1120,14 @@ Dispatch rules:
1168
1120
  rewritten finding, the merge discards that whole claim and records the attempt.
1169
1121
  Do not "help" by applying it.
1170
1122
 
1123
+ ### Wave D — the premise judge, after the verifier
1124
+
1125
+ A finding can reproduce and still not be a defect: one against a timeline pinned LTR on purpose, as platform practice advises, passed the verifier because the `dir="ltr"` really was there. `review-premise` asks the other question, on the deep tier and a clean context: intent, accepted practice, consistency, fix soundness.
1126
+ - Before dispatch, renumber any display id that another finding, carried or new, already has, in the saved reviewer results, so the judge, its claims and ingest all see the same ids. A new finding has no `global_id` yet (ingest mints `<reviewId>#<id>` after Wave D); ingest refuses two findings under one key, and a claim naming an id two findings share is rejected as `ambiguous-finding`.
1127
+ - Dispatch it once after the last verifier pass (no verifier ran: after the last reviewer), over the canonical findings of severity ≥ minor, each with its display `id`, the **real** `reviewer` and `source`, and, for a finding carried from an earlier round, its `global_id`. External (PR-comment, `source: external`) findings are included: they can be challenged, never downgraded. In a delta round only findings without a carried premise. On keryx shell the judge has no shell and no git tool: run `git log -L` and `git blame -L` for each cited site first and pass the output in `context_files`.
1128
+ - The judge's claims name the `id`, or a carried finding's `global_id`. Save its claims object unchanged to `research-evidence/premises.json` (the verdict reads it there) and pass that file with `keryx review ingest --premises <file>`; never apply verdicts by hand. The merge is delete-only: `upheld` changes nothing, `downgraded` lowers the severity, and a claim that adds, raises or rewrites is rejected and listed in `scope.md`.
1129
+ - `challenged` and `owner-decision` **hold** a finding: it is neither fixable nor clean — not an open blocker or major, never in a fix loop's `fix_context.review_feedback`, and it blocks until answered; the verdict lists it as awaiting the operator. **Asking about a held finding** (every skill that meets one points here): at the tail, after `ingest --premises` wrote `findings.json` (never during Wave D, before the ingest: the answer commands read `findings.json`), in keryx shell call the card `review_decide_premise`, which records the answer; elsewhere put its `question` and `options` to the operator with the host's question tool, then give them the exact command to run in their own terminal, `keryx review decide-premise --package <package> --finding <global_id> --answer uphold|dismiss --reason "<why>"`, and wait. Never run it yourself (it needs a terminal) and never write their reason. In a flow, journal the recorded answer. Readiness and the flow review gate fail while a held finding has no decision. Unattended: leave it held and report it.
1130
+
1171
1131
  ### `verification_mode`
1172
1132
 
1173
1133
  `off` | `annotate` | `filter`. **Default `annotate`, and it stays `annotate` for
@@ -1236,6 +1196,7 @@ Each reviewer must return a `REVIEW_RESULT` object matching `.metaproject/skills
1236
1196
  | Performance anti-patterns | NO | `review-performance` |
1237
1197
  | Style / naming / import order | NO | `review-style` |
1238
1198
  | Checking whether a reported finding is real | NO | `review-verifier` |
1199
+ | Judging whether a finding is a defect at all | NO | `review-premise` |
1239
1200
  | Clean Code principles + SOLID at code level | NO | `review-clean-code` |
1240
1201
  | Concurrency, resource pools, caching, queues, idempotency | NO | `review-highload` |
1241
1202
  | Frontend repository conventions | NO | `review-frontend-conventions` |
@@ -1350,17 +1311,12 @@ inventing a fifth level to express it would put us back where we started.
1350
1311
 
1351
1312
  ### Shared laws (every reviewer)
1352
1313
 
1353
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
1354
- name the input, call, or condition that reaches the code, you have an
1355
- observation, not a finding. Report it as `info` and say what would settle it.
1356
- 2. **Never flag the theoretical.** The path you describe must exist in the code
1357
- under review. Do not report a safe API because it could be misused, or a
1358
- pattern because it is often wrong elsewhere.
1359
- 3. **One finding per class, not one per occurrence.** When the same shape appears
1360
- at several sites, report it once and list every site. Ten findings that are one
1361
- finding hide the other nine problems.
1362
-
1363
- `review-security-code` carries a fourth — every security finding states its attack
1314
+ 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
1315
+ 2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
1316
+ 3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
1317
+ 4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.
1318
+
1319
+ `review-security-code` carries a fifth — every security finding states its attack
1364
1320
  vector — which does not generalise and stays there.
1365
1321
 
1366
1322
  ## Finding Format
@@ -1503,7 +1459,7 @@ file and must include the wire-contract line.
1503
1459
 
1504
1460
  ## Stage counts
1505
1461
 
1506
- Required in **How this review was run**, copied from `scope.md`, not re-counted by hand. State what each stage removed. Never state it as a precision improvement: no precision baseline exists to improve on. The line carries `verification_mode` (`off | annotate | filter`), confirmed / refuted / unverifiable / unverified, and retained.
1462
+ Required in **How this review was run**, copied from `scope.md`, not re-counted by hand. State what each stage removed. Never state it as a precision improvement: no precision baseline exists to improve on. The line carries `verification_mode` (`off | annotate | filter`), confirmed / refuted / unverifiable / unverified, the premise verdicts (upheld / downgraded / held), and retained.
1507
1463
 
1508
1464
  `## Checked and cleared` is now **Verified clean**. Same rule: a hypothesis
1509
1465
  that was tested and died, with the evidence, not a list of virtues. There is
@@ -1595,6 +1551,7 @@ When a prompt carries `JOB_NAME` and `CONTEXT_PATH`, read that context document
1595
1551
  | "A strict re-read of the findings will sharpen them" | That pass existed and was removed: self-correction without new evidence measured 95.5 → 91.5 → 89.0 on GSM8K and 75.8 → 38.1 on CommonSenseQA. Run something instead |
1596
1552
  | "Three reviewers agree, so the finding is verified" | Consensus is not evidence. 80+ agents unanimously endorsed a vulnerability that did not exist; one empirical test killed it |
1597
1553
  | "The verifier suggested a higher severity, I'll apply it" | It cannot suggest one. A claim carrying a severity is discarded whole and the attempt is recorded |
1554
+ | "The verifier confirmed it, so the fixer gets it" | Confirmed means the fact reproduces, not that it is a defect. Wave D judges the premise; a held finding waits for the operator |
1598
1555
  | "This finding has no `verification`, so it can be dropped" | Absent means nobody checked. All 83 recorded findings are in that state; none of them is thereby wrong |
1599
1556
  | "Precision went up after the verifier landed" | There is no precision baseline to have gone up from. State stage counts: dropped, refuted, retained |
1600
1557
  | "I'll widen the blast radius, this change looks risky" | It is bounded because review quality decays with context: F1 0.65 at round 2 → 0.29 at round 10. Widening makes the later rounds worse, not safer |
@@ -193,6 +193,19 @@
193
193
  "minLength": 1
194
194
  }
195
195
  },
196
+ "prior_dispositions": {
197
+ "title": "Dispositions of prior findings (FIX slices)",
198
+ "description": "Returned by a reviewer on a FIX slice: one entry for every attached prior finding id, giving its disposition checked against the code. The ledger reads it.",
199
+ "type": "array",
200
+ "items": {
201
+ "type": "object",
202
+ "required": ["id", "disposition"],
203
+ "properties": {
204
+ "id": {"type": "string", "minLength": 1},
205
+ "disposition": {"type": "string", "enum": ["closed", "open", "partial", "regressed", "withdrawn"]}
206
+ }
207
+ }
208
+ },
196
209
  "slices": {
197
210
  "title": "Slices this result covered",
198
211
  "description": "The ids of the dispatched slices the reviewer read. An entry is an id string, or an object with an `id`, an optional `coverage` note and an optional `status`. `keryx review retry-plan` and `ledger build` read both. An object counts as covered only when its `status` is absent or one of DONE, COMPLETE, COMPLETED, COVERED, OK (any case); any other status (NOT_READ, INCOMPLETE, SKIPPED, PARTIAL, …) leaves the slice uncovered and is named in the plan reason or the ledger gap. An entry with no id counts for nothing.",