@mrciphersmith/keryx 0.3.112 → 0.3.114

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 (38) hide show
  1. package/README.md +21 -3
  2. package/THIRD_PARTY_NOTICES.md +56 -0
  3. package/dist/cli.js +95320 -90301
  4. package/dist/core.js +5528 -4330
  5. package/package.json +3 -1
  6. package/src/gdgraph/affected-report.ts +14 -4
  7. package/src/gdgraph/build.ts +12 -9
  8. package/src/gdgraph/core-sources.ts +1 -0
  9. package/src/gdgraph/data-dir.ts +14 -0
  10. package/src/gdgraph/enrich.ts +5 -3
  11. package/src/gdgraph/query.ts +3 -2
  12. package/src/gdgraph/staleness.ts +8 -1
  13. package/src/gdgraph/wiki-layer.ts +9 -6
  14. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +3 -3
  15. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +3 -3
  16. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/orchestrator-prompt.md +2 -2
  17. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +4 -4
  18. package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +1 -1
  19. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +3 -3
  20. package/src/gdskills/bundled/skills/quality/api-truth/SKILL.md +2 -2
  21. package/src/gdskills/bundled/skills/quality/deprecation-path/SKILL.md +3 -3
  22. package/src/gdskills/bundled/skills/quality/fresh-eyes/SKILL.md +2 -2
  23. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.md +1 -1
  24. package/src/gdskills/bundled/skills/quality/root-cause/SKILL.md +2 -2
  25. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +14 -15
  26. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +14 -14
  27. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +13 -16
  28. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +14 -14
  29. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +3 -3
  30. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +27 -25
  31. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +16 -0
  32. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +53 -0
  33. package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-frontend.md +1 -1
  34. package/src/gdskills/bundled/skills/review/review-orchestrator/templates/review-report.md +22 -0
  35. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +13 -13
  36. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +23 -25
  37. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +13 -15
  38. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +31 -57
@@ -341,20 +341,7 @@ STATUS: DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED
341
341
 
342
342
  ## Job Context Awareness
343
343
 
344
- When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY include:
345
-
346
- ```
347
- JOB_NAME: <job-name>
348
- CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md
349
- ```
350
-
351
- If provided and the file exists, read the context document **before** the spec compliance gate.
352
- Use it to:
353
- - Understand intentional design decisions (do not flag correct library usage)
354
- - Identify acceptance criteria if no `issue_url` is provided
355
- - Calibrate severity for edge cases the team has explicitly accepted
356
-
357
- If absent, proceed normally — context is optional and non-blocking.
344
+ When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
358
345
 
359
346
  ---
360
347
 
@@ -368,3 +355,16 @@ If absent, proceed normally — context is optional and non-blocking.
368
355
  | "I'll mark everything blocker to be safe" | Overstated severity makes reports unactionable; calibrate per the severity guide |
369
356
  | "Async performance is slow, so that's a logic bug" | Performance lives in `review-performance` unless incorrect ordering changes the result |
370
357
  | "I didn't reproduce the bug so I won't report it" | Every blocker needs a scenario, not a repro — describe the failing code path |
358
+
359
+ <!-- keryx:layers-block:start -->
360
+ ## Project layers: graph, tests, wiki, memory
361
+
362
+ Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
363
+
364
+ - `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
365
+ - `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
366
+ - `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
367
+ - `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
368
+
369
+ In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
370
+ <!-- keryx:layers-block:end -->
@@ -33,7 +33,7 @@ comma-separated list, `stack_requires` as a string, only keys directly under
33
33
  has already applied it — use the fields, not the raw frontmatter.
34
34
 
