@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.120",
3
+ "version": "0.3.121",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -455,7 +455,7 @@
455
455
  },
456
456
  "review-core-skills": {
457
457
  "kind": "skill",
458
- "description": "Generic (non-stack-specific) review skills: orchestrator, logic, architecture, security, performance, clean-code, highload, regression, core-boundaries, flow-graph, layout, style, testing-practices, verifier, pr-feedback, and the legacy AI/learned/style review profiles.",
458
+ "description": "Generic (non-stack-specific) review skills: orchestrator, logic, architecture, security, performance, clean-code, highload, regression, core-boundaries, flow-graph, layout, style, testing-practices, verifier, premise, pr-feedback, and the legacy AI/learned/style review profiles.",
459
459
  "paths": [
460
460
  "src/gdskills/bundled/skills/review/review-orchestrator/**",
461
461
  "src/gdskills/bundled/skills/review/review-logic/**",
@@ -472,6 +472,7 @@
472
472
  "src/gdskills/bundled/skills/review/review-style/**",
473
473
  "src/gdskills/bundled/skills/review/review-testing-practices/**",
474
474
  "src/gdskills/bundled/skills/review/review-verifier/**",
475
+ "src/gdskills/bundled/skills/review/review-premise/**",
475
476
  "src/gdskills/bundled/skills/review/review-pr-feedback/**",
476
477
  "src/gdskills/bundled/skills/review/code-ai-review/**",
477
478
  "src/gdskills/bundled/skills/review/code-learned-review/**",
@@ -36,7 +36,7 @@ in progress, so it never makes the agent continue on its own, which is what make
36
36
  |---|---|---|
37
37
  | `job-orchestrator` | the step ids `keryx job status <name> --json` reports — `analyze`, `context`, `prepare`, `tests-creator`, `implement`, `sanity-check`, `verify`, `review`, `security`, `fix`, `verify-post-fix`, `perf-check`, `report`, `pr`, `deploy` | `keryx job status <name>` (read it, never retype it) |
38
38
  | `flow-orchestrator` | the Flow's task ids `T1..Tn` | `keryx flow status <id>` / the Flow's `tasks.md` |
39
- | `review-orchestrator` | `step-0` … `step-14`, from its own numbered checklist | its Workflow section |
39
+ | `review-orchestrator` | `step-0` … `step-14` and `step-10b`, from its own numbered checklist | its Workflow section |
40
40
 
41
41
  An id that exists only in the session plan is drift by construction: the operator
42
42
  cannot reconcile it with the CLI, and a resumed run cannot match it. If a
@@ -39,7 +39,7 @@ End-to-end feature development workflow from idea to merge-ready PR.
39
39
 
40
40
  ### Phase 1: REQUIREMENTS + SPEC
41
41
 
42
- 1. Parse input (description or GitHub issue via `gh issue view`)
42
+ 1. Parse input (description or GitHub issue via `gh issue view`). An issue filed from a review finding, or an external review comment, is a premise to check: dispatch `review-premise` on it first, shaped and recorded as `flow-orchestrator` Phase 1 says ("A flow sourced from a finding": no `decide-premise`; claims in `<flow-dir>/premise/<n>.json` if a flow exists; with none, its claims object goes into the Implementation Spec under **Premise**), and on `challenged` or `owner-decision` ask the operator its question with its options and journal their answer before writing the spec
43
43
  2. Clarify ambiguities — ask the user up to 3 questions max
44
44
  3. Produce the **Implementation Spec** (per `implementation-doc-mandate.mdc`):
45
45
  - **What**: feature description in 2-3 sentences
@@ -48,8 +48,8 @@ End-to-end feature development workflow from idea to merge-ready PR.
48
48
  - **Acceptance criteria**: testable bullet points
49
49
  - **Approach**: which files will change, key design decisions
50
50
  - **Test strategy**: framework, which scenarios will be covered
51
- 4. **Save spec** to `.feature-spec.md` in project root (add to .gitignore if not already)
52
- 5. **Get user confirmation before proceeding**
51
+ - **Premise** (only for an input sourced from a finding, with no flow): the review-premise claims object and the operator's answer, in their words
52
+ 4. **Save spec** to `.feature-spec.md` in project root (add to .gitignore if not already), then **get user confirmation before proceeding**
53
53
 
54
54
  ### Phase 2: DESIGN
55
55
 
@@ -113,7 +113,7 @@ Input: codebase_path=<project_root>, scope=changed, base_branch=<base>
113
113
  - `git diff main...HEAD` — review the full diff
114
114
  - Check for: TODOs left behind, console.logs, hardcoded values
115
115
  - Verify all acceptance criteria from Phase 1 spec
116
- 3. Fix any findings (max 2 review-fix cycles). Each next round is `keryx review start` or `keryx review plan` on the new head: the round comes from `round.json`; no own range, no whole-branch re-review (the `git diff main...HEAD` above is round 1 only).
116
+ 3. Fix any findings (max 2 review-fix cycles), never one `review-premise` holds: a held finding is neither fixable nor clean and blocks the cycle until answered; ask the operator about it as `review-orchestrator` "Wave D" says, and only an upheld one is fixed, carrying `premise_verdict` and `premise_answer` as task-implementer's `FIX_CONTEXT` defines them (unattended: stop and report the held list). Each next round is `keryx review start` or `keryx review plan` on the new head: the round comes from `round.json`; no own range, no whole-branch re-review (the `git diff main...HEAD` above is round 1 only).
117
117
  4. Re-run `code-verifier` after any fixes
118
118
 
119
119
  ### Phase 8: DELIVER + CHANGE REPORT
@@ -264,17 +264,8 @@ Tasks are the mechanism for this. `keryx flow complete` runs a `tasks` gate over
264
264
 
265
265
  Know the gate's exact scope, because for years this file claimed a gate that did not exist and 24 completed flows shipped with an open task:
266
266
 
267
- - the gate is **opt-in per flow package**, keyed on `gates.tasks` in
268
- `flow.json`, which `keryx flow init` writes for every flow it creates. A
269
- package created before the gate landed does not carry the flag, and for it
270
- the gate reports `skipped` and blocks nothing;
271
- - a task fails the gate when its status is not `done`; when its disposition is
272
- `failed`; when its disposition is `blocked` (terminal, but the work did not
273
- happen — and the harness emits this disposition on its own for a run that
274
- ended blocked); when its disposition is `skipped` with no recorded reason; or
275
- when its disposition is a value this build does not recognise. An
276
- unrecognised disposition FAILS rather than falling through: a gate whose
277
- default for the unknown case is "pass" is not a gate;
267
+ - the gate is **opt-in per flow package**, keyed on `gates.tasks` in `flow.json`, which `keryx flow init` writes for every flow it creates. A package created before the gate landed does not carry the flag, and for it the gate reports `skipped` and blocks nothing;
268
+ - a task fails the gate when its status is not `done`; when its disposition is `failed`; when its disposition is `blocked` (terminal, but the work did not happen — and the harness emits this disposition on its own for a run that ended blocked); when its disposition is `skipped` with no recorded reason; or when its disposition is a value this build does not recognise. An unrecognised disposition FAILS rather than falling through: a gate whose default for the unknown case is "pass" is not a gate;
278
269
  - to close a task as deliberately not needed, record why:
279
270
 
280
271
  ```bash
@@ -283,6 +274,8 @@ Know the gate's exact scope, because for years this file claimed a gate that did
283
274
 
284
275
  Read the `tasks` line in the `flow complete` output. If it says `skipped`, the gate did not run and the task list is yours to verify by hand.
285
276
 
277
+ **A flow sourced from a finding: check its premise before freeze.** A follow-up issue filed from a review, or an external review comment, is a premise to check, not a settled requirement. Before `flow freeze`, dispatch `review-premise` with `source: follow-up-issue` or `external-comment` and the finding shaped as its Input Contract `source` row says (the issue number or the comment's `C-NNN` as `id`, its URL as `url`). Skip it when the dispatch says the premise is already recorded (`review-pr-feedback` rule 7 sends a `premise:` constraint). No review package exists, so no `ingest` or `decide-premise` runs: save its claims as `<flow-dir>/premise/<n>.json`, and apply every refusal of the merge by hand, as that `source` row lists them (`PREMISE_REJECTION_REASONS`, `src/review/premise.ts`): a refused claim leaves the finding upheld. On `challenged` or `owner-decision` ask the operator its question with its options (`ask_user` in keryx shell, the host's question tool elsewhere), journal their answer, and plan only what the operator upholds.
278
+
286
279
  Then freeze and start (`--yes`: the operator already answered the kinds question, so the freeze must not prompt):
287
280
 
288
281
  ```bash
@@ -444,6 +437,7 @@ Before accepting implementation:
444
437
  6. If findings require code changes, run a fix round through `task-implementer`, recorded as a flow fix task:
445
438
  - **Scope freeze.** A fix round fixes the round's findings and nothing else. Hardening, refactors or new cells a fix suggests go to the operator as a question (as in step 4); never grow scope inside a fix round.
446
439
  - **Red probes → ONE implementer.** When reviewers left red probes (failing tests or commands on the findings), pass them as `test_case_specs` to one `task-implementer` dispatch — no separate `tests-creator` task. `tests-creator` runs only for a new contract no probe covers.
440
+ - **A held finding is not fixed.** A finding `review-premise` held (`challenged` or `owner-decision`) is neither fixable nor clean: it never goes into `fix_context.review_feedback` and it blocks the loop until answered. Ask the operator about it as `review-orchestrator` "Wave D" says (the card in keryx shell; elsewhere the question tool, then the exact `keryx review decide-premise` command for them to run in their terminal) and journal the recorded answer; only an upheld finding enters a fix round, carrying `premise_verdict` and `premise_answer` as task-implementer's `FIX_CONTEXT` defines them. A dispatched run leaves it held and journals it.
447
441
  - **`suggested_fix` is a hypothesis.** Pass each finding's `id` and `suggested_fix` in `fix_context.review_feedback`; the implementer reproduces the finding (red), checks the suggestion against the state × event matrix, then fixes (task-implementer 1.3). Journal every `suggested_fix diverged` / `did not reproduce` note it returns.
448
442
  7. Close the skill-learning loop (see `rules/core/skill-lifecycle.mdc`). Collect
449
443
  the `skill_drift` fields from task-implementer results and the
@@ -533,15 +527,11 @@ the bound plus an escalation — never an unbounded loop.
533
527
  ### PR review/fix loop
534
528
 
535
529
  1. Each round — the first and every one after a fix — is `keryx review start` on the PR's current head, then `review-orchestrator` from that package. `review start` finds the previous round itself (local package, git history, the PR's round block, the flow package) and, when the previous reviewed head is an ancestor, reviews the delta: fix changes with a small roster (logic, regression, the findings' authors, the verifier) and the prior findings attached, new changes as round 1, unchanged code carried with its dispositions. Never pass a whole-branch range or `--all` per round; `<package>/round.json` records the round, its source and its mode.
536
- 2. If findings or required check failures remain, run a fix round under Phase 3 step 6 (flow fix task, `task-implementer`), push the fix, and run the next round as in step 1.
530
+ 2. If findings (held ones aside: Phase 3 step 6) or required check failures remain, run a fix round under Phase 3 step 6 (flow fix task, `task-implementer`), push the fix, and run the next round as in step 1.
537
531
 
538
532
  **A required check failure is not automatically a fix task.** When `review.jev.ci_triage` is on, run `keryx review ci-triage --run <id> --json` on each failed run first: `top: flaky` (or a `deterministic` override) → rerun once (`gh run rerun --failed <id>`), record it in `journal.md`, and treat a second failure as `real-regression` regardless; `top: real-regression` → investigate and fix as usual; `top: infra` → report it in the completion notes and leave the code alone. The verdict is advisory only — never the sole reason to skip a fix task.
539
533
 
540
- **The threshold is `minor`.** The loop exits when the round reports zero
541
- findings at `blocker`, `major` or `minor`; `info` does not hold it. State the
542
- remaining `info` findings in the completion report rather than fixing them
543
- under a loop that was not opened for them. A caller may lower the threshold in
544
- `constraints`; it cannot raise it to merge over a `minor`.
534
+ **The threshold is `minor`.** The loop exits when the round reports zero findings at `blocker`, `major` or `minor` that are not held, and no held finding awaits the operator; `info` does not hold it. A held finding counts as neither fixable nor clean: while one is unanswered, run no fix round for it and stop to ask (unattended: stop and report the held list). State the remaining `info` findings in the completion report rather than fixing them under a loop that was not opened for them. A caller may lower the threshold in `constraints`; it cannot raise it to merge over a `minor`.
545
535
  3. Allow at most **five** review/fix attempts for the current approach. Count
546
536
  an attempt when review/check results are available, including a clean result,
547
537
  and record it with `keryx flow task attempt <id> <Tn> --outcome ...` so the
@@ -686,6 +676,7 @@ Stop and re-read this skill if you are thinking:
686
676
  | "Verification is described in the plan, so it will happen." | A verification step in the plan is a task, not a sentence. If it is not a task with a status, nothing records whether it ran, and the flow reaches `implemented` with an unrun gate. |
687
677
  | "The review fan-out is cheap, so the budget check can wait." | `keryx review budget --spent … --outstanding …` gates the fan-out, and `review-orchestrator` runs inline in this same main session, where keryx cannot see the in-flight subagents; declare them with `--outstanding`. Skipping the check means the cap bounds nothing. |
688
678
  | "The reviewer wrote the fix; applying it is the fastest close." | A `suggested_fix` is a hypothesis. Most majors in a long fix loop are introduced by fixes: reproduce the finding red, check the suggestion against the state × event matrix, then fix (Phase 3 step 6). |
679
+ | "The finding came from a review, so its premise is settled." | A finding can reproduce and still not be a defect. Never pass a held finding in `fix_context.review_feedback`; ask the operator as `review-orchestrator` "Wave D" says (Phase 3 step 6); a flow sourced from a finding runs `review-premise` before freeze (Phase 1). |
689
680
  | "While I'm in this code, the fix round can also harden the empty state." | Scope freeze: a fix round fixes findings. New hardening is an operator decision at the first-green gate or as an explicit question, never silent growth. |
690
681
  | "The implementer journaled its UX choice, so it is decided." | A `behavior_changes` entry with `needs_operator: true` is decided by the operator, asked with options before the result is accepted (Phase 2). A journal line decides nothing. |
691
682
  | "I'll set the verification kind later." | An `unclassified` criterion cannot become data afterwards without a recorded rewrite: `keryx flow ac update <id> --criterion ACn --text "…" --reason "<why>"`. Put the `[verify: …]` marker on every criterion before `flow freeze`. |
@@ -0,0 +1,70 @@
1
+ # Job Orchestrator - Reference Detail
2
+
3
+ Reference material moved out of `SKILL.md` to keep it within its length ceiling:
4
+ rationale, evidence and long examples. Nothing here is an instruction the agent must
5
+ follow at a step; each section is linked from the spot in `SKILL.md` that used it.
6
+
7
+ ## Dry-run plan output example
8
+
9
+ ```
10
+ Dry-run plan for: issue-4141--pipeline-validation
11
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12
+ Step 1: analyze [issue-analyzer] → input: issue #4141
13
+ Step 2: context [context-collector] → input: analysis result, project_dir
14
+ Step 3: prepare [orchestrator] → creates: feature/pipeline-validation worktree
15
+ Step 4: tests-creator [tests-creator × 3] → RED stubs, one per task
16
+ Step 5: implement [task-implementer × 3] → wave-parallel, 3 tasks
17
+ Step 6: sanity-check [orchestrator] → verifies commits exist
18
+ Step 7: verify [code-verifier] → lint + type-check + test + imports
19
+ Step 8: review [review-orchestrator] → managed round, ingested
20
+ Step 9: security [security-audit] → conditional: auth/API/DB/env files
21
+ Step 10: fix [task-implementer] → conditional: if NEEDS_FIX
22
+ Step 11: verify-post-fix [code-verifier] → conditional: after fix
23
+ Step 12: perf-check [perf-check] → conditional: frontend/bundle files
24
+ Step 13: report [orchestrator] → aggregates all results
25
+ Step 14: pr [orchestrator + gh CLI] → conditional: if create_pr
26
+ Step 15: deploy [deploy] → conditional: if user asks
27
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
28
+ Estimated sub-agent calls: 11-14 (varies with tasks and review findings)
29
+ No changes will be made. Use without --dry-run to execute.
30
+ ```
31
+
32
+ ## Post-mortem document template
33
+
34
+ ```markdown
35
+ # Post-Mortem: <job-name>
36
+
37
+ ## Timeline
38
+ (from .metaproject/jobs/<job-name>/journal.md — every line as recorded)
39
+ - <ISO timestamp> - created
40
+ - <ISO timestamp> - step: implement in-progress (retries 0)
41
+ - <ISO timestamp> - step: implement in-progress (retries 1)
42
+ - <ISO timestamp> - step: implement failed (retries 1) — <reason>
43
+
44
+ ## What Went Wrong
45
+ - <Step name> failed with: <error class> — <error message>
46
+ - Recorded retries: <metrics.steps[].retries>
47
+ - Root cause hypothesis: <analysis>
48
+
49
+ ## What Worked
50
+ - <N> tasks completed successfully
51
+ - Context collection was accurate
52
+
53
+ ## Recommendations for Retry
54
+ - Fix <specific issue> before re-running
55
+ - Consider splitting task-3 into smaller subtasks
56
+ ```
57
+
58
+ ## Metrics table in the report
59
+
60
+ **Aggregated in the report:**
61
+ ```markdown
62
+ ## Metrics
63
+ | Step | Duration | Retries |
64
+ |------|----------|---------|
65
+ | Analyze | 45s | 0 |
66
+ | Context | 30s | 0 |
67
+ | Implement | 5m 22s | 1 |
68
+ | Review | 1m 10s | 0 |
69
+ | **Total** | **7m 47s** | **1** |
70
+ ```
@@ -989,7 +989,7 @@ transcript and nothing else, which is precisely the failure the managed pipeline
989
989
  replaced.
990
990
 
991
991
  A pull request driven by this orchestrator has to pass the completion gate shipped in
992
- 0.2.71. Its five conditions are what 2.6 and 2.7 are built to satisfy:
992
+ 0.2.71. Its conditions are what 2.6 and 2.7 are built to satisfy:
993
993
 
994
994
  | Gate condition | Satisfied by |
995
995
  |---|---|
@@ -998,6 +998,7 @@ A pull request driven by this orchestrator has to pass the completion gate shipp
998
998
  | scope B is recorded when a scope-B reviewer ran | `keryx review blast-radius --json` → `review ingest --blast-radius` (2.6.1) |
999
999
  | no inbound PR comment is unanswered | `keryx review comments collect` every round, `… reply --final` once (2.6.2) |
1000
1000
  | verification stats exist | `review-verifier` dispatched, passed as `--verifications` (2.6.1) |
1001
+ | no held finding lacks an operator decision | `review-premise` (Wave D) claims passed as `--premises`; each held finding asked as `review-orchestrator` "Wave D" says (2.6.1) |
1001
1002
 
1002
1003
  #### 2.6.0 Review Scope Selection
1003
1004
 
@@ -1134,15 +1135,17 @@ is_fix_round: <true on any round after the first; the round, its range and
1134
1135
  pr_comments: { enabled: <true when a PR exists> }
1135
1136
  ```
1136
1137
 
1137
- It emits the unified report AND the fenced ```json keryx:findings``` block, and runs
1138
- `review-verifier` (Wave C) over the consolidated findings, returning its verification
1139
- claims as a file path.
1138
+ It emits the unified report AND the fenced ```json keryx:findings``` block, runs
1139
+ `review-verifier` (Wave C) and then `review-premise` (Wave D) over the consolidated
1140
+ findings, and returns the verification claims and the premise claims as file paths.
1140
1141
 
1141
- **Step 7 — verification is part of the round, not an extra.** `review-orchestrator`
1142
- dispatches `review-verifier` in Wave C over the consolidated findings. The verifier
1143
- **runs something** and can only delete — it never raises a severity, adds a finding,
1144
- or rewrites one, and it never verifies a finding raised by the same reviewer. Its
1145
- claims are merged by the CLI, not by hand.
1142
+ **Step 7 — verification and the premise check are part of the round, not extras.**
1143
+ `review-orchestrator` dispatches `review-verifier` in Wave C over the consolidated
1144
+ findings. The verifier **runs something** and can only delete — it never raises a
1145
+ severity, adds a finding, or rewrites one, and it never verifies a finding raised by the
1146
+ same reviewer. After it, `review-premise` (Wave D) judges whether each finding is a
1147
+ defect at all: it can lower a severity or hold a finding for the operator, never add
1148
+ one. Both claim sets are merged by the CLI, not by hand.
1146
1149
 
1147
1150
  **Step 8 — ingest the round.** This is what makes it citable.
1148
1151
 
@@ -1152,13 +1155,14 @@ keryx review ingest --report <path/to/review-report.md> --ref <feature-branch> \
1152
1155
  --scope <JOBS_ROOT>/<job-name>/scope.json \
1153
1156
  --blast-radius <JOBS_ROOT>/<job-name>/blast-radius.json \
1154
1157
  --verifications <path/to/verifications.json> --verification-mode annotate \
1155
- --refuted <path/to/refuted.json> \
1158
+ --premises <path/to/premises.json> --refuted <path/to/refuted.json> \
1156
1159
  --spent <usd-so-far> --outstanding <subagents in flight>
1157
1160
  ```
1158
1161
 
1159
1162
  An unrecognised option is **refused, not ignored** — a silently dropped flag writes
1160
1163
  nothing and still reports success. `--refuted` carries findings this round raised and
1161
1164
  then dismissed; without it the package keeps only the survivors of an unlogged triage.
1165
+ A first ingest without `--premises` holds nothing; a re-ingest carries earlier holds.
1162
1166
 
1163
1167
  **Findings are the canonical shape.** One vocabulary, everywhere in this skill:
1164
1168
 
@@ -1174,9 +1178,18 @@ then dismissed; without it the package keeps only the survivors of an unlogged t
1174
1178
 
1175
1179
  **Classify:**
1176
1180
  ```
1177
- NEEDS_FIX = count(blocker) > 0 OR count(major) > 0
1181
+ HELD = findings review-premise holds (challenged / owner-decision) with no operator decision
1182
+ OPEN = blocker + major findings not in HELD
1183
+ NEEDS_FIX = count(OPEN) > 0
1178
1184
  ```
1179
1185
 
1186
+ A HELD finding is neither fixable nor clean: it never enters a fix prompt, and it blocks
1187
+ the job until answered. Ask the operator about each one as `review-orchestrator` "Wave
1188
+ D" says; an upheld one rejoins OPEN at its severity (carrying `premise_verdict` and
1189
+ `premise_answer` as task-implementer's `FIX_CONTEXT` defines them), a dismissed one
1190
+ carries `dismissed-incorrect` from the operator's decision. Unattended: stop and report
1191
+ the HELD list; never let the loop end reading clean while HELD is non-empty.
1192
+
1180
1193
  **Document:** record the report in the job package too, so the job and the review
1181
1194
  record point at each other:
1182
1195
 
@@ -1276,7 +1289,7 @@ still reported — so a finding the next reviewer simply did not look at was rec
1276
1289
  fixed. That is absence-as-evidence, and the completion gate refuses it.
1277
1290
 
1278
1291
  ```
1279
- UNRESOLVED_FINDINGS = all blocker + major findings from step 2.6
1292
+ UNRESOLVED_FINDINGS = OPEN from step 2.6 # never a HELD finding (Classify, 2.6.1)
1280
1293
  PREVIOUS_REVIEW_OUTPUT = <the ingested report from step 2.6>
1281
1294
 
1282
1295
  FOR iteration in [1, 2, 3]:
@@ -1305,8 +1318,8 @@ FOR iteration in [1, 2, 3]:
1305
1318
  <run review-orchestrator inline, in this session; it takes the round from round.json>
1306
1319
  keryx review ingest --report <new-report> --ref <feature-branch> --head <new-head> \
1307
1320
  --scope scope.json --blast-radius blast-radius.json \
1308
- --verifications <file> --refuted <file> --outstanding <n>
1309
- 6. Recompute NEEDS_FIX from the ingested findings
1321
+ --verifications <file> --premises <file> --refuted <file> --outstanding <n>
1322
+ 6. Recompute HELD, OPEN and NEEDS_FIX from the ingested findings; a new HELD finding is asked about as in Classify
1310
1323
  7. Record what became of each finding raised in the PREVIOUS round — every one of
1311
1324
  them, before the next iteration starts:
1312
1325
 
@@ -1320,9 +1333,8 @@ FOR iteration in [1, 2, 3]:
1320
1333
  must cite where the outcome is written down. A recorded state and its citation
1321
1334
  cannot be overwritten by a later close — record a correction as a new round.
1322
1335
  Closing with no dispositions leaves every finding reading `unknown`, which means
1323
- "nobody wrote down what happened".
1324
- 8. UNRESOLVED_FINDINGS = the blocker + major findings of the NEW round that are
1325
- still without a terminal disposition
1336
+ "nobody wrote down what happened". A HELD finding gets no disposition here: it waits for the operator.
1337
+ 8. UNRESOLVED_FINDINGS = the OPEN findings of the NEW round still without a terminal disposition
1326
1338
 
1327
1339
  9. STUCK CHECK — runs before the next iteration and ignores the budget:
1328
1340
  IF any finding identity is in UNRESOLVED_FINDINGS for the SECOND iteration
@@ -1351,6 +1363,8 @@ IF still NEEDS_FIX after max iterations, or the stuck check broke the loop:
1351
1363
  steps. Give every surviving finding a disposition (dismissed-wont-fix or
1352
1364
  dismissed-deprioritised, with evidence) rather than leaving it `unknown`
1353
1365
  → continue to VERIFY (2.8)
1366
+
1367
+ IF HELD is non-empty when the loop ends: ask the operator (Classify); unattended, stop and report the HELD list
1354
1368
  ```
1355
1369
 
1356
1370
  `comments reply` **refuses without `--final`**: replying per round turns one review
@@ -1936,28 +1950,8 @@ When `dry_run: true` is set (or `--dry-run` is passed):
1936
1950
  3. **Phase 2 is skipped entirely** — no sub-agents dispatched, no git operations
1937
1951
  4. **Output:** Full plan tree with agent names, input data shapes, dependencies:
1938
1952
 
1939
- ```
1940
- Dry-run plan for: issue-4141--pipeline-validation
1941
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1942
- Step 1: analyze [issue-analyzer] → input: issue #4141
1943
- Step 2: context [context-collector] → input: analysis result, project_dir
1944
- Step 3: prepare [orchestrator] → creates: feature/pipeline-validation worktree
1945
- Step 4: tests-creator [tests-creator × 3] → RED stubs, one per task
1946
- Step 5: implement [task-implementer × 3] → wave-parallel, 3 tasks
1947
- Step 6: sanity-check [orchestrator] → verifies commits exist
1948
- Step 7: verify [code-verifier] → lint + type-check + test + imports
1949
- Step 8: review [review-orchestrator] → managed round, ingested
1950
- Step 9: security [security-audit] → conditional: auth/API/DB/env files
1951
- Step 10: fix [task-implementer] → conditional: if NEEDS_FIX
1952
- Step 11: verify-post-fix [code-verifier] → conditional: after fix
1953
- Step 12: perf-check [perf-check] → conditional: frontend/bundle files
1954
- Step 13: report [orchestrator] → aggregates all results
1955
- Step 14: pr [orchestrator + gh CLI] → conditional: if create_pr
1956
- Step 15: deploy [deploy] → conditional: if user asks
1957
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1958
- Estimated sub-agent calls: 11-14 (varies with tasks and review findings)
1959
- No changes will be made. Use without --dry-run to execute.
1960
- ```
1953
+ The full plan tree (agent names, input shapes, dependencies, no changes made):
1954
+ `SKILL.detail.md`, "Dry-run plan output example".
1961
1955
 
1962
1956
  5. Ask user: "Execute this plan? (yes / adjust / abort)"
1963
1957
 
@@ -2158,29 +2152,7 @@ When a job ends with a step recorded `failed`, or with unresolved blocker findin
2158
2152
  off `journal.md`, which `keryx job` timestamped as the job ran, and the retry counts
2159
2153
  come from `keryx job status <job-name> --json`:
2160
2154
 
2161
- ```markdown
2162
- # Post-Mortem: <job-name>
2163
-
2164
- ## Timeline
2165
- (from .metaproject/jobs/<job-name>/journal.md — every line as recorded)
2166
- - <ISO timestamp> - created
2167
- - <ISO timestamp> - step: implement in-progress (retries 0)
2168
- - <ISO timestamp> - step: implement in-progress (retries 1)
2169
- - <ISO timestamp> - step: implement failed (retries 1) — <reason>
2170
-
2171
- ## What Went Wrong
2172
- - <Step name> failed with: <error class> — <error message>
2173
- - Recorded retries: <metrics.steps[].retries>
2174
- - Root cause hypothesis: <analysis>
2175
-
2176
- ## What Worked
2177
- - <N> tasks completed successfully
2178
- - Context collection was accurate
2179
-
2180
- ## Recommendations for Retry
2181
- - Fix <specific issue> before re-running
2182
- - Consider splitting task-3 into smaller subtasks
2183
- ```
2155
+ Use the template in `SKILL.detail.md`, "Post-mortem document template".
2184
2156
 
2185
2157
  2. Save to `.metaproject/jobs/<job-name>/post-mortem.md`
2186
2158
  3. Include in final user message: "Post-mortem saved to `.metaproject/jobs/<job-name>/post-mortem.md`"
@@ -2220,16 +2192,7 @@ terminal disposition.
2220
2192
  keryx job status <job-name> --json # `retries` per step, plus phase and next_step
2221
2193
  ```
2222
2194
 
2223
- **Aggregated in the report:**
2224
- ```markdown
2225
- ## Metrics
2226
- | Step | Duration | Retries |
2227
- |------|----------|---------|
2228
- | Analyze | 45s | 0 |
2229
- | Context | 30s | 0 |
2230
- | Implement | 5m 22s | 1 |
2231
- | Review | 1m 10s | 0 |
2232
- | **Total** | **7m 47s** | **1** |
2233
- ```
2195
+ **Aggregated in the report:** a per-step Duration/Retries table with a total row
2196
+ (`SKILL.detail.md`, "Metrics table in the report").
2234
2197
 
2235
2198
  This data identifies which steps are bottlenecks and which ones needed a second attempt.
@@ -98,7 +98,7 @@ For a description-based task, omit `issue_number` and issue references in commit
98
98
 
99
99
  ```
100
100
  FIX_CONTEXT:
101
- review_feedback: structured findings from reviewer (id, file, line, severity, message, suggested_fix)
101
+ review_feedback: structured findings from reviewer (id, file, line, severity, message, suggested_fix); the one statement of the premise fields (flow 459): `premise_verdict` on each item review-premise judged, and `premise_answer: "uphold"` on a held one (challenged, owner-decision) the operator upheld; an item with a held `premise_verdict` and no `premise_answer: "uphold"` is refused, not fixed
102
102
  original_task_ids: the tasks that introduced the findings (array)
103
103
  iteration: fix iteration number, 1..3 — the same repair bound as 5.4
104
104
  ```
@@ -178,10 +178,25 @@
178
178
  "type": "string",
179
179
  "description": "Which review skill found this",
180
180
  "examples": ["code-ai-review", "code-learned-review", "code-style-review"]
181
+ },
182
+ "premise_verdict": {
183
+ "type": "string",
184
+ "enum": ["upheld", "downgraded", "challenged", "owner-decision"],
185
+ "description": "What review-premise found, when it judged this finding (flow 459). `challenged` and `owner-decision` HOLD the finding: such an item is valid only with `premise_answer: uphold`, so a held finding that reached a fixer without the operator's answer fails this contract instead of being fixed."
186
+ },
187
+ "premise_answer": {
188
+ "type": "string",
189
+ "enum": ["uphold"],
190
+ "description": "The operator's answer to a held finding, recorded with `keryx review decide-premise` (or the `review_decide_premise` card). Only `uphold` returns a finding to the fix; a dismissed one is never dispatched."
181
191
  }
182
- }
192
+ },
193
+ "if": {
194
+ "required": ["premise_verdict"],
195
+ "properties": { "premise_verdict": { "enum": ["challenged", "owner-decision"] } }
196
+ },
197
+ "then": { "required": ["premise_answer"] }
183
198
  },
184
- "description": "Structured findings from review skills"
199
+ "description": "Structured findings from review skills, to fix. Never carries a finding held by review-premise (verdict challenged or owner-decision) until the operator upholds it with `keryx review decide-premise`; the caller filters held findings out before dispatch, and an item that names a held verdict without `premise_answer: uphold` is refused by this contract."
185
200
  },
186
201
  "original_task_ids": {
187
202
  "type": "array",
@@ -26,7 +26,7 @@ license: "MIT"
26
26
 
27
27
  Specialized reviewer for **architectural patterns and structural decisions**.
28
28
  Reviews only changes introduced in the current branch (merge-base to HEAD).
29
- Focuses exclusively on verifiable structural violations — not style opinions or hypothetical concerns. 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`.
29
+ Focuses exclusively on verifiable structural violations — not style opinions or hypothetical concerns. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. 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).
30
30
 
31
31
  ---
32
32
 
@@ -66,7 +66,7 @@ See shared script: `.metaproject/skills/gdskills/shared/git-merge-base.md`
66
66
  Review scope: **changes introduced in the current branch since merge-base only**.
67
67
  Do not review pre-existing architectural problems unless they are directly touched by the diff.
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}"
@@ -269,15 +269,10 @@ if the concern is purely readability it belongs to `review-style`.
269
269
 
