@mrciphersmith/keryx 0.3.120 → 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 (39) hide show
  1. package/dist/cli.js +8511 -7282
  2. package/dist/core.js +954 -791
  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 +8 -17
  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 +36 -73
  10. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +1 -1
  11. package/src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json +17 -2
  12. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +6 -11
  13. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +6 -11
  14. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +6 -11
  15. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +5 -10
  16. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +5 -10
  17. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +6 -11
  18. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +5 -10
  19. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +6 -11
  20. package/src/gdskills/bundled/skills/review/review-jev-comments/SKILL.md +4 -9
  21. package/src/gdskills/bundled/skills/review/review-jev-contract/SKILL.md +4 -9
  22. package/src/gdskills/bundled/skills/review/review-jev-docs/SKILL.md +4 -9
  23. package/src/gdskills/bundled/skills/review/review-jev-risk/SKILL.md +4 -9
  24. package/src/gdskills/bundled/skills/review/review-jev-rules/SKILL.md +4 -9
  25. package/src/gdskills/bundled/skills/review/review-jev-scenarios/SKILL.md +4 -9
  26. package/src/gdskills/bundled/skills/review/review-layout/SKILL.md +8 -9
  27. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +6 -11
  28. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +25 -2
  29. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +34 -44
  30. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +1 -1
  31. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +6 -11
  32. package/src/gdskills/bundled/skills/review/review-pr-contract/SKILL.md +2 -2
  33. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +8 -10
  34. package/src/gdskills/bundled/skills/review/review-premise/SKILL.md +180 -0
  35. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +3 -3
  36. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +6 -11
  37. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +6 -11
  38. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +2 -2
  39. package/src/gdskills/contracts/review-finding.schema.json +63 -0
@@ -44,7 +44,7 @@ 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
 
@@ -55,8 +55,8 @@ license: "MIT"
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
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.
59
- 9. `keryx review verdict <package>` to the operator, then the tail: mutation pass, `ledger build`, `ingest`, `readiness`, `complete`.
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,22 +102,22 @@ 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.
109
- - Reviewers are read-only: they read the diff and the files and run no command. Only you (through `keryx review verify-run --timeout <seconds>`), the verifier and at most one testing reviewer run commands, inside a time budget. Each payload carries `allowed_tools` (`read-only` or `run-tests`) and `exec_budget_s`.
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`.
110
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`.
111
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`.
112
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`.
113
- - 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.
114
115
 
115
116
  ## Slices, waves and results — every host; keryx shell specifics marked
116
117
 
117
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.
118
119
 
119
- 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.
120
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.
121
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.
122
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.
@@ -128,11 +129,11 @@ A reviewer starts in the project root and reads project files; a path outside th
128
129
  ## Control
129
130
 
130
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).
131
- - **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`).
132
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.
133
- - **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").
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").
134
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").
135
- - **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`).
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`).
136
137
 
137
138
  ---
138
139
 
@@ -238,7 +239,7 @@ keryx review start --target <kind> --ref <ref>
238
239
  keryx review ingest --report <path> [--flow <id>] --ref <ref>
239
240
  [--verifications <file>] [--verification-mode off|annotate|filter]
240
241
  [--scope <scope.json>] [--blast-radius <blast-radius.json>]
241
- [--refuted <file>]
242
+ [--refuted <file>] [--premises <file>]
242
243
  # --blast-radius is REQUIRED whenever this round dispatched a
243
244
  # scope-B reviewer (review-regression). See below.
244
245
  keryx review status <review-id-or-path>
@@ -481,25 +482,7 @@ Read each run's verdict (`flaky` | `regression` | `infra`) into the report: `fla
481
482
 
482
483
  ## Everything written to GitHub is brief
483
484
 
484
- One rule, applied to every outward surface: **PR bodies, PR comments, review
485
- replies, issue comments, and commit messages going to a PR.**
486
-
487
- - Lead with the conclusion. No preamble, no restating the question, no apology,
488
- no summary of the flow.
489
- - Say what changed and where. **Link, do not paste.**
490
- - The reasoning, the evidence, the rejected alternatives and the round history live
491
- in the flow package — `journal.md`, `context.md`, the review artifacts — which is
492
- durable, searchable, and costs a reader nothing to skip.
493
- - A GitHub artifact that needs more than a short paragraph is a signal that the
494
- detail belongs in the flow with a link out, **not** that the paragraph should
495
- grow.
496
- - No orchestrator-written PR comment or reply exceeds two sentences without
497
- carrying a link to the artifact holding the detail. The reply pass enforces
498
- this; for anything else you write outward, hold yourself to it.
499
-
500
- This is deliberately asymmetric: **verbose in the flow, terse on GitHub.** The
501
- flow is written for whoever resumes the work; GitHub is read by someone who did
502
- 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").
503
486
 