35
35
  A description saying another entry point dispatches it ("Dispatched by
36
- vantage-review …") is its author's routing note, not a restriction: this
36
+ acme-review …") is its author's routing note, not a restriction: this
37
37
  orchestrator dispatches it through the fields above.
38
38
 
39
39
  ### Family flags — why a shared flag does not lift the path gate
@@ -441,8 +441,8 @@ flow (`flow-orchestrator` Phase 3), a pre-merge or pre-ship review, a
441
441
  re-request after fixes. A gating round runs the composition the start questions
442
442
  selected.
443
443
 
444
- - **No dispatch tool, no review.** A host that cannot dispatch subagents — this
445
- engine running inside a subagent, say — returns
444
+ - **No dispatch tool, no review.** A host that cannot dispatch subagents — no
445
+ spawn tool, or the depth budget spent — returns
446
446
  `STATUS: BLOCKED` with reason `nested_dispatch_unavailable` and no verdict.
447
447
  It does not review the diff alone and call that a round. Measured (flow 405):
448
448
  a single-agent round on a 150-line frontend PR wrote "did not dispatch any
@@ -24,9 +24,9 @@ license: "MIT"
24
24
 
25
25
  ## Preflight — before Step 0, in this order
26
26
 
27
- 1. **Can it spawn?** The round needs the `Agent` tool (or the host's equivalent) and depth budget left: Claude Code nests subagents at most 3 deep, and at the limit `Agent` is withheld. If it cannot spawn, the whole output is this line, with no tool calls and no review of your own:
27
+ 1. **Can it spawn?** The round needs a subagent-spawn tool (`Agent`, `spawn_subagent` or the host's equivalent) and depth budget left: Claude Code nests subagents at most 3 deep, and at the limit `Agent` is withheld. If it cannot spawn, the whole output is this line, with no tool calls and no review of your own:
28
28
  `STATUS: BLOCKED nested_dispatch_unavailable — run this skill in the main session`
29
- 2. **Is a round needed?** A diff of only docs, markdown, comments, formatting, lockfiles or generated files, with no CI, auth, migration or rule-bearing config, ends here with one line, `round not needed: <reason>`, and no reviewer. `--all`, an explicit reviewer list or a gating round forces a round.
29
+ 2. **Is a round needed?** List the files with `git diff --name-status --no-renames <base>...HEAD`, so a rename shows both paths. A diff where EVERY file is prose or machine-written data ends here with one line, `round not needed: <reason>`, and no reviewer. Prose is exactly: README or CHANGELOG at any depth; CONTRIBUTING, LICENSE, SECURITY or CODE_OF_CONDUCT at the top level; and under `docs/`, `.metaproject/wiki`, `.metaproject/reviews` or a flow's `journal.md`, a file with extension md, rst or adoc whose name holds a lowercase letter (an all-uppercase name such as AGENT or WARP is steering by convention). Machine-written data is a file under `coverage/` or `__generated__/` with extension lcov, info or map only; json, txt, html and md there are code. Steering is code wherever it sits, `docs/` included: a directory (singular or plural) named agent, skill, command, rule, prompt, instruction, persona, steering or hook, any path segment starting with a dot (`.claude`, `.cursorrules`, `.mcp.json`), a file name starting with SKILL, AGENT, CLAUDE, GEMINI, QWEN, CODEX, WARP, CRUSH, JULES, KNOWLEDGE, GUIDELINES, CONVENTIONS or copilot-instructions, ending in .local, .override, .instructions, .prompt, .agent or .chatmode before the extension, or containing prompt, instruction or system. A flow's `description.md`, `acceptance-criteria.md` and `tasks/` are gate inputs, so they are code. Every other file counts as code too, including lockfiles, committed `dist/` output, CI, auth, migrations, config JSON, and any path with `..`, a backslash, a leading `./` or `//`. `classifyRoundNeed` in `src/review/round-need.ts` is the tested reference of this rule; the host executes this text, and nothing in the CLI calls the function yet. `--all`, an explicit reviewer list or a gating round forces a round.
30
30
  3. **Round ceiling.** 5 rounds (`REVIEW_ROUND_CAP`) over the same `merge-base..HEAD`. Past it: interactive, ask the operator; unattended, `STATUS: BLOCKED round_cap`.
31
31
 
32
32
  ## Workflow
@@ -74,7 +74,7 @@ Publish this checklist with `plan_set` under the ids `step-0`…`step-14` once,
74
74
  - One `Agent` call per reviewer, all calls of a wave in a single message, so the wave runs in parallel.
75
75
  - Use the reviewer's exact `subagent_type`. If the runtime has no such type, use `general-purpose` and name the reviewer's `SKILL.md` path in the prompt. Neither available: that reviewer is `BLOCKED`.
76
76
  - Prompts carry pointers, not pasted files — the diff, the SHAs, the PR, the schema paths — and never paraphrase a contract.
77
- - A reply is a result only if it starts with a `STATUS:` line and carries a `REVIEW_RESULT` block matching `reviewer-finding.schema.json`; anything else is `BLOCKED`.
77
+ - A reply is a result only if it starts with a `STATUS:` line and carries a `REVIEW_RESULT` block matching `reviewer-finding.schema.json`; anything else is `BLOCKED`. The one exception: a reply or dispatch error of `STATUS: RATE_LIMITED` is handled by the Rate limits rule under Control, never marked `BLOCKED`.
78
78
  - The model comes from `keryx review tier` (Step 6). On `spawn_subagent` pass its tier as `model_tier` on every reviewer — `review-verifier` and simple reviewers `light`, normal `standard`, complex `deep`; an omitted tier runs the child on your own model.
79
79
 
80
80
  ## Shell host (keryx shell, or any host with no file-reading subagent) — mandatory
@@ -85,15 +85,15 @@ A reviewer on this host cannot open a path: its file tool reads inside its worki
85
85
  1. **Slice first.** `keryx review slice --ref <base> --out <dir>` after `keryx review scope`. It writes `slice-NN.diff` files of at most 150000 bytes each and a `manifest.json` carrying a wave budget (`--wave-bytes`, default 60000 and never below the slice ceiling): what ONE reviewer dispatch may total, so a role owning many slices is dispatched in slice waves that each fit the child deadline. On a large diff pass a small `--max-bytes` (for example 18000) and `--wave-bytes` (for example 54000) so no wave outruns a reviewer's five minutes; ledgers (csv, lockfiles, snapshots, generated files) are listed under `omissions` with a reason — list them in the report as not reviewed, never as clean.
86
86
  2. **Slices travel by `context_files`.** Write the slices under the project (the default `--out`, `.metaproject/data/review/slices`, already is) and pass each reviewer its slice paths in `spawn_subagent`'s `context_files`: the host copies the text into that reviewer's task, so you never paste or retype a slice. Put the `slices` ids in its reviewer-input. A dispatch that names a git range but no slice and no `context_files` leaves the reviewer with nothing to read — that is `BLOCKED`, not a review.
87
87
  3. **Check before dispatch.** `keryx review dispatch-check --payload <file> --manifest <dir>/manifest.json` for the wave; exit 1 means a payload names no slice, is over the wave ceiling (dispatch fewer slices, then the next wave), or breaks `reviewer-input.schema.json`. Fix it; do not dispatch around it.
88
- 4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means the next wave while it makes progress, Not run when it stalls.** Every reviewer result lists the `slices` it covered. On `INCOMPLETE`, `BLOCKED` or `NEEDS_CONTEXT` (never accepted as a finished scope), and on a `DONE` that left slices open, `keryx review retry-plan --manifest <dir>/manifest.json --result <raw/reviewer.txt>` decides and hands out the next wave of only the slices still uncovered (`--next-wave` plans one without a result). A result that covered a new slice spends no attempt; two results in a row with nothing new, or six failed rounds, print the `- **Not run:** …` line to paste into the report, and a result with nothing new first has its open slices cut in half. Dispatch each wave, save its reply, and run `retry-plan` again until it says `accepted`. Only the operator can accept a smaller set than that, with their own quote. An unfinished reviewer is never counted as a clean pass. **Persist every result.** Pass each reviewer `save_result_to: .metaproject/data/review/raw/<reviewer>.txt`: the host writes its full final text there, so `review complete` has raw evidence even after the transcript is cut. Build `research.json` with `keryx review ledger build <input-dir> --package <review-dir>` — never by hand: it reads the saved results, `scope-files.json` and the retry state, marks a reviewer complete only when its result is finished and its payloads cover the scope, and prints each gap with the exact next command and the waves left (a `retry-plan --next-wave` call, or a `--dispositions` entry for a raw finding). Run `keryx review ingest --research <review-dir>/research.json` once it prints READY (exit 0). A refused `review complete` names what is missing: fix that with a command and run it again; it is never `blocked`. `--head` wants a SHA (`git rev-parse HEAD`), not `HEAD`.
88
+ 4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means the next wave while it makes progress, Not run when it stalls.** Every reviewer result lists the `slices` it covered, in its `REVIEW_RESULT` object, as ids (`"slices": ["slice-01", "slice-02"]`); an object with an `id` and an optional `coverage` note (`{"id": "slice-01", "coverage": "read in full"}`) is read the same way. An object with a `status` counts only when it is DONE, COMPLETE, COVERED or OK (any case); a slice marked NOT_READ, INCOMPLETE, SKIPPED or PARTIAL is not covered, so give a slice you did not read no `status` of that kind and leave it out. An entry with no id counts for nothing. **One driver file per dispatch.** Write `drivers/<reviewer>.json` next to `raw/` with `{"reviewer": "<name>", "slices": [<ids dispatched>], "result": "raw/<reviewer>.txt", "definition": "<path of the reviewer's SKILL.md>"}`: `ledger build` takes the reviewer's rule file from `definition` (a `skill_path` there, or inside a `payload` object, is read too) and the slices it was handed from `slices`. Only reviewer replies belong in `raw/`; a verification payload or a note filed there is reported as set aside and left in place, but it still costs a step. On `INCOMPLETE`, `BLOCKED` or `NEEDS_CONTEXT` (never accepted as a finished scope), and on a `DONE` that left slices open, `keryx review retry-plan --manifest <dir>/manifest.json --result <raw/reviewer.txt>` decides and hands out the next wave of only the slices still uncovered (`--next-wave` plans one without a result). A result that covered a new slice spends no attempt; two results in a row with nothing new, or six failed rounds, print the `- **Not run:** …` line to paste into the report, and a result with nothing new first has its open slices cut in half. Dispatch each wave, save its reply, and run `retry-plan` again until it says `accepted`. Only the operator can accept a smaller set than that, with their own quote. An unfinished reviewer is never counted as a clean pass. **Persist every result.** Pass each reviewer `save_result_to: .metaproject/data/review/raw/<reviewer>.txt`: the host writes its full final text there, so `review complete` has raw evidence even after the transcript is cut. Build `research.json` with `keryx review ledger build <input-dir> --package <review-dir>` — never by hand: it reads the saved results, `scope-files.json` and the retry state, marks a reviewer complete only when its result is finished and its payloads cover the scope, and prints each gap with the exact next command and the waves left (a `retry-plan --next-wave` call, or a `--dispositions` entry for a raw finding). Run `keryx review ingest --research <review-dir>/research.json` once it prints READY (exit 0). A refused `review complete` names what is missing: fix that with a command and run it again; it is never `blocked`. `--head` wants a SHA (`git rev-parse HEAD`), not `HEAD`.
89
89
  5. **Never print a scope or a slice.** The tool output of one call is cut at about 20 KB and `keryx review scope` of a large PR prints hundreds of KB. Run it as `keryx review scope --ref <base> --json > .metaproject/data/review/scope.json` and read the counts from the file (`keryx ctx read`, or `jq`); take `<base>` from `git symbolic-ref refs/remotes/origin/HEAD`, not a guessed `origin/main`. Create `.metaproject/data/review/` first (`mkdir -p`) — a missing directory is a command to run, not a blocker. **Machine artifacts by direct write.** Save slices, payloads and results by redirection or `keryx ctx run --raw -- <command>`; the summarized form of `keryx ctx run` drops the bytes a later step parses.
90
90
 
91
91
  ## Control
92
92
 
93
93
  - **Profiles.** The default is read-only: one round, no edits. `--fix` hands the findings to `flow-orchestrator` or `task-implementer`; the orchestrator never edits code. Control returns to this main session after each hand-off, which loads this skill again (never the implementer, which would nest); each re-review counts toward the ceiling (it adds 1 to the count).
94
94
  - **Waves.** Split by diff domain (`core` = logic, security, architecture; `domain` = frontend, backend, conventions; `support` = style, tests), in that order; A/B/C below keep their dependency order. A full or `--all` round runs at most 10 reviewers per wave (`MAX_REVIEWERS_PER_WAVE_FULL`).
95
- - **Rate limits.** On a reviewer dispatch that fails with a rate-limit or overloaded error (reported as `STATUS: RATE_LIMITED`, a harness signal, not a schema status), halve the wave, requeue the rest and honour `retry-after`. After at most two halvings (`MAX_RATE_HALVINGS`) stop with `STATUS: BLOCKED rate_limited`, naming the queue left.
96
- - **Done when** every dispatched reviewer's result is recorded with `keryx review ingest`, the stage counts and **Not run** are in the report, and `keryx review complete` has run.
95
+ - **Rate limits.** On a reviewer dispatch that fails with a rate-limit or overloaded error (reported as `STATUS: RATE_LIMITED`, a harness signal, not a schema status), halve the wave, requeue the rest and honour `retry-after`, at most 300 seconds (`MAX_RETRY_AFTER_SECONDS`). After at most two halvings (`MAX_RATE_HALVINGS`) stop with `STATUS: BLOCKED rate_limited`, naming the queue left.
96
+ - **Done when** the consolidated report and the `keryx:findings` block are emitted and the stage counts and **Not run** are stated. A managed round (not `lightweight`, which is report-only) is also done only when every dispatched reviewer's result is recorded with `keryx review ingest` and `keryx review complete` has run.
97
97
 
98
98
  ---
99
99
 
@@ -207,8 +207,7 @@ keryx review complete <review-id-or-path>
207
207
  [--finding <id> --disposition <state> --evidence <ref>]...
208
208
  ```
209
209
 
210
- **An unrecognised option is refused, not ignored** — a misspelled flag exits
211
- non-zero rather than printing `status: closed` and writing nothing at all.
210
+ **An unrecognised option is refused, not ignored** — a misspelled flag exits non-zero rather than printing `status: closed` and writing nothing at all.
212
211
 
213
212
  `--verifications` takes what `review-verifier` returned. `--scope` takes the
214
213
  whole `--json` output of `keryx review scope`, so the package records what the
@@ -234,9 +233,7 @@ Two channels, and both work:
234
233
  it: it is copied into the package it screened and removed from the slot, so a
235
234
  later round cannot be screened against a set nobody recomputed.
236
235
 
237
- Do **not** write the record inside the package directory before the ingest. A
238
- round that names no `--review-id` has not allocated that directory yet, and
239
- creating it makes the ingest take the next free name instead.
236
+ Do **not** write the record inside the package directory before the ingest. A round that names no `--review-id` has not allocated that directory yet, and creating it makes the ingest take the next free name instead.
240
237
 
241
238
  `--refuted` takes the findings this round **raised and then dismissed**, in the
242
239
  same finding shape, each carrying `disposition: {state, evidence}` with one of
@@ -252,9 +249,12 @@ Everything except `unknown` must cite where the outcome is written down — the
252
249
  commit, the test, the decision. A recorded state and its citation cannot be
253
250
  overwritten by a later close; record a correction as a new round.
254
251
 
255
- **Closing a fix round without dispositions leaves every finding reading
256
- `unknown`.** That is not "the reviewers were right"; it is "nobody wrote down
257
- what happened", and it is the single reason the precision figure cannot be read.
252
+ `review complete` on a PR-bound package refuses a merged PR or a moved head unless `report.md`'s first line names the reviewed SHA and says so; a package with no PR binding is unaffected.
253
+ `review complete` refuses a report with no `Evidence level:` line (`static only — did not run: <what>` or `ran — <what>`); a package ingested before the field existed only warns.
254
+ `review ingest` refuses an internal finding whose `quote` is not at its `path` at the reviewed SHA, and adds a `citation not found` line, never a deletion, to a rebuttal citing a rule or document that is not in the tree.
255
+ A finding may close as `narrowed` (research obligation `"status":"narrowed","remains":"<what remains>"`); it counts as closed only with that text, and the report keeps it under "Refuted and narrowed".
256
+
257
+ **Closing a fix round without dispositions leaves every finding reading `unknown`.** That is not "the reviewers were right"; it is "nobody wrote down what happened", and it is the single reason the precision figure cannot be read.
258
258
 
259
259
  Managed modes:
260
260
 
@@ -401,8 +401,8 @@ question at the end answers the wrong question late.
401
401
  human or a bot has already reviewed pull request `#A`, and someone wants those
402
402
  comments interpreted, checked against the code, fixed and answered. Under its
403
403
  `--fix` mode it dispatches `flow-orchestrator`, which opens a **second** pull
404
- request `#B` carrying the fix, based on `#A`'s own head branch, and dispatches
405
- **this** orchestrator on every round against `#B`. `review-pr-feedback` is present only when installed — it is in the `full` profile only. When it is absent no caller of this kind exists, so the default below holds and this orchestrator owns the reply; do not hand a request to it, say it is not installed and name the install command (`SKILL.detail.md`, "Skills present only when installed").
404
+ request `#B` carrying the fix, based on `#A`'s own head branch, and runs
405
+ **this** orchestrator inline, in the main session, on every round against `#B`. `review-pr-feedback` is present only when installed — it is in the `full` profile only. When it is absent no caller of this kind exists, so the default below holds and this orchestrator owns the reply; do not hand a request to it, say it is not installed and name the install command (`SKILL.detail.md`, "Skills present only when installed").
406
406
 
407
407
  `#B` is its own conversation. Collect and reply on it exactly as always: someone
408
408
  reviewing the fix deserves an answer from the run that made the fix, and its
@@ -516,7 +516,7 @@ the SHA:
516
516
 
517
517
  ```yaml
518
518
  cross_repo:
519
- - repo: vantage-backend
519
+ - repo: acme-backend
520
520
  state: merged
521
521
  sha: f5219d5d4
522
522
  merge_order: independent
@@ -792,13 +792,11 @@ and those are different questions — only the first has ever been asked here.
792
792
  A deep round dispatches under **both**. Scope B is computed, never browsed:
793
793
 
794
794
  ```bash
795
- keryx review blast-radius --ref "${BASE_SHA}" --json > blast-radius.json # KEEP THIS FILE
796
- keryx review blast-radius --ref "${BASE_SHA}" --brief # what a scope-B reviewer is told
795
+ keryx review blast-radius --ref "${BASE_SHA}" --package "${PKG}" --json > blast-radius.json # KEEP THIS FILE
796
+ keryx review blast-radius --ref "${BASE_SHA}" --package "${PKG}" --brief # what a scope-B reviewer is told
797
797
  ```
798
798
 
799
- **KEEP THIS FILE** is not advice. The ingest at Step 12 is **refused** if a
800
- scope-B finding arrives without it — pass it back as
801
- `review ingest ... --blast-radius blast-radius.json`.
799
+ **KEEP THIS FILE**: the ingest at Step 12 is **refused** for a scope-B finding without it — pass it as `review ingest ... --blast-radius blast-radius.json`.
802
800
 
803
801
  Scope B is bounded and computed: distance ≤ 2 from every changed file, at most 40 files, closest
804
802
  first. Do not pick the files or widen the set. Record it with `--out "<review-package>/blast-radius.md"`,
@@ -813,9 +811,11 @@ names the caller that breaks.
813
811
  Recompute scope B on rounds 2..N only when the changed-file set moved, and always on the final round:
814
812
 
815
813
  ```bash
816
- keryx review blast-radius --ref "${BASE_SHA}" --previous blast-radius.json [--final]
814
+ keryx review blast-radius --ref "${BASE_SHA}" --package "${PKG}" --previous blast-radius.json [--final]
817
815
  ```
818
816
 
817
+ `PKG` is the review package, created by `keryx review start` before dispatch; `--package` makes scope B read the graph built at the PR head. Give each reviewer `keryx review layers block --package "${PKG}" --files <its slice files> --json` as the payload's `layers` field.
818
+ When `dropped` is non-empty, run `keryx review chunks plan|estimate|next|record|merge --package "${PKG}"` until `next` has none left. `review complete` refuses while a file is uncovered; `--waive-coverage "<operator quote>"` takes the operator's own words only, never yours.
819
819
  The measurements, the rule table and the recompute table: `SKILL.detail.md` § "Scope B — bounds, rejections and recompute".
820
820
 
821
821
  ### Path Mode
@@ -824,13 +824,15 @@ When a path or target is named, collect the candidate files:
824
824
 
825
825
  ```bash
826
826
  # If a directory path is given:
827
- keryx ctx rg --files -g '*.{ts,tsx,js,jsx}' <path> | sort
827
+ keryx ctx run --raw -- rg --files -g '*.{ts,tsx,js,jsx}' <path> | sort
828
828
 
829
829
  # If a module name is given (e.g. "UserStore", "pipelines module"):
830
- keryx ctx rg --files -g '*<name>*.{ts,tsx}'
830
+ keryx ctx run --raw -- rg --files -g '*<name>*.{ts,tsx}' | sort
831
831
  # Also check common locations: src/stores/, src/modules/, src/components/
832
832
  ```
833
833
 
834
+ `--raw` returns plain paths, one per line, and the whole list. The summarized form (`keryx ctx rg --files`) prints header lines among the paths and cuts the list at 120 entries, so a round built on it silently covers a part of the scope. Only path lines are file entries.
835
+
834
836
  Then put the list through the same exclusions before reading anything:
835
837
 
836
838
  ```bash
@@ -184,6 +184,22 @@
184
184
  "type": "string"
185
185
  }
186
186
  },
187
+ "slices": {
188
+ "title": "Slices this result covered",
189
+ "description": "The ids of the dispatched slices the reviewer read. An entry is an id string, or an object with an `id`, an optional `coverage` note and an optional `status`. `keryx review retry-plan` and `ledger build` read both. An object counts as covered only when its `status` is absent or one of DONE, COMPLETE, COMPLETED, COVERED, OK (any case); any other status (NOT_READ, INCOMPLETE, SKIPPED, PARTIAL, …) leaves the slice uncovered and is named in the plan reason or the ledger gap. An entry with no id counts for nothing.",
190
+ "type": "array",
191
+ "items": {
192
+ "type": ["string", "object"],
193
+ "minLength": 1,
194
+ "required": ["id"],
195
+ "properties": {
196
+ "id": { "type": "string", "minLength": 1 },
197
+ "coverage": { "type": "string" },
198
+ "status": { "type": "string" }
199
+ },
200
+ "additionalProperties": true
201
+ }
202
+ },
187
203
  "stats": {
188
204
  "type": "object",
189
205
  "required": [
@@ -223,6 +223,59 @@
223
223
  "additionalProperties": true
224
224
  }
225
225
  },
226
+ "layers": {
227
+ "type": "object",
228
+ "description": "The bounded layers block for this reviewer's files, built from the package's own graph, the working-copy wiki and the memory (`keryx review layers block --package <dir> --files <a,b>`). Optional. `truncated` names what was cut and the command that fetches the rest.",
229
+ "required": ["version", "files", "affected", "truncated"],
230
+ "properties": {
231
+ "version": { "const": 1 },
232
+ "files": { "type": "array", "items": { "type": "string" } },
233
+ "prHead": { "type": ["string", "null"] },
234
+ "graphCommit": { "type": ["string", "null"] },
235
+ "maxBytes": { "type": "integer", "minimum": 1 },
236
+ "affected": {
237
+ "type": "object",
238
+ "required": ["depth", "files"],
239
+ "properties": {
240
+ "depth": { "enum": [1, 2] },
241
+ "files": { "type": "array", "items": { "type": "string" } }
242
+ },
243
+ "additionalProperties": false
244
+ },
245
+ "symbols": { "type": "array", "items": { "type": "object" } },
246
+ "relatedTests": { "type": "array", "items": { "type": "string" } },
247
+ "wiki": { "type": "array", "items": { "type": "object" } },
248
+ "memory": { "type": "array", "items": { "type": "object" } },
249
+ "truncated": {
250
+ "type": "array",
251
+ "items": {
252
+ "type": "object",
253
+ "required": ["section", "shown", "total", "command"],
254
+ "properties": {
255
+ "section": { "enum": ["files", "affected", "symbols", "relatedTests", "wiki", "memory"] },
256
+ "shown": { "type": "integer", "minimum": 0 },
257
+ "total": { "type": "integer", "minimum": 0 },
258
+ "command": { "type": "string" }
259
+ },
260
+ "additionalProperties": false
261
+ }
262
+ },
263
+ "unavailable": {
264
+ "type": "array",
265
+ "description": "Sections that could not be read, with the reason. An empty section that is not listed here was read and held nothing.",
266
+ "items": {
267
+ "type": "object",
268
+ "required": ["section", "reason"],
269
+ "properties": {
270
+ "section": { "enum": ["affected", "wiki", "memory"] },
271
+ "reason": { "type": "string" }
272
+ },
273
+ "additionalProperties": false
274
+ }
275
+ }
276
+ },
277
+ "additionalProperties": false
278
+ },
226
279
  "metaproject": {
227
280
  "type": "object",
228
281
  "description": "Shared project context, the same context `keryx flow init` already collects for an implementation flow. The review pipeline collected none of it for eleven rounds, which is why a recorded lesson naming the exact recurring failure never reached a reviewer.",
@@ -16,7 +16,7 @@ React / MobX
16
16
  - Disposers run on unmount; an async callback checks them before writing.
17
17
  - State that outlives the view lives in the store, not in `useState`.
18
18
 
19
- Vantage conventions (skip a line the repository has no rule for)
19
+ Acme conventions (skip a line the repository has no rule for)
20
20
 
21
21
  - `t()` only in render, no `defaultValue`.
22
22
  - Arabic plurals and FSI/PDI isolates where the catalog has them.
@@ -34,8 +34,10 @@ what a reader must act on; everything else is folded.
34
34
 
35
35
  ```markdown
36
36
  <!-- slot:pre-verdict -->
37
+ <only when the PR merged or its head moved: "Reviewed `<sha>` — the PR has since merged / moved on to `<new sha>`." as the very first line>
37
38
  **Changes requested — 1 Blocker, 2 Major, 4 Minor, 1 question.** <what holds, and where the risk is — one sentence.>
38
39
  Reviewed `<head>` against `<base>` · round N · <files> files, +<add>/−<del> · CI <green | red: check names>.
40
+ Evidence level: <static only — did not run: tests, build | ran — the commands that ran>
39
41
  <!-- slot:after-verdict -->
40
42
 
41
43
  ### Prior findings (fix rounds only)
@@ -43,6 +45,7 @@ Reviewed `<head>` against `<base>` · round N · <files> files, +<add>/−<del>
43
45
  ### Major
44
46
  ### Minor
45
47
  ### Questions
48
+ ### Refuted and narrowed (only when a finding was dismissed or narrowed)
46
49
 
47
50
  <details><summary><b>Pre-existing (not blocking)</b></summary> … </details>
48
51
  <details><summary><b>Scope</b></summary> … </details> (only when a pr-process note exists)
@@ -68,6 +71,25 @@ author answer, rendered under Questions, not as a finding.
68
71
  The second line is the context line: head, base, round, size, CI. If head moved
69
72
  during the round, add `· unchecked: <commits>`.
70
73
 
74
+ The third line is the **evidence level** and is required: `Evidence level: static
75
+ only — did not run: <what>` when nothing was executed, or `Evidence level: ran —
76
+ <what ran>`. `keryx review complete` refuses a report without it.
77
+
78
+ When the PR was merged or its head moved after the review, the report's first line
79
+ says so and names the reviewed SHA, or `keryx review complete` refuses.
80
+
81
+ ### Refuted and narrowed
82
+
83
+ One line per finding that did not stand as reported, kept with its evidence so a
84
+ reader sees what was claimed and why it was set aside:
85
+
86
+ ```markdown
87
+ - **F-007. Dismissed** — <the author's rebuttal, quoted>. <citation not found: …> where the cited rule is not in the tree.
88
+ - **F-009. Narrowed** — <what the finding claimed>. **Remains:** <what is still open>. Evidence: <what was run>.
89
+ ```
90
+
91
+ A narrowed finding counts as closed only with its "Remains" text.
92
+
71
93
  ## One finding
72
94
 
73
95
  Blocker and Major as a paragraph, visible:
@@ -339,21 +339,21 @@ Stop and re-read these rules if you are thinking:
339
339
 
340
340
  ## Job Context Awareness
341
341
 
342
- When dispatched by `job-orchestrator` or `review-orchestrator` as part of a job pipeline, the prompt MAY include:
342
+ When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
343
343
 
344
- ```
345
- JOB_NAME: <job-name>
346
- CONTEXT_PATH: <JOBS_ROOT>/<job-name>/ai/context.md
347
- ```
344
+ ## Orchestrated Review Contract
348
345
 
349
- If provided and the file exists, read the context document before starting the review. Use it to:
350
- - Understand expected dataset sizes and traffic patterns documented for the project
351
- - Identify ORM and caching strategies already in place (avoid flagging already-cached paths)
352
- - Understand which MobX patterns and React memo conventions the project follows
353
- - Avoid flagging intentional trade-offs (e.g., a known small dataset where pagination is explicitly deferred)
346
+ When dispatched by `review-orchestrator`, follow the provided `reviewer-input.schema.json` payload. Return a `REVIEW_RESULT` object compatible with `.metaproject/skills/gdskills/review/review-orchestrator/reviewer-finding.schema.json`, then a concise markdown summary. Keep findings evidence-based, include concrete `suggested_fix` for every blocker/major, and return `NEEDS_CONTEXT` instead of guessing when required context is missing.
354
347
 
355
- If the file does not exist or is not provided, proceed normally — context is optional and non-blocking.
348
+ <!-- keryx:layers-block:start -->
349
+ ## Project layers: graph, tests, wiki, memory
356
350
 
357
- ## Orchestrated Review Contract
351
+ Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
358
352
 
359
- When dispatched by `review-orchestrator`, follow the provided `reviewer-input.schema.json` payload. Return a `REVIEW_RESULT` object compatible with `.metaproject/skills/gdskills/review/review-orchestrator/reviewer-finding.schema.json`, then a concise markdown summary. Keep findings evidence-based, include concrete `suggested_fix` for every blocker/major, and return `NEEDS_CONTEXT` instead of guessing when required context is missing.
353
+ - `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
354
+ - `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
355
+ - `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
356
+ - `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
357
+
358
+ In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
359
+ <!-- keryx:layers-block:end -->
@@ -168,20 +168,11 @@ Severity comes from **Severity (canonical)** in `review-orchestrator/SKILL.md`;
168
168
 
169
169
  ### Shared laws (every reviewer)
170
170
 
171
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
172
- name the input, call, or condition that reaches the code, you have an
173
- observation, not a finding. Report it as `info` and say what would settle it.
174
- 2. **Never flag the theoretical.** The path you describe must exist in the code
175
- under review. Do not report a safe API because it could be misused, or a
176
- pattern because it is often wrong elsewhere.
177
- 3. **One finding per class, not one per occurrence.** When the same shape appears
178
- at several sites, report it once and list every site. Ten findings that are one
179
- finding hide the other nine problems.
180
-
181
- Severity levels are defined once, in `review-orchestrator/SKILL.md` →
182
- **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
183
- four merge-blocking shapes named there and nothing else, and the `major`/`minor`
184
- boundary is the trigger-and-outcome test.
171
+ 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
+ 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
+ 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.
174
+
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.
185
176
 
186
177
  ---
187
178
 
@@ -203,14 +194,21 @@ boundary is the trigger-and-outcome test.
203
194
 
204
195
  Report done only once all of these hold:
205
196
 
206
- - Every finding is anchored inside the computed set or the changed set, at the
207
- code that **breaks** rather than the code that changed.
208
- - Every finding is `major` or above, and every `major` names the changed file,
209
- module or symbol whose behaviour moved — the anchor alone does not carry it.
210
- - Every finding carries `class_scope` whose `sites` are the callers that break and
211
- whose `enumeration_method` is the walk over the blast-radius set that produced
212
- them.
213
- - The summary states whether the cap dropped files, and whether the radius could
214
- answer the question at all for the shape of this change.
215
- - Nothing that is merely an observation about pre-existing code is filed here; it
216
- is either raised under scope A or not at all.
197
+ - Every finding is anchored inside the computed set or the changed set, at the code that **breaks** rather than the code that changed.
198
+ - Every finding is `major` or above, and every `major` names the changed file, module or symbol whose behaviour moved — the anchor alone does not carry it.
199
+ - Every finding carries `class_scope` whose `sites` are the callers that break and whose `enumeration_method` is the walk over the blast-radius set that produced them.
200
+ - The summary states whether the cap dropped files, and whether the radius could answer the question at all for the shape of this change.
201
+ - Nothing that is merely an observation about pre-existing code is filed here; it is either raised under scope A or not at all.
202
+
203
+ <!-- keryx:layers-block:start -->
204
+ ## Project layers: graph, tests, wiki, memory
205
+
206
+ Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
207
+
208
+ - `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
209
+ - `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
210
+ - `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
211
+ - `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
212
+
213
+ In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
214
+ <!-- keryx:layers-block:end -->
@@ -342,21 +342,7 @@ Stop and re-read these rules if you are thinking:
342
342
 
343
343
  ## Job Context Awareness
344
344
 
345
- When dispatched by `job-orchestrator` or `review-orchestrator` as part of a job pipeline, the prompt MAY include:
346
-
347
- ```
348
- JOB_NAME: <job-name>
349
- CONTEXT_PATH: <JOBS_ROOT>/<job-name>/ai/context.md
350
- ```
351
-
352
- If provided and the file exists, read the context document before starting the review. Use it to:
353
- - Understand which auth framework is in use (custom JWT, Passport, Keycloak, etc.)
354
- - Identify intentional public endpoints that are documented as unauthenticated by design
355
- - Understand which validation library and pipe configuration the project uses
356
- - Avoid flagging intentional architectural security decisions as findings
357
-
358
- If the file does not exist or is not provided, proceed normally — context is optional and non-blocking.
359
-
345
+ When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
360
346
 
361
347
  ## Orchestrated Review Contract
362
348
 
@@ -364,3 +350,15 @@ When dispatched by `review-orchestrator`, follow the provided `reviewer-input.sc
364
350
 
365
351
  ---
366
352
 
353
+ <!-- keryx:layers-block:start -->
354
+ ## Project layers: graph, tests, wiki, memory
355
+
356
+ Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
357
+
358
+ - `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
359
+ - `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
360
+ - `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
361
+ - `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
362
+
363
+ In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
364
+ <!-- keryx:layers-block:end -->