270
270
  ### Shared laws (every reviewer)
271
271
 
272
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
273
- name the input, call, or condition that reaches the code, you have an
274
- observation, not a finding. Report it as `info` and say what would settle it.
275
- 2. **Never flag the theoretical.** The path you describe must exist in the code
276
- under review. Do not report a safe API because it could be misused, or a
277
- pattern because it is often wrong elsewhere.
278
- 3. **One finding per class, not one per occurrence.** When the same shape appears
279
- at several sites, report it once and list every site. Ten findings that are one
280
- finding hide the other nine problems.
272
+ 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.
273
+ 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.
274
+ 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.
275
+ 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.
281
276
 
282
277
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
283
278
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -26,7 +26,7 @@ license: "MIT"
26
26
 
27
27
  Focused backend reviewer covering NestJS patterns, REST API design, database access patterns,
28
28
  and TypeScript correctness for service-layer code. This skill does NOT duplicate security or
29
- performance checks — those belong to `review-security-code` and `review-performance`. 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`.
29
+ performance checks — those belong to `review-security-code` and `review-performance`. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. 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).
30
30
 
31
31
  ---
32
32
 
@@ -65,7 +65,7 @@ Run that script to determine `BASE_SHA` before collecting the diff.
65
65
 
66
66
  Only review files changed in scope. Do not comment on legacy code outside the diff.
67
67
 
68
- **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:
68
+ **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:
69
69
  ```bash