504
487
  ## Review Context Pack
505
488
 
@@ -899,7 +882,7 @@ Three bounds keep it from deleting coverage:
899
882
 
900
883
  - **Only path-triggered reviewers.** A reviewer selected by an explicit flag, or
901
884
  one whose scope is the whole change rather than a path set — `review-logic`,
902
- `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.
903
886
  - **Scope A only.** Scope B is the blast radius; it is *supposed* to name files the
904
887
  diff never touched.
905
888
  - **Ambiguity includes.** If you cannot decide whether a path matches, dispatch.
@@ -1028,6 +1011,7 @@ Review Plan Preview must include an `Optional legacy/profile reviewers` group (e
1028
1011
  | `--pr-contract` | `review-pr-contract` |
1029
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 |
1030
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 |
1031
1015
  | (auto) | detected from diff file extensions — see Auto-detection table |
1032
1016
 
1033
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.
@@ -1080,6 +1064,7 @@ Dispatch selected reviewers in parallel when independent — this engine dispatc
1080
1064
  1. Wave A - core correctness/risk reviewers: logic, architecture, security/highload when selected.
1081
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".
1082
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).
1083
1068
 
1084
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.
1085
1070
 
@@ -1135,6 +1120,14 @@ Dispatch rules:
1135
1120
  rewritten finding, the merge discards that whole claim and records the attempt.
1136
1121
  Do not "help" by applying it.
1137
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
+
1138
1131
  ### `verification_mode`
1139
1132
 
1140
1133
  `off` | `annotate` | `filter`. **Default `annotate`, and it stays `annotate` for
@@ -1203,6 +1196,7 @@ Each reviewer must return a `REVIEW_RESULT` object matching `.metaproject/skills
1203
1196
  | Performance anti-patterns | NO | `review-performance` |
1204
1197
  | Style / naming / import order | NO | `review-style` |
1205
1198
  | Checking whether a reported finding is real | NO | `review-verifier` |
1199
+ | Judging whether a finding is a defect at all | NO | `review-premise` |
1206
1200
  | Clean Code principles + SOLID at code level | NO | `review-clean-code` |
1207
1201
  | Concurrency, resource pools, caching, queues, idempotency | NO | `review-highload` |
1208
1202
  | Frontend repository conventions | NO | `review-frontend-conventions` |
@@ -1317,17 +1311,12 @@ inventing a fifth level to express it would put us back where we started.
1317
1311
 
1318
1312
  ### Shared laws (every reviewer)
1319
1313
 
1320
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
1321
- name the input, call, or condition that reaches the code, you have an
1322
- observation, not a finding. Report it as `info` and say what would settle it.
1323
- 2. **Never flag the theoretical.** The path you describe must exist in the code
1324
- under review. Do not report a safe API because it could be misused, or a
1325
- pattern because it is often wrong elsewhere.
1326
- 3. **One finding per class, not one per occurrence.** When the same shape appears
1327
- at several sites, report it once and list every site. Ten findings that are one
1328
- finding hide the other nine problems.
1329
-
1330
- `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
1331
1320
  vector — which does not generalise and stays there.
1332
1321
 
1333
1322
  ## Finding Format
@@ -1470,7 +1459,7 @@ file and must include the wire-contract line.
1470
1459
 
1471
1460
  ## Stage counts
1472
1461
 
1473
- 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.
1474
1463
 
1475
1464
  `## Checked and cleared` is now **Verified clean**. Same rule: a hypothesis
1476
1465
  that was tested and died, with the evidence, not a list of virtues. There is
@@ -1562,6 +1551,7 @@ When a prompt carries `JOB_NAME` and `CONTEXT_PATH`, read that context document
1562
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 |
1563
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 |
1564
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 |
1565
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 |
1566
1556
  | "Precision went up after the verifier landed" | There is no precision baseline to have gone up from. State stage counts: dropped, refuted, retained |
