@mrciphersmith/keryx 0.3.120 → 0.3.122

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 (40) hide show
  1. package/dist/cli.js +9184 -6402
  2. package/dist/core.js +1702 -1311
  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 +9 -18
  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 +27 -3
  29. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +38 -48
  30. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +10 -1
  31. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +1 -1
  32. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +6 -11
  33. package/src/gdskills/bundled/skills/review/review-pr-contract/SKILL.md +2 -2
  34. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +8 -10
  35. package/src/gdskills/bundled/skills/review/review-premise/SKILL.md +180 -0
  36. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +3 -3
  37. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +6 -11
  38. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +6 -11
  39. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +2 -2
  40. package/src/gdskills/contracts/review-finding.schema.json +77 -2
@@ -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). A display `id` holds no `#`, the global_id separator (`<reviewId>#<id>`): ingest refuses one, so the caller names a finding of several waves `<raw stem>:<id>` (`review-logic-w1:F-001`), never `review-logic-w1#F-001`. Several judge dispatches each return one claims file; `review ingest --premises` takes them all. 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
 
@@ -23,7 +23,7 @@ license: "MIT"
23
23
 
24
24
  ## Purpose
25
25
 
26
- Finds exploitable security vulnerabilities introduced in the changed code of the current branch. Covers injection, auth/authz gaps, IDOR, secrets, insecure crypto, CSRF, path traversal, and framework-specific patterns (NestJS, React). Produces findings with explicit attack vectors and concrete fixes. 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`.
26
+ Finds exploitable security vulnerabilities introduced in the changed code of the current branch. Covers injection, auth/authz gaps, IDOR, secrets, insecure crypto, CSRF, path traversal, and framework-specific patterns (NestJS, React). Produces findings with explicit attack vectors and concrete fixes. 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).
27
27
 
28
28
  This skill covers **code-level security only**. It does NOT audit npm/bun dependency trees, Docker configurations, or deployment surfaces — use `security-audit` for those.
29
29
 
@@ -67,7 +67,7 @@ See shared script: `.metaproject/skills/gdskills/shared/git-merge-base.md`
67
67
 
68
68
  Run the script from that file to determine `MERGE_BASE` (`BASE_SHA`) and `SCOPE` before proceeding.
69
69
 
70
- **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:
70
+ **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:
71
71
  ```bash
72
72
  git diff --name-status "${BASE_SHA}" && git diff "${BASE_SHA}" && git ls-files --others --exclude-standard
73
73
  # explicit range: <FROM_SHA>..<TO_SHA> in place of "${BASE_SHA}"
@@ -201,15 +201,10 @@ Attack vector template: _"Attacker sends `filename=../../etc/passwd`, reading ar
201
201
 
202
202
  ### Shared laws (every reviewer)
203
203
 
204
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
205
- name the input, call, or condition that reaches the code, you have an
206
- observation, not a finding. Report it as `info` and say what would settle it.
207
- 2. **Never flag the theoretical.** The path you describe must exist in the code
208
- under review. Do not report a safe API because it could be misused, or a
209
- pattern because it is often wrong elsewhere.
210
- 3. **One finding per class, not one per occurrence.** When the same shape appears
211
- at several sites, report it once and list every site. Ten findings that are one
212
- finding hide the other nine problems.
204
+ 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.
205
+ 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.
206
+ 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.
207
+ 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.
213
208
 
214
209
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
215
210
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -25,7 +25,7 @@ license: "MIT"
25
25
 
26
26
  Focused style reviewer. Covers naming conventions, dead code, readability, DRY violations,
27
27
  import organization, comment quality, file length, cyclomatic complexity, and console noise.