70
70
  git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files --others --exclude-standard
71
71
  # explicit range: <FROM_SHA>..<TO_SHA> in place of "${BASE_SHA}"
@@ -187,15 +187,10 @@ git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files -
187
187
 
188
188
  ### Shared laws (every reviewer)
189
189
 
190
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
191
- name the input, call, or condition that reaches the code, you have an
192
- observation, not a finding. Report it as `info` and say what would settle it.
193
- 2. **Never flag the theoretical.** The path you describe must exist in the code
194
- under review. Do not report a safe API because it could be misused, or a
195
- pattern because it is often wrong elsewhere.
196
- 3. **One finding per class, not one per occurrence.** When the same shape appears
197
- at several sites, report it once and list every site. Ten findings that are one
198
- finding hide the other nine problems.
190
+ 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.
191
+ 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.
192
+ 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.
193
+ 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.
199
194
 
200
195
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
201
196
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -27,7 +27,7 @@ license: "MIT"
27
27
  # Review: Clean Code + SOLID
28
28
 
29
29
  Specialized reviewer for **Clean Code principles** (Robert C. Martin) and **SOLID** at the
30
- function and class level. Focuses on code in the current branch diff only. 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`.
30
+ function and class level. Focuses on code in the current branch diff only. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. 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
  The goal is not stylistic nitpicking — every finding here points to a concrete
33
33
  maintainability, readability, or extensibility problem that will cause friction
@@ -71,7 +71,7 @@ Review scope: **only code introduced or modified in this branch since merge-base
71
71
  Pre-existing problems in unchanged lines are out of scope unless a change directly
72
72
  worsens them.
73
73
 
74
- **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:
74
+ **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:
75
75
  ```bash