1567
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 |
@@ -185,7 +185,7 @@
185
185
  "type": "string",
186
186
  "enum": ["read-only", "run-tests"],
187
187
  "default": "read-only",
188
- "description": "What the reviewer may do beyond reading. `read-only` (the default): read the diff and files, run no command. `run-tests`: at most one testing reviewer per round may run the tests, inside `exec_budget_s`. Verification commands go through the parent's `keryx review verify-run --timeout`."
188
+ "description": "What the reviewer may do beyond reading. `read-only` (the default): read the diff and files, and run no command, except the read-only history commands `git log`, `git blame` and `git show` (shared law 4; the premise judge too) where the host gives a read-only child git. On keryx shell a read-only child has no shell and no git tool: the parent passes `git log -L`/`git blame` output in `context_files`. `run-tests`: at most one testing reviewer per round may run the tests, inside `exec_budget_s`. Verification commands go through the parent's `keryx review verify-run --timeout`."
189
189
  },
190
190
  "exec_budget_s": {
191
191
  "type": "integer",
@@ -21,7 +21,7 @@ license: "MIT"
21
21
 
22
22
  ## Purpose
23
23
 
24
- Finds real, code-level performance problems introduced in the changed code of the current branch. Covers N+1 database queries, unnecessary React re-renders, missing memoization in hot paths, memory leaks, large bundle imports, synchronous blocking in async contexts, missing pagination, and redundant API calls. 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`.
24
+ Finds real, code-level performance problems introduced in the changed code of the current branch. Covers N+1 database queries, unnecessary React re-renders, missing memoization in hot paths, memory leaks, large bundle imports, synchronous blocking in async contexts, missing pagination, and redundant API calls. 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).
25
25
 
26
26
  This skill focuses on **measurable or high-likelihood bottlenecks** only. Premature optimization, hypothetical slowness, and style preferences are out of scope.
27
27
 
@@ -66,7 +66,7 @@ See shared script: `.metaproject/skills/gdskills/shared/git-merge-base.md`
66
66
 
67
67
  Run the script from that file to determine `MERGE_BASE` (`BASE_SHA`) and `SCOPE` before proceeding.
68
68
 
69
- **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:
69
+ **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:
70
70
  ```bash
71
71
  git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files --others --exclude-standard
72
72
  # explicit range: <FROM_SHA>..<TO_SHA> in place of "${BASE_SHA}"
@@ -196,15 +196,10 @@ Detectable from query patterns in changed code (not from DB schema directly):
196
196
 
197
197
  ### Shared laws (every reviewer)
198
198
 
199
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
200
- name the input, call, or condition that reaches the code, you have an
201
- observation, not a finding. Report it as `info` and say what would settle it.
202
- 2. **Never flag the theoretical.** The path you describe must exist in the code
203
- under review. Do not report a safe API because it could be misused, or a
204
- pattern because it is often wrong elsewhere.
205
- 3. **One finding per class, not one per occurrence.** When the same shape appears
206
- at several sites, report it once and list every site. Ten findings that are one
207
- finding hide the other nine problems.
199
+ 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.
200
+ 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.
201
+ 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.
202
+ 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.
208
203
 
209
204
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
210
205
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -36,8 +36,7 @@ frontend PR missed a documentation gap that sat in plain view: the body left
36
36
  the page that describes that table lives outside the diff. The box and the diff
37
37
  disagreed, and no reviewer held both.
38
38
 
39
- A finding here is a disagreement between two things you can quote: a line of
40
- `pr-context.md` and a line of the diff (or of a document). Nothing else is filed.
39
+ A finding here is a disagreement between two things you can quote: a line of `pr-context.md` and a line of the diff (or of a document). Nothing else is filed.
41
40
 
42
41
  ---
43
42
 
@@ -149,6 +148,7 @@ finding ids prefixed `PC-`, then a short summary; `NEEDS_CONTEXT` rather than a
149
148
  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.
150
149
  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.
151
150
  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.
151
+ 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.
152
152
 
153
153
  Severity levels are defined once, in `review-orchestrator/SKILL.md` → **Severity (canonical)**. This reviewer does not restate them: `blocker` is the four merge-blocking shapes named there and nothing else, and the `major`/`minor` boundary is the trigger-and-outcome test.
154
154
 
@@ -347,16 +347,12 @@ Assign one verdict per comment:
347
347
 
348
348
  Rules, and each one is a way this step goes wrong:
349
349
 
350
- 1. **A verdict carries evidence or it is `unverified`.** The file and line read,
351
- the query run, the commit cited, the test executed. A verdict reached by
352
- re-reading the comment is not a verdict on the code.
350
+ 1. **A verdict carries evidence or it is `unverified`.** The file and line read, the query run, the commit cited, the test executed. A verdict reached by re-reading the comment is not a verdict on the code.
353
351
  2. **`disagree` is a claim about the code, not about the reviewer.** It requires
354
352
  the decision it rests on to exist somewhere a reader can reach — a wiki page,
355
353
  a memory entry, an ADR, a test that pins the behaviour. "It is fine" is
356
354
  `unverified`.
357
- 3. **Never lower a comment's severity to make it disappear.** Severity is set by
358
- the collector; this step assigns a *verdict*, and a `minor` comment that is
359
- `valid` is still fixed.
355
+ 3. **Never lower a comment's severity to make it disappear.** Severity is set by the collector; this step assigns a *verdict*, and a `minor` comment that is `valid` is still fixed. The premise judge cannot lower it either (rule 7).
360
356
  4. **`needs-clarification` is asked before `--fix` runs, not after.** State both
361
357
  readings and what each would change. A guess here produces a fix nobody asked
362
358
  for and a reply that answers the wrong question.
@@ -367,6 +363,7 @@ Rules, and each one is a way this step goes wrong:
367
363
  6. **A `praise` comment takes no verdict.** It makes no claim about the code, so
368
364
  there is nothing to establish. It is still answered in Step 10, because the
369
365
  reply pass requires a decision for every comment it sees.
366
+ 7. **A `valid` comment has its premise checked before it enters the plan.** Before Step 8, dispatch `review-premise` with `source: external-comment` over the `valid` and `valid-wider` comments of severity `minor` or above, each as one finding: `id` its collected `C-NNN`, `url` its URL, `reviewer` its author, `source: external`, the comment text and its `file:line` refs (review-premise, `source` row). An external finding is upheld, challenged or owner-decision, never downgraded. This skill has no review package, so no `ingest` or `decide-premise` runs: save the claims object unchanged beside the durable record, as `.metaproject/reviews/pr-comments/<owner>__<repo>__<n>.premise.json`, apply the merge's refusals by hand (the same `source` row lists them), and record each claim on the comment's Step 7 entry (**Premise**). A `challenged` or `owner-decision` comment is held: ask the operator its question with its options (`ask_user` in keryx shell, the host's question tool elsewhere) and record their answer, in their words, on that entry: it is the one record of it, which a resumed or `--fix` run reads, and the report's Stats count it. An upheld comment is planned and passed in `fix_context.review_feedback`, carrying `premise_verdict` and `premise_answer` as task-implementer's `FIX_CONTEXT` defines them; a dismissed one takes verdict `disagree`, citing that recorded answer as its decision (rule 2), and is answered in Step 10 with no code change. Never dismiss it yourself.
370
367
 
371
368
  ---
372
369
 
@@ -390,6 +387,7 @@ For each comment:
390
387
  ```typescript
391
388
  // Corrected code example
392
389
  ```
390
+ - **Premise** (rule 7): upheld, or held with the judge's question and the operator's answer in their words
393
391
  - **Plan item**: P-00N, or "none" with the reason
394
392
  - **Confidence**: High | Medium | Low
395
393
  - High: reviewer's intent is clear and the fix is straightforward
@@ -453,8 +451,8 @@ it into a fix the reviewer did not ask for.
453
451
 
454
452
  1. `--fix` was passed explicitly.
455
453
  2. Step 3 ran through the CLI and the durable record exists.
456
- 3. No comment is still `needs-clarification`, and none carries an unreviewed
457
- `prompt-injection` finding.
454
+ 3. No comment is still `needs-clarification` or held without the operator's answer
455
+ (rule 7), and none carries an unreviewed `prompt-injection` finding.
458
456
  4. The working tree is clean and Task Manager is enabled
459
457
  (`modules.tasks.enabled: true`).
460
458
  5. The reviewed PR is open.
@@ -524,7 +522,7 @@ branch on purpose.
524
522
  "operator_confirmed": { "confirmed_by": "<who>", "confirmed_at": "<iso8601>", "plan_digest": "<digest of the plan shown>" },
525
523
  "constraints": [
526
524
  "pr: open it as a draft, titled 'fix(review): address feedback on #<n>', body linking #<n> and listing which plan item answers which comment.",
527
- "review: run review-orchestrator on every round, starting each round with `keryx review start` (or `keryx review plan`) on the new head: the round, its range and the prior findings come from `round.json`. No own range, no `--all` per round, no whole-branch re-review. The loop's exit threshold is the one your own PR review/fix loop defines; do not take it from this string.",
525
+ "review: run review-orchestrator on every round, starting each round with `keryx review start` (or `keryx review plan`) on the new head: the round, its range and the prior findings come from `round.json`. No own range, no `--all` per round, no whole-branch re-review. The loop's exit threshold is the one your own PR review/fix loop defines; do not take it from this string. Every plan item's comment was premise-checked in review-pr-feedback rule 7 and each held one answered by the operator (its Premise entry; claims in .metaproject/reviews/pr-comments/<owner>__<repo>__<n>.premise.json): do not run review-premise again before freeze.",
528
526
  "review: the fix PR is its own conversation — collect and reply on IT as normal. The round MUST NOT run a reply pass against #<n>: a reply there writes the durable record, so the post-merge answer citing the merge SHA is skipped as already-handled and the reviewer is left holding a mid-loop answer that has since stopped being true.",
529
527
  "attempt budget: at most <max_fix_rounds> review/fix attempts. This LOWERS your bound and never raises it; absent the value, your own bound stands. The `keryx review loop` repetition check applies either way. Do not raise anything to reach a clean round; escalate instead.",
530
528
  "scope: the plan items only. A finding outside them is recorded as follow-up, not fixed in this flow."
@@ -812,7 +810,7 @@ Full markdown report structure:
812
810
 
813
811
  ## Stats
814
812
  - blocker: N / major: N / minor: N / info: N / praise: N
815
- - verdicts: valid N, already-fixed N, disagree N, out-of-scope N, unverified N
813
+ - verdicts: valid N, already-fixed N, disagree N, out-of-scope N, unverified N; premise: upheld N, held N (each answer is on its Step 7 **Premise** entry)
816
814
 
817
815
  ## By Author
818
816
  ### <reviewer-login> (N comments — REQUEST_CHANGES)
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: review-premise
3
+ model_tier: deep
4
+ description: |
5
+ Use when: findings exist and someone is about to act on them — after the verifier in a
6
+ review round (Wave D), or before a fix loop implements a finding that came from a
7
+ follow-up issue or an external review comment. Judges whether each finding is a defect
8
+ at all, on intent, accepted practice, consistency and fix soundness, and returns
9
+ upheld | downgraded | challenged | owner-decision. It can only lower a severity or hold a
10
+ finding for the operator; it never adds a finding, raises a severity or edits its text.
11
+ NOT for: first-pass review (run domain reviewers first); checking whether a finding
12
+ reproduces (review-verifier); dismissing a finding, which only the operator does.
13
+ triggers:
14
+ - "judge the premise of these findings"
15
+ - "review --premise"
16
+ - "is this standard practice"
17
+ - "is this finding a real defect"
18
+ metadata:
19
+ author: "MrCipherSmith"
20
+ version: "1.0.0"
21
+ category: "review"
22
+ compatible_harnesses: "cursor,codex,zed,opencode,claude"
23
+ origin: "authored"
24
+ license: "MIT"
25
+ ---
26
+
27
+ # Review — Premise
28
+
29
+ Wave D. A finding can reproduce and still be wrong. The verifier asks whether the fact a
30
+ finding names is there; this judge asks whether that fact is a defect. It reads each
31
+ finding on a clean context, judges it, and emits one premise claim per finding. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.
32
+
33
+ ## The case this exists for
34
+
35
+ A final review reported: *the playback timeline is pinned LTR — two components hard-code
36
+ `dir="ltr"`, so the timeline does not mirror in RTL.* The fact was true and reproduced.
37
+ The finding was still wrong. Platform guidance says media playback controls and their
38
+ progress indicator do not mirror (Material Design, Bidirectionality; Apple HIG, Right to
39
+ left), and the code carried three signals of a deliberate choice: the explicit override,
40
+ a lint exemption naming that area a physical-LTR island, and a sibling media control
41
+ forcing the same direction. The finding was implemented; two reviews of the fix checked
42
+ only the implementation. Asked "is this standard practice?", a model refuted it in one turn.
43
+
44
+ ## Workflow
45
+
46
+ ```
47
+ review-premise Progress:
48
+ - [ ] Step 1: Drop every finding below `minor`
49
+ - [ ] Step 2: Per finding, read only its bare claim (title, file, quote) and the code there; form a view
50
+ - [ ] Step 3: Collect intent signals at and around the site (see question 1)
51
+ - [ ] Step 4: Answer the four questions
52
+ - [ ] Step 5: Only now read the reviewer's problem, impact, evidence and suggested_fix; revise if they show something you missed
53
+ - [ ] Step 6: Emit one premise claim per finding judged, and nothing else
54
+ ```
55
+
56
+ The order of steps 2 and 5 is the point. A reviewer's argument read first anchors the
57
+ judgement on it; the claim and the code read first let you see what the reviewer did not.
58
+
59
+ ## Input Contract
60
+
61
+ | Field | Type | Required | Description |
62
+ |-------|------|----------|-------------|
63
+ | `findings` | array | yes | Canonical findings (`review-finding.schema.json`), each with its display `id`, unique in the package (the caller renumbers a collision, a new finding sharing a carried one's id included, in the saved reviewer results before you run): your claim's `finding_id` (a claim may name an id the duplicate merge absorbed; it then targets the surviving finding). Only a finding carried from an earlier round also has a `global_id` (ingest mints the rest after you run); a claim may name a carried finding by it. Each has `reviewer`, `severity`, `source` (`external` marks a PR comment), `file`, `quote`, `problem`, `suggested_fix`. In a delta round, only findings with no carried premise. |
64
+ | `judge` | string | yes | Your own name. Recorded on the claims file. |
65
+ | `source` | string | no | `round` (default), `follow-up-issue` or `external-comment`: where the findings came from. The last two have no review package: each finding is the issue or comment text as `problem`, its `file:line` refs as `file`/`line` with the code there as `quote`, the comment's `C-NNN` (review-pr-feedback) or the issue's number as `id` with its URL as `url`, its author as `reviewer` and the severity it states (else `minor`). The caller saves your claims beside its own record (a flow: `<flow-dir>/premise/<n>.json`) and journals the operator's answer; no `ingest` or `decide-premise` runs, so the caller applies every refusal of the merge (`PREMISE_REJECTION_REASONS`, `src/review/premise.ts`) by hand. For one finding those are: any claim on a finding below `minor` (`below-minor`); an uncited `challenged` or `downgraded`; a `downgraded` with no `severity`, or with the finding's own severity (`not-a-downgrade`) or a higher one (`raise-severity`); a `severity` on any other verdict (`severity-without-downgrade`); a downgrade of an external or `review-security-code` finding, of a `minor`, or below `minor`; a hold without a `question`; an `owner-decision` with fewer than two options; a judge that raised the finding. |
66
+ | `branch` / `base_sha` | string | no | So `git log` and `git blame` read the change under review, where your host gives you git; on keryx shell the caller passes their output in `context_files`. |
67
+
68
+ ## The four questions
69
+
70
+ 1. **Intent.** Is the thing called a defect a deliberate choice? Look for an explicit
71
+ override (`dir="ltr"`, `!important`, a pinned version, a forced flag), a suppression or
72
+ exemption (a lint disable, a `@ts-expect-error` with a reason, an allowlist entry), a
73
+ comment or commit message giving a reason (`git log -L <start>,<end>:<file>`, `git blame`, `git show <sha>`
74
+ where your host gives you git; on keryx shell, the history excerpts the caller passes in `context_files`), and
75
+ sibling code doing the same. A signal does not prove the choice right; it proves someone chose, so the finding has to show their reason wrong.
76
+ A signal the branch under review itself introduces (in `git log <base>..<head>`, or in lines
77
+ the diff adds) is not evidence of a prior deliberate choice: the change cannot ratify itself.
78
+ 2. **Accepted practice.** What do platform guidelines (Material Design, Apple HIG, WCAG,
79
+ the framework's own docs), the language's idioms, clean-code principles and common
80
+ patterns say? Then the project's own rules, with their known exceptions. A project rule
81
+ applied where accepted practice makes an exception is not a defect.
82
+ 3. **Consistency.** Would the suggested fix make the system more consistent or less? A fix
83
+ that makes one site differ from siblings doing the same thing is evidence against the
84
+ premise, not a follow-up.
85
+ 4. **Fix soundness.** Would a senior reviewer reject the suggested fix? A fix that is wrong
86
+ for the platform usually means the premise is wrong too.
87
+
88
+ ## Verdicts
89
+
90
+ | Verdict | Meaning | Must carry |
91
+ |---|---|---|
92
+ | `upheld` | The premise stands; the finding goes on unchanged. | — |
93
+ | `downgraded` | A defect, but intent or practice shows it is smaller than reported. Never for a `minor`, an external or a `review-security-code` finding: hold those with `challenged` or `owner-decision` instead. | `severity`, strictly lower and never below `minor`, and ≥1 `intent_signals` or `practice_sources` |
94
+ | `challenged` | Evidence says it is not a defect. | ≥1 `intent_signals` or `practice_sources`, and a `question` |
95
+ | `owner-decision` | A product choice the code cannot settle either way. | a `question` and ≥2 `options` |
96
+
97
+ `challenged` and `owner-decision` **hold** the finding: it does not count as an open
98
+ blocker or major, it is not sent to a fixer, and the verdict lists it as awaiting the
99
+ operator, who answers with `keryx review decide-premise` (`uphold` or `dismiss`). You never
100
+ dismiss. `upheld` is the normal answer: a finding with a trigger, an outcome, no intent
101
+ signal and no practice source against it is upheld.
102
+
103
+ ## Iron Laws
104
+
105
+ | Rule | Why |
106
+ |------|-----|
107
+ | **You can only lower or hold.** No new finding, no raised severity, no edit to a finding's text. | The merge builds the record from the original finding and takes only your verdict; a claim carrying more is rejected (`unknown-property`), an entry that is no object too (`malformed-claim`). |
108
+ | **Never judge your own finding.** | The merge rejects a judge equal to the reporter (`self-judgement`). |
109
+ | **Claim first, argument second.** | The case passed two reviews that read the fix's argument and never the premise. |
110
+ | **`challenged` cites.** Each intent signal names its `ref` (`file:line` or a SHA) and what it says; each practice source names the guideline and section precisely enough to look up. | An uncited challenge is rejected and the finding stays as reported. Never invent a quote. |
111
+ | **Never re-grade by the rubric.** Severity is the reviewer's and the verifier's call; a test gap or a surviving mutant stays as reported unless intent or practice shrinks it, and a minor is upheld or challenged, never downgraded. | An uncited downgrade is rejected (`downgrade-without-evidence`). Minors matter: a finding you weaken is one nobody fixes. |
112
+ | **Read-only.** Read files; run nothing but `git log`, `git blame` and `git show`, and those only where your host gives a read-only child git. On keryx shell you have no shell and no git tool: read the history excerpts in `context_files`, or say the history was not read. | Executing is the verifier's job; this judgement is about meaning. |
113
+ | **An external finding, and a `review-security-code` finding, is held or upheld, never dismissed or downgraded.** | A human asked; the operator answers them. Severity of a security finding measures exposure, which intent does not lower. The merge rejects the downgrade (`external-downgrade`, `security-downgrade`). |
114
+
115
+ ## Output Contract
116
+
117
+ ```
118
+ STATUS: DONE | NEEDS_CONTEXT | BLOCKED
119
+ ```
120
+
121
+ - `DONE` — every finding given was judged or explicitly left alone (below `minor`).
122
+ - `NEEDS_CONTEXT` — the code at a finding's site cannot be read; say which.
123
+ - `BLOCKED` — the findings input is unreadable or carries no ids.
124
+
125
+ Then one premise claims object. The orchestrator saves it unchanged as the file
126
+ `keryx review ingest --premises <file>` reads:
127
+
128
+ ````text
129
+ ```json keryx:premises
130
+ {
131
+ "judge": "review-premise",
132
+ "model": "<model id>",
133
+ "premises": [
134
+ {
135
+ "finding_id": "LY-003",
136
+ "verdict": "challenged",
137
+ "intent_signals": [
138
+ { "ref": "src/player/TimelineSlider.tsx:150", "says": "explicit dir=\"ltr\" on the timeline root" },
139
+ { "ref": "eslint.config.js:42", "says": "exemption names this area a physical-LTR scroll/pixel island" },
140
+ { "ref": "src/player/MediaControls.tsx:81", "says": "sibling media control forces the same direction" }
141
+ ],
142
+ "practice_sources": [
143
+ { "name": "Material Design — Bidirectionality", "says": "media playback controls and progress do not mirror" },
144
+ { "name": "Apple HIG — Right to left", "says": "video controls and timeline indicators keep their direction" }
145
+ ],
146
+ "reasoning": "The fact reproduces, but LTR is the platform practice for playback and the code chose it three times.",
147
+ "question": "The timeline is LTR on purpose, as platforms do. Keep it, or mirror it anyway?",
148
+ "options": ["dismiss — keep LTR, as platforms do", "uphold — mirror the timeline"]
149
+ },
150
+ { "finding_id": "LG-002", "verdict": "downgraded", "severity": "minor", "intent_signals": [{ "ref": "src/a.ts:12", "says": "comment: legacy fallback kept until v3, read-only" }], "reasoning": "A real defect in a path the code marks as legacy and read-only." },
151
+ { "finding_id": "LG-004", "verdict": "upheld", "reasoning": "No signal of intent; the null path is reachable from the form reset." }
152
+ ]
153
+ }
154
+ ```
155
+ ````
156
+
157
+ Then a short markdown summary: counts per verdict, and for each held finding its id, the
158
+ question, and the signals or sources behind it.
159
+
160
+ ## Scope Boundaries
161
+
162
+ | Concern | This skill | Use instead |
163
+ |---------|------------|-------------|
164
+ | Whether a finding is a defect at all | YES | — |
165
+ | Lowering a severity, holding a finding for the operator | YES | — |
166
+ | Whether a finding reproduces | NO | `review-verifier` |
167
+ | Adding a finding, raising a severity, editing one | **NO** | a domain reviewer in a new round |
168
+ | Dismissing a finding | NO | the operator: `keryx review decide-premise --answer dismiss` |
169
+
170
+ ## Red Flags
171
+
172
+ | Rationalization | Why it is wrong |
173
+ |----------------|-----------------|
174
+ | "The fact reproduces, so the finding is right." | Reproducing proves the fact, not the defect. The case reproduced. |
175
+ | "The reviewer's argument is convincing." | That is why you read it last. |
176
+ | "A sibling does the same; that is a follow-up." | A sibling doing the same is a signal of intent, against the premise. |
177
+ | "The project rule says X, so any deviation is a defect." | Check the rule against platform practice and its known exceptions first. |
178
+ | "It is clearly wrong; I will mark it dismissed." | You cannot dismiss. Hold it with a question; the operator decides. |
179
+ | "Challenge anything ambiguous, to be safe." | A held finding costs the operator a question. Without a cited signal or source it is upheld. |
180
+ | "I will run the tests to be sure." | Read-only. Running something is the verifier's method, not yours. |
@@ -22,15 +22,14 @@ license: "MIT"
22
22
  # Review: Regression
23
23
 
24
24
  You are reviewing **scope B** of a deep round. The files you are given are not
25
- under review. They are under **regression check**. 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`.
25
+ under review. They are under **regression check**. 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).
26
26
 
27
27
  ## The one question
28
28
 
29
29
  > Does this change break an existing behaviour here?
30
30
 
31
31
  Not "is this code good". Not "would I have written it this way". The blast-radius
32
- set is code that already worked; your job is to find where the change stops it
33
- working.
32
+ set is code that already worked; your job is to find where the change stops it working.
34
33
 
35
34
  This is enforced, not requested. `keryx review ingest` runs
36
35
  `screenBlastRadiusFindings` over the findings this scope returns and refuses
@@ -171,6 +170,7 @@ Severity comes from **Severity (canonical)** in `review-orchestrator/SKILL.md`;
171
170
  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.
172
171
  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.
173
172
  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.
173
+ 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.
174
174
 
175
175
  Severity levels are defined once, in `review-orchestrator/SKILL.md` → **Severity (canonical)**. This reviewer does not restate them: `blocker` is the four merge-blocking shapes named there and nothing else, and the `major`/`minor` boundary is the trigger-and-outcome test.
176
176