28
- Never touches logic correctness, architecture, security, or 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`.
28
+ Never touches logic correctness, architecture, security, or 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).
29
29
 
30
30
  ---
31
31
 
@@ -66,7 +66,7 @@ Run that script to determine `BASE_SHA` before collecting the diff.
66
66
 
67
67
  Only review code changed in scope. Do not flag style issues in lines outside 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}"
@@ -195,15 +195,10 @@ Do not flag DRY violations for code outside the diff even if legacy duplication
195
195
 
196
196
  ### Shared laws (every reviewer)
197
197
 
198
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
199
- name the input, call, or condition that reaches the code, you have an
200
- observation, not a finding. Report it as `info` and say what would settle it.
201
- 2. **Never flag the theoretical.** The path you describe must exist in the code
202
- under review. Do not report a safe API because it could be misused, or a
203
- pattern because it is often wrong elsewhere.
204
- 3. **One finding per class, not one per occurrence.** When the same shape appears
205
- at several sites, report it once and list every site. Ten findings that are one
206
- finding hide the other nine problems.
198
+ 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.
199
+ 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.
200
+ 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.
201
+ 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.
207
202
 
208
203
  Severity levels are defined once, in `review-orchestrator/SKILL.md` →
209
204
  **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
@@ -28,8 +28,7 @@ license: "MIT"
28
28
 
29
29
  # Review — Testing Practices
30
30
 
31
- Reviewer for local testing discipline. Read project test guides first when present, then apply
32
- the neutral baseline below. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. It runs the tests only when its payload's `allowed_tools` says `run-tests`, within `exec_budget_s`; otherwise it runs no command.
31
+ Reviewer for local testing discipline. Read project test guides first when present, then apply the neutral baseline below. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs. It runs the tests only when its payload's `allowed_tools` says `run-tests`, within `exec_budget_s`; otherwise it runs no command, 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).
33
32
 
34
33
  ---
35
34
 
@@ -195,6 +194,7 @@ pass, then work the checklist.
195
194
  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.
196
195
  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.
197
196
  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.
197
+ 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.
198
198
 
199
199
  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.
200
200
 
@@ -115,6 +115,69 @@
115
115
  "description": "Reasoning alone produces no new evidence, so it can never reach `confirmed` (AC7). It cannot reach `refuted` either, and that extension is deliberate: `refuted` is the only verdict with a destructive consequence, so granting it to the weakest method would reinstate review-strict with the sign flipped. Anything checkable is `site-check` or `execution`; `reasoning` is what is left when nothing was run."
116
116
  }
117
117
  },
118
+ "premise": {
119
+ "title": "What the premise judge found when it asked whether this finding's request is right",
120
+ "description": "Flow 459. Declared HERE and deliberately NOT in the bundled reviewer-finding.schema.json, on the same basis as `verification`: the reviewer that raised a finding is the one actor that may not judge its premise. The verifier asks whether the facts hold; the premise judge asks whether the request is right (an explicit override, an exemption, a sibling doing the same and accepted platform practice are all evidence that a flagged shape is a deliberate choice). `challenged` and `owner-decision` HOLD the finding: it is not an open blocker or major and is not passed to a fixer until the operator answers. The judge is delete-only: it never adds a finding, never raises a severity and never edits the finding's text; `downgraded` carries a strictly lower `severity` (`major` or `minor`: a downgrade stops at the fix-loop threshold), which is then also the finding's own. One source of truth each: the finding's own `severity` wins over a `premise.severity` that disagrees (ingest aligns them), and the operator's answer is the `premise-question` decision in the package's operator-decisions.json; `premise.operator` is only its audit trail on the record, and ingest strips it from any finding it receives. The schema states the per-verdict fields below; that a downgrade is STRICTLY lower than the original is checked in code (src/review/premise.ts). Absent means nobody judged.",
121
+ "type": "object",
122
+ "additionalProperties": false,
123
+ "required": ["verdict", "judge"],
124
+ "properties": {
125
+ "verdict": { "type": "string", "enum": ["upheld", "downgraded", "challenged", "owner-decision"] },
126
+ "judge": { "type": "string", "minLength": 1 },
127
+ "model": { "type": "string", "minLength": 1 },
128
+ "severity": { "type": "string", "enum": ["major", "minor"], "description": "`downgraded` only: the lower severity, also the finding's own. Never `info`: a downgrade stops at `minor`, the fix-loop threshold." },
129
+ "original_severity": { "type": "string", "enum": ["blocker", "major"], "description": "`downgraded` only: what the reviewer reported." },
130
+ "intent_signals": {
131
+ "type": "array",
132
+ "items": {
133
+ "type": "object",
134
+ "additionalProperties": false,
135
+ "required": ["ref", "says"],
136
+ "properties": { "ref": { "type": "string", "minLength": 1 }, "says": { "type": "string", "minLength": 1 } }
137
+ }
138
+ },
139
+ "practice_sources": {
140
+ "type": "array",
141
+ "items": {
142
+ "type": "object",
143
+ "additionalProperties": false,
144
+ "required": ["name", "says"],
145
+ "properties": { "name": { "type": "string", "minLength": 1 }, "says": { "type": "string", "minLength": 1 } }
146
+ }
147
+ },
148
+ "reasoning": { "type": "string" },
149
+ "question": { "type": "string", "minLength": 1, "description": "`challenged` and `owner-decision`: what the operator is asked." },
150
+ "options": { "type": "array", "minItems": 2, "items": { "type": "string", "minLength": 1 } },
151
+ "operator": {
152
+ "type": "object",
153
+ "additionalProperties": false,
154
+ "required": ["answer", "reason", "at", "actor"],
155
+ "description": "The operator's answer once applied to the record (`keryx review decide-premise`, the `review_decide_premise` card). An audit trail: the answer counts only from the package's operator-decisions.json, and ingest strips this field from input findings.",
156
+ "properties": {
157
+ "answer": { "type": "string", "enum": ["uphold", "dismiss"] },
158
+ "reason": { "type": "string", "minLength": 1 },
159
+ "quote": { "type": "string", "minLength": 1, "description": "The operator's own words: what they typed at the terminal, or the card text they said yes to." },
160
+ "at": { "type": "string", "minLength": 1 },
161
+ "actor": { "type": "string", "minLength": 1 },
162
+ "confirmedVia": { "type": "string", "enum": ["tui-card", "remote-card", "terminal"] }
163
+ }
164
+ }
165
+ },
166
+ "allOf": [
167
+ {
168
+ "if": { "required": ["verdict"], "properties": { "verdict": { "const": "downgraded" } } },
169
+ "then": { "required": ["severity", "original_severity"] }
170
+ },
171
+ {
172
+ "if": { "required": ["verdict"], "properties": { "verdict": { "enum": ["challenged", "owner-decision"] } } },
173
+ "then": { "required": ["question"] }
174
+ },
175
+ {
176
+ "if": { "required": ["verdict"], "properties": { "verdict": { "const": "owner-decision" } } },
177
+ "then": { "required": ["options"] }
178
+ }
179
+ ]
180
+ },
118
181
  "severity": { "type": "string", "enum": ["blocker", "major", "minor", "info"] },
119
182
  "repo": {
120
183
  "type": ["string", "null"],
@@ -129,7 +192,7 @@
129
192
  },
130
193
  "quote": {
131
194
  "title": "The code this finding is about, copied verbatim out of `file`",
132
- "description": "What replaces asking the model for a line number: a model is poor at counting lines and good at repeating text it has just read. The quote is matched against `file` at the round's head — exactly first, then with whitespace collapsed, then not at all. A quote that matches in more than one place is `unlocatable` rather than anchored to the first hit, because choosing among them would be a guess wearing a line number. Absent for a finding that is about the round rather than a site.",
195
+ "description": "What replaces asking the model for a line number: a model is poor at counting lines and good at repeating text it has just read. The quote is matched against `file` at the round's head — exactly first, then with whitespace collapsed, then (a one-line quote of at least 12 characters, MIN_SUBSTRING_QUOTE_CHARS) as an exact substring of exactly one line, then not at all; a shorter fragment must be a whole line. A quote that matches in more than one place is `unlocatable` rather than anchored to the first hit, because choosing among them would be a guess wearing a line number. Absent for a finding that is about the round rather than a site.",
133
196
  "type": ["string", "null"]
134
197
  },
135
198
  "locator": {
@@ -140,7 +203,7 @@
140
203
  "required": ["state"],
141
204
  "properties": {
142
205
  "state": { "type": "string", "enum": ["derived", "unlocatable"] },
143
- "method": { "type": "string", "enum": ["exact", "whitespace-normalised"] },
206
+ "method": { "type": "string", "enum": ["exact", "whitespace-normalised", "substring"] },
144
207
  "reason": { "type": ["string", "null"] },
145
208
  "reported_line": { "type": ["integer", "null"], "minimum": 1 }
146
209
  },
@@ -159,6 +222,18 @@
159
222
  "type": "boolean",
160
223
  "description": "Written, as true, only by `review ingest` when `file` does not exist at the round's reviewed head (a cat-file existence check of `<head>:<file>`). The finding is kept, never dropped, and is listed in scope.md: a finding that cites a path nobody can open is the reviewer's claim, not a located site."
161
224
  },
225
+ "quote_unlocated": {
226
+ "type": "object",
227
+ "additionalProperties": false,
228
+ "required": ["reason"],
229
+ "description": "Written only by `review ingest` when `quote` was checked against `file` at the round's reviewed head and is absent from it (`absent`) or matches more than one place (`ambiguous`, with the matched lines in `candidate_lines`, bounded by the scan). The finding is kept with `line` null, never relocated by similarity or proximity, listed in scope.md and by readiness item `quotes-located`; the round is recorded rather than refused. It is the machine-readable outcome of the same check that writes `locator` (`state: unlocatable`, its `reason` the prose of it): ingest writes both from one result and recomputes both on every ingest, so they never disagree. Gates and readers branch on this flag; `locator` is the record of how the line was or was not derived.",
230
+ "properties": {
231
+ "reason": { "type": "string", "enum": ["absent", "ambiguous"] },
232
+ "candidate_lines": { "type": "array", "maxItems": 50000, "items": { "type": "integer", "minimum": 1 } }
233
+ },
234
+ "if": { "properties": { "reason": { "const": "absent" } }, "required": ["reason"] },
235
+ "then": { "not": { "required": ["candidate_lines"] } }
236
+ },
162
237
  "symbol": { "type": ["string", "null"] },
163
238
  "problem": { "type": "string" },
164
239
  "impact": { "type": "string" },