76
76
  git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files --others --exclude-standard
77
77
  # explicit range: <FROM_SHA>..<TO_SHA> in place of "${BASE_SHA}"
@@ -83,15 +83,10 @@ git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files -
83
83
 
84
84
  ### Shared laws (every reviewer)
85
85
 
86
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
87
- name the input, call, or condition that reaches the code, you have an
88
- observation, not a finding. Report it as `info` and say what would settle it.
89
- 2. **Never flag the theoretical.** The path you describe must exist in the code
90
- under review. Do not report a safe API because it could be misused, or a
91
- pattern because it is often wrong elsewhere.
92
- 3. **One finding per class, not one per occurrence.** When the same shape appears
93
- at several sites, report it once and list every site. Ten findings that are one
94
- finding hide the other nine problems.
86
+ 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.
87
+ 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.
88
+ 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.
89
+ 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.
95
90
 
96
91
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
97
92
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -24,7 +24,7 @@ license: "MIT"
24
24
  # Review — Core Boundaries
25
25
 
26
26
  Reviewer for shared infrastructure modules. A core module should provide stable foundations
27
- used by feature modules; it should not accumulate feature-specific behaviour. 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`.
27
+ used by feature modules; it should not accumulate feature-specific behaviour. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. 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).
28
28
 
29
29
  ---
30
30
 
@@ -58,15 +58,10 @@ If a more specific module reviewer also applies, run both.
58
58
 
59
59
  ### Shared laws (every reviewer)
60
60
 
61
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
62
- name the input, call, or condition that reaches the code, you have an
63
- observation, not a finding. Report it as `info` and say what would settle it.
64
- 2. **Never flag the theoretical.** The path you describe must exist in the code
65
- under review. Do not report a safe API because it could be misused, or a
66
- pattern because it is often wrong elsewhere.
67
- 3. **One finding per class, not one per occurrence.** When the same shape appears
68
- at several sites, report it once and list every site. Ten findings that are one
69
- finding hide the other nine problems.
61
+ 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.
62
+ 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.
63
+ 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.
64
+ 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.
70
65
 
71
66
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
72
67
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the