@mrciphersmith/keryx 0.3.112 → 0.3.113

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 (37) hide show
  1. package/README.md +17 -3
  2. package/THIRD_PARTY_NOTICES.md +56 -0
  3. package/dist/cli.js +106311 -101534
  4. package/dist/core.js +5525 -4329
  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 +19 -17
  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 +40 -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-performance/SKILL.md +13 -13
  35. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +23 -25
  36. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +13 -15
  37. 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
 
@@ -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,46 @@
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
+ },
264
+ "additionalProperties": false
265
+ },
226
266
  "metaproject": {
227
267
  "type": "object",
228
268
  "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.
@@ -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 -->
@@ -192,20 +192,11 @@ pass, then work the checklist.
192
192
 
193
193
  ### Shared laws (every reviewer)
194
194
 
195
- 1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot
196
- name the input, call, or condition that reaches the code, you have an
197
- observation, not a finding. Report it as `info` and say what would settle it.
198
- 2. **Never flag the theoretical.** The path you describe must exist in the code
199
- under review. Do not report a safe API because it could be misused, or a
200
- pattern because it is often wrong elsewhere.
201
- 3. **One finding per class, not one per occurrence.** When the same shape appears
202
- at several sites, report it once and list every site. Ten findings that are one
203
- finding hide the other nine problems.
204
-
205
- Severity levels are defined once, in `review-orchestrator/SKILL.md` →
206
- **Severity (canonical)**. This reviewer does not restate them: `blocker` is the
207
- four merge-blocking shapes named there and nothing else, and the `major`/`minor`
208
- boundary is the trigger-and-outcome test.
195
+ 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
+ 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
+ 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.
198
+
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.
209
200
 
210
201
  ---
211
202
 
@@ -219,15 +210,9 @@ When dispatched by `review-orchestrator`, follow the provided `reviewer-input.sc
219
210
 
220
211
  ### Class scope — required for `blocker` and `major`
221
212
 
222
- Every `blocker` and `major` finding must carry `class_scope`: **every** site that
223
- holds the shape you found, and **how you enumerated them** — the grep or query
224
- you ran, or the guard that derives the set.
213
+ Every `blocker` and `major` finding must carry `class_scope`: **every** site that holds the shape you found, and **how you enumerated them** — the grep or query you ran, or the guard that derives the set.
225
214
 
226
- A finding anchored to one `file:line` is a claim about one site. The recorded
227
- history of this repository is that a fix then repairs that site and leaves its
228
- siblings: one writer of five, one operator instruction of four, six readers of
229
- eight. Each was found by the *next* review round, which is why reviews here have
230
- run to seven and four rounds instead of one.
215
+ A finding anchored to one `file:line` is a claim about one site. The recorded history of this repository is that a fix then repairs that site and leaves its siblings: one writer of five, one operator instruction of four, six readers of eight. Each was found by the *next* review round, which is why reviews here have run to seven and four rounds instead of one.
231
216
 
232
217
  ```yaml
233
218
  class_scope:
@@ -235,12 +220,9 @@ class_scope:
235
220
  enumeration_method: "grep for the config-path resolvers; 7 writers, 2 unguarded"
236
221
  ```
237
222
 
238
- "I checked the others" is not an enumeration method. A single-entry `sites` list
239
- is a claim that the class has exactly one member — make it deliberately, because
240
- `review-finding.schema.json` accepts it and the next round tests it.
223
+ "I checked the others" is not an enumeration method. A single-entry `sites` list is a claim that the class has exactly one member — make it deliberately, because `review-finding.schema.json` accepts it and the next round tests it.
241
224
 
242
- `minor` and `info` may omit it: enumerating the class for every low-severity
243
- observation is theatre, not rigour.
225
+ `minor` and `info` may omit it: enumerating the class for every low-severity observation is theatre, not rigour.
244
226
 
245
227
  ```markdown
246
228
  ### [F-NNN] Title
@@ -252,9 +234,7 @@ observation is theatre, not rigour.
252
234
  - **Fix**: concrete test rewrite or fixture/handler change
253
235
  ```
254
236
 
255
- Severity comes from **Severity (canonical)** in `review-orchestrator/SKILL.md`.
256
- This reviewer keeps no rubric of its own; what follows is where its recurring
257
- conditions land under that rubric.
237
+ Severity comes from **Severity (canonical)** in `review-orchestrator/SKILL.md`. This reviewer keeps no rubric of its own; what follows is where its recurring conditions land under that rubric.
258
238
 
259
239
  | Condition | Severity | Why, under the canonical rubric |
260
240
  |---|---|---|
@@ -266,22 +246,11 @@ conditions land under that rubric.
266
246
  | Substrate choice, smoke tagging, locator priority, co-location | `minor` | The suite is correct; the cost is to whoever maintains it |
267
247
  | A convention preference with no effect on determinism or signal | `info` | Shared laws 1 and 2 |
268
248
 
269
- A flaky test is `major`, not `blocker`: it wastes time, but it does not ship a
270
- defect. A test that cannot fail does — which is why it is the one `blocker` here.
249
+ A flaky test is `major`, not `blocker`: it wastes time, but it does not ship a defect. A test that cannot fail does — which is why it is the one `blocker` here.
271
250
 
272
- The three mutation-pass rows sit at `minor` deliberately, and the reasoning is
273
- the canonical rubric rather than modesty: a coverage gap names no runtime trigger
274
- and no user-visible outcome, so it cannot be `major` under the boundary test. What
275
- makes them worth reporting is not severity but **evidence class** — each one is a
276
- command that ran, which is the rarest thing in a review and the only kind of
277
- finding a later round cannot argue away. Report them with the mutation and its
278
- result, and they survive adjudication intact. Report them as "coverage looks
279
- thin" and they are correctly discarded.
251
+ The three mutation-pass rows sit at `minor` deliberately, and the reasoning is the canonical rubric rather than modesty: a coverage gap names no runtime trigger and no user-visible outcome, so it cannot be `major` under the boundary test. What makes them worth reporting is not severity but **evidence class** — each one is a command that ran, which is the rarest thing in a review and the only kind of finding a later round cannot argue away. Report them with the mutation and its result, and they survive adjudication intact. Report them as "coverage looks thin" and they are correctly discarded.
280
252
 
281
- The moment a surviving mutation is accompanied by a **reachable input that makes
282
- the unpinned code do the wrong thing**, that is a separate finding at the severity
283
- its own outcome earns — usually `major`. The coverage gap and the defect are two
284
- findings, not one, and conflating them loses whichever the adjudicator disbelieves.
253
+ The moment a surviving mutation is accompanied by a **reachable input that makes the unpinned code do the wrong thing**, that is a separate finding at the severity its own outcome earns — usually `major`. The coverage gap and the defect are two findings, not one, and conflating them loses whichever the adjudicator disbelieves.
285
254
 
286
255
  ---
287
256
 
@@ -303,17 +272,22 @@ findings, not one, and conflating them loses whichever the adjudicator disbeliev
303
272
 
304
273
  Report done only once all of these hold:
305
274
 
306
- - The mutation table is published in full, survivors and casualties both, or the
307
- report says which command failed and that the pass was skipped.
308
- - The report states the cap: how many added or previously-requested gates were
309
- mutated and how many were not reached.
310
- - Every finding names `file:line` and the evidence that settles it — the mutation
311
- and its result, the producer line, or the selector that names the branch.
312
- - Every `blocker` and `major` carries `class_scope` with `sites` and an
313
- `enumeration_method` naming the search that produced them.
314
- - No finding invents a severity: each lands under **Severity (canonical)** in
315
- `review-orchestrator/SKILL.md`, and a coverage gap is filed separately from any
316
- defect it exposes.
317
- - The reply is the `REVIEW_RESULT` the Orchestrated Review Contract asks for, or
318
- `NEEDS_CONTEXT` naming the context that was missing — never a guess in its place.
275
+ - The mutation table is published in full, survivors and casualties both, or the report says which command failed and that the pass was skipped.
276
+ - The report states the cap: how many added or previously-requested gates were mutated and how many were not reached.
277
+ - Every finding names `file:line` and the evidence that settles it — the mutation and its result, the producer line, or the selector that names the branch.
278
+ - Every `blocker` and `major` carries `class_scope` with `sites` and an `enumeration_method` naming the search that produced them.
279
+ - No finding invents a severity: each lands under **Severity (canonical)** in `review-orchestrator/SKILL.md`, and a coverage gap is filed separately from any defect it exposes.
280
+ - The reply is the `REVIEW_RESULT` the Orchestrated Review Contract asks for, or `NEEDS_CONTEXT` naming the context that was missing — never a guess in its place.
281
+
282
+ <!-- keryx:layers-block:start -->
283
+ ## Project layers: graph, tests, wiki, memory
284
+
285
+ 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.
286
+
287
+ - `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.
288
+ - `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.
289
+ - `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.
290
+ - `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.
319
291
 
292
+ 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.
293
+ <!-- keryx:layers-block:end -->