@mrciphersmith/keryx 0.3.5 → 0.3.7

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 (84) hide show
  1. package/README.md +47 -0
  2. package/dist/cli.js +3099 -1160
  3. package/dist/core.js +22 -3
  4. package/docs/README.md +2 -0
  5. package/package.json +1 -1
  6. package/src/gdskills/bundled/install-manifest.json +319 -76
  7. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.md +19 -26
  8. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +6 -6
  9. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +4 -7
  10. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +2 -4
  11. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +23 -0
  12. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +17 -17
  13. package/src/gdskills/bundled/stacks/django/agent-refs.json +3 -0
  14. package/src/gdskills/bundled/stacks/django/governance/eval.json +1763 -0
  15. package/src/gdskills/bundled/stacks/django/governance/scout.json +40 -0
  16. package/src/gdskills/bundled/stacks/django/pack.json +43 -0
  17. package/src/gdskills/bundled/stacks/django/rules/coding-style.mdc +80 -0
  18. package/src/gdskills/bundled/stacks/django/rules/patterns.mdc +92 -0
  19. package/src/gdskills/bundled/stacks/django/rules/security.mdc +92 -0
  20. package/src/gdskills/bundled/stacks/django/rules/testing.mdc +89 -0
  21. package/src/gdskills/bundled/stacks/django/skills/django-build-fix/SKILL.md +149 -0
  22. package/src/gdskills/bundled/stacks/django/skills/django-build-fix/evals.json +49 -0
  23. package/src/gdskills/bundled/stacks/django/skills/django-code-review/SKILL.md +137 -0
  24. package/src/gdskills/bundled/stacks/django/skills/django-code-review/evals.json +48 -0
  25. package/src/gdskills/bundled/stacks/django/skills/django-implementation/SKILL.md +147 -0
  26. package/src/gdskills/bundled/stacks/django/skills/django-implementation/evals.json +75 -0
  27. package/src/gdskills/bundled/stacks/django/skills/django-migrate/SKILL.md +166 -0
  28. package/src/gdskills/bundled/stacks/django/skills/django-migrate/evals.json +49 -0
  29. package/src/gdskills/bundled/stacks/django/skills/django-testing/SKILL.md +130 -0
  30. package/src/gdskills/bundled/stacks/django/skills/django-testing/evals.json +48 -0
  31. package/src/gdskills/bundled/stacks/fastapi/agent-refs.json +3 -0
  32. package/src/gdskills/bundled/stacks/fastapi/governance/eval.json +1777 -0
  33. package/src/gdskills/bundled/stacks/fastapi/governance/scout.json +34 -0
  34. package/src/gdskills/bundled/stacks/fastapi/pack.json +43 -0
  35. package/src/gdskills/bundled/stacks/fastapi/rules/coding-style.mdc +68 -0
  36. package/src/gdskills/bundled/stacks/fastapi/rules/patterns.mdc +108 -0
  37. package/src/gdskills/bundled/stacks/fastapi/rules/security.mdc +99 -0
  38. package/src/gdskills/bundled/stacks/fastapi/rules/testing.mdc +85 -0
  39. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/SKILL.md +157 -0
  40. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/evals.json +76 -0
  41. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/SKILL.md +150 -0
  42. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/evals.json +74 -0
  43. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/SKILL.md +158 -0
  44. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/evals.json +75 -0
  45. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/SKILL.md +146 -0
  46. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/evals.json +74 -0
  47. package/src/gdskills/bundled/stacks/java-kotlin-spring/agent-refs.json +3 -0
  48. package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/eval.json +2194 -0
  49. package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/scout.json +39 -0
  50. package/src/gdskills/bundled/stacks/java-kotlin-spring/pack.json +40 -0
  51. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/coding-style.mdc +67 -0
  52. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/patterns.mdc +65 -0
  53. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/security.mdc +69 -0
  54. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/testing.mdc +80 -0
  55. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/SKILL.md +144 -0
  56. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/evals.json +74 -0
  57. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/SKILL.md +129 -0
  58. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/evals.json +74 -0
  59. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/SKILL.md +147 -0
  60. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/evals.json +75 -0
  61. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/SKILL.md +139 -0
  62. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/evals.json +74 -0
  63. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/SKILL.md +128 -0
  64. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/evals.json +73 -0
  65. package/src/gdskills/bundled/stacks/python/agent-refs.json +2 -1
  66. package/src/gdskills/bundled/stacks/python/pack.json +1 -1
  67. package/src/gdskills/bundled/stacks/rust/agent-refs.json +3 -0
  68. package/src/gdskills/bundled/stacks/rust/governance/eval.json +1823 -0
  69. package/src/gdskills/bundled/stacks/rust/governance/scout.json +32 -0
  70. package/src/gdskills/bundled/stacks/rust/pack.json +42 -0
  71. package/src/gdskills/bundled/stacks/rust/rules/coding-style.mdc +93 -0
  72. package/src/gdskills/bundled/stacks/rust/rules/patterns.mdc +85 -0
  73. package/src/gdskills/bundled/stacks/rust/rules/security.mdc +85 -0
  74. package/src/gdskills/bundled/stacks/rust/rules/testing.mdc +82 -0
  75. package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/SKILL.md +141 -0
  76. package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/evals.json +78 -0
  77. package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/SKILL.md +127 -0
  78. package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/evals.json +72 -0
  79. package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/SKILL.md +133 -0
  80. package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/evals.json +79 -0
  81. package/src/gdskills/bundled/stacks/rust/skills/rust-testing/SKILL.md +130 -0
  82. package/src/gdskills/bundled/stacks/rust/skills/rust-testing/evals.json +75 -0
  83. package/src/gdskills/bundled/agents/python-build-fixer.md +0 -52
  84. package/src/gdskills/bundled/agents/python-code-auditor.md +0 -49
@@ -799,6 +799,8 @@ Task({
799
799
  })
800
800
  ```
801
801
 
802
+ **Before this wave's first task-implementer dispatch:** when `review.jev.edit_guard` is on (`.metaproject/tasks.config.json`), confirm the guard is active — `keryx review jev-edit-guard status`, else `keryx review jev-edit-guard install` — and say why in one line.
803
+
802
804
  #### task-implementer dispatch (Step B)
803
805
 
804
806
  ```
@@ -2024,6 +2026,7 @@ Each step failure is classified into one of three classes with different recover
2024
2026
  | All reviewers fail | `recoverable` | Record the round as failed with a reason, add a warning to the report, continue to VERIFY (2.8) |
2025
2027
  | Fix loop exceeds max_review_iterations | `recoverable` | Disposition every surviving finding, log which ended the loop, continue to VERIFY (2.8) |
2026
2028
  | Final checks fail | `recoverable` | Include in report, still propose PR (user decides) |
2029
+ | A GitHub CI check on the PR fails | `recoverable` | When `review.jev.ci_triage` is on, run `keryx review ci-triage --run <id> --json` before reporting it as a defect: `flaky`/`deterministic` → rerun once and note it in the report, a second failure counts as `real-regression`; `real-regression` → treat as a real failure; `infra` → report it, don't touch code. Verdict is advisory only. |
2027
2030
  | gh CLI not available | `recoverable` | Print PR data, user creates manually. `keryx review comments` needs it too — say so rather than reporting `0 outstanding`. |
2028
2031
 
2029
2032
  ### Retry Protocol (for `retryable` errors)
@@ -2041,13 +2044,7 @@ attempt 1: keryx job step <job-name> <step-id> --status in-progress
2041
2044
  **Critical:** on retry, re-send the **same prompt** — hold it for the duration of the
2042
2045
  step and re-send it verbatim. Never re-derive it; re-derivation causes drift.
2043
2046
 
2044
- The prompt itself is **not** persisted: `keryx job` writes no `step.prompt` and no
2045
- prompt size, so do not instruct a resuming session to read one. What *is* persisted is
2046
- that the attempt happened — `metrics.steps[].retries`, incremented every time the step
2047
- re-enters `in_progress`, and the `--reason` line in `journal.md`. A resumed session
2048
- therefore knows how many attempts a step has had, which is the fact the retry budget
2049
- needs, and reconstructs the prompt from the plan and the analysis exactly as the first
2050
- attempt did.
2047
+ The prompt itself is **not** persisted: `keryx job` writes no `step.prompt` and no prompt size, so do not instruct a resuming session to read one. What *is* persisted is that the attempt happened — `metrics.steps[].retries`, incremented every time the step re-enters `in_progress`, and the `--reason` line in `journal.md`. A resumed session therefore knows how many attempts a step has had, which is the fact the retry budget needs, and reconstructs the prompt from the plan and the analysis exactly as the first attempt did.
2051
2048
 
2052
2049
  ---
2053
2050
 
@@ -546,10 +546,8 @@ second copy of a schema is how that happens.
546
546
  7. **DO** use `runInAction()` after every `await` in MobX actions.
547
547
  8. **DO** use conventional commit format when auto-commit is enabled. Reference only a supplied real issue number; omit the issue reference when absent.
548
548
  9. **DO** verify your work before reporting.
549
- 10. **DO** make `STATUS: <TOKEN>` the first line of your final message, and put no
550
- JSON in the response body. The full JSON result is the file Phase 6.1 writes
551
- and records. `parseChildResult` throws on any first line that is not a
552
- canonical STATUS token.
549
+ 10. **DO** make `STATUS: <TOKEN>` the first line of your final message, and put no JSON in the response body. The full JSON result is the file Phase 6.1 writes and records. `parseChildResult` throws on any first line that is not a canonical STATUS token.
550
+ 11. **DO** check a `Rule check flagged: <clause id> at <file>:<line> — fix it if it is a real violation.` line against the named clause as soon as it arrives — fix the flagged line if it's real, otherwise continue; never argue with or silently ignore it, and record a false flag as `edit-guard false flag: <clause id> — <why>` in `notes` (Phase 6.1) so `review.jev.edit_guard_threshold` can be tuned.
553
551
 
554
552
  ---
555
553
 
@@ -94,6 +94,29 @@ dispatch). A future engine-backed reviewer follows the same pattern: gate on
94
94
  its own opt-in and reachability, dispatch as a command, merge its `--json`
95
95
  output the same way.
96
96
 
97
+ ### Measured verdicts (flow 344 — a live benchmark on a large production React/MobX frontend)
98
+
99
+ Gating them on is still a project's own choice; these are RESULTS, not a change to the gates above.
100
+
101
+ | Reviewer | Verdict | Measured |
102
+ |---|---|---|
103
+ | `review-jev-risk` | **Off by default** — measured weaker than a strong model | Top-3 recall 21% vs. "largest diff first" 30%; Sonnet 5 alone: 44%. |
104
+ | `review-jev-contract` | **Off by default** — measured weaker than a strong model | Caught 12.5% of false PR-description claims vs. Sonnet 5's 67.5%. |
105
+ | `review-jev-rules` | **Not useful on top of a strong reviewer** | Dispatched as an EXTRA reviewer beside an already-strong reviewer: +0 findings. |
106
+ | `review-jev-scenarios` | Experimental — not measured | — |
107
+ | `review-jev-docs` | Experimental — not measured | — |
108
+ | `review-jev-comments` | Experimental — not measured | — |
109
+
110
+ By contrast, `keryx review ci-triage` (Step 0b, not a reviewer) and `keryx
111
+ review jev-select` (Step 5c, not a reviewer either) both have a measured case
112
+ FOR them: CI triage cut developer minutes per failure from 30 to 15.4 under an
113
+ explicit cost model (38% vs. 25% flaky/regression/infra accuracy against
114
+ Sonnet 5 reading the same log, p=0.035); reviewer *selection* is the
115
+ unmeasured lever this benchmark named as most promising, which is why
116
+ `jev-select` ships recall-first and fails open rather than waiting for a
117
+ measurement that has not run yet. Full numbers, methodology and the cost
118
+ model: `docs/docs/jev-in-review.md`.
119
+
97
120
  ## `jev-triage` — advisory annotations, not a reviewer (Step 9b)
98
121
 
99
122
  `review-jev-triage` (flow 340) is a DIFFERENT shape from every CLI-engine
@@ -32,12 +32,14 @@ unified report sorted by severity. It does not perform any review logic itself.
32
32
  ```
33
33
  Review Orchestrator Progress:
34
34
  - [ ] Step 0: On a PR target, collect external comments — `keryx review comments collect`
35
+ - [ ] Step 0b: On a PR target whose checks are red, triage each failed run with `keryx review ci-triage --run <id>` (opt-in `review.jev.ci_triage`) — see "CI Triage on Red Checks"
35
36
  - [ ] Step 1: Build Review Context Pack — PR metadata AND the PR's own description, scope, rules, context_doc summary, accepted memory, and the cross-repo contracts the diff consumes
36
37
  - [ ] Step 2: Detect review mode (diff mode vs. path mode)
37
38
  - [ ] Step 3: Build the bounded scope with `keryx review scope` — never by hand
38
39
  - [ ] Step 3b: On a deep round, compute scope B with `keryx review blast-radius` — never by browsing — and KEEP the `--json` file; `review ingest --blast-radius <file>` is refused without it
39
40
  - [ ] Step 4: Parse flags / auto-detect domain from scope
40
41
  - [ ] Step 5: Ask user to confirm optional convention reviewers (legacy/profile reviewers are flag-only, never prompted)
42
+ - [ ] Step 5c: When `review.jev.select` is on, run `keryx review jev-select` over the finalized candidate set and drop its `skip` decisions from Wave A/B — see "Reviewer selection with Jev"
41
43
  - [ ] Step 6: Plan sub-agent dispatch and token budgets, and compute each dispatch's model with `keryx review tier` — never by hand
42
44
  - [ ] Step 7: Stage 1 gate - spec compliance check (if issue/task provided)
43
45
  - [ ] Step 8: Dispatch selected reviewers in PARALLEL with reviewer-input schema
@@ -411,6 +413,14 @@ The rule is about the other pull request:
411
413
 
412
414
  ---
413
415
 
416
+ ## CI Triage on Red Checks (Step 0b)
417
+
418
+ Run once per round, on a PR target whose checks are red, before Step 1: for each failed check run, `keryx review ci-triage --run <id>` (flow 306/307) — an existing keryx command, not something this skill re-implements. Gate it exactly the way the command gates itself: skip it — recorded in the report, never silently absent — when `review.jev.ci_triage` is not `true` in `.metaproject/tasks.config.json`, or no Jev/OpenRouter credential is resolvable; either means the command refuses before any read or network call.
419
+
420
+ Read each run's verdict (`flaky` | `regression` | `infra`) into the report: `flaky` suggests a rerun rather than a finding; `regression` means investigate before trusting this round's other findings, since a broken build can hide or mimic a real defect; `infra` is noted and the round continues. Advisory only — a verdict never gates dispatch and is never itself a finding.
421
+
422
+ ---
423
+
414
424
  ## Everything written to GitHub is brief
415
425
 
416
426
  One rule, applied to every outward surface: **PR bodies, PR comments, review
@@ -663,6 +673,8 @@ A **fix round** is any review of work produced to answer earlier findings. Set
663
673
  `is_fix_round: true` on every reviewer input, and populate `prior_findings` with
664
674
  the earlier findings and the disposition the fix claimed for each.
665
675
 
676
+ **The Jev edit guard is a FIX-phase tool, not a review-round tool.** `keryx review jev-edit-guard` (a separate feature) is the recommended Jev step during the FIX phase itself — run by the author's agent as it applies fixes, before this round re-reviews them. This skill never runs it; it is not part of review-orchestrator's own dispatch.
677
+
666
678
  **Nothing refuses a dispatch that omits them.** `reviewer-input.schema.json`
667
679
  states the rule and no production TypeScript loads that schema; reviewer
668
680
  dispatch is an action the host agent takes, not a `keryx` invocation, so there
@@ -891,8 +903,6 @@ nothing moved. The final round recomputes whatever the file set did — otherwis
891
903
  fix introduced in round 3 gets no regression check at all, and the round that
892
904
  certifies the flow is the one that checked the least.
893
905
 
894
- ---
895
-
896
906
  ### Path Mode
897
907
 
898
908
  When a path or target is named, collect the candidate files:
@@ -918,8 +928,6 @@ and therefore no context window; the drop list is recorded exactly the same way.
918
928
 
919
929
  **Reviewer behavior in path mode:** reviewers check the entire file content — not just added lines. All findings apply to the current state of the code, not only to changes.
920
930
 
921
- ---
922
-
923
931
  ### Auto-detection of Reviewers (both modes)
924
932
 
925
933
  When no flag is provided, infer reviewers from the collected file list:
@@ -1069,6 +1077,10 @@ If the user does not answer and the review is part of an automated `job-orchestr
1069
1077
  use the job setting `convention_reviewers` (default: `"ask"`; if still unresolved, include all
1070
1078
  detected reviewers and record that choice in the review scope).
1071
1079
 
1080
+ ### Reviewer selection with Jev (`jev-select`) — advisory, before dispatch (Step 5c)
1081
+
1082
+ When `review.jev.select` is on, before Wave A/B dispatch: run `keryx review jev-select (--diff <ref>|--pr <n>) --json` over the finalized candidate set (bundled + project reviewers, after every filter above) and drop every reviewer whose `decision` is `skip` from Wave A/B — **never** the Wave A core safety set (`review-logic`, `review-architecture`, `review-security-code`, `review-highload` when selected), which `jev-select` itself never marks `skip`. Record every decision in the report's scope section as `skipped by Jev selection (advisory)`, naming the probability and reason — this lever is UNMEASURED (unlike every CLI-engine reviewer below), so its skips must stay visible enough for a later round to check whether the skipped reviewer's domain surfaced a real finding anyway. It fails open — keeps every candidate — on its own opt-in being off, a missing credential, or any error; never treat a `jev-select` failure as a reason to skip a reviewer.
1083
+
1072
1084
  ---
1073
1085
 
1074
1086
  ## Legacy/Profile Reviewer Auto-Detection
@@ -1137,8 +1149,6 @@ Multiple flags may be combined: `review --backend --security` dispatches `review
1137
1149
  This table applies once this skill is running; reaching it is a separate question. The router strips `--`, so `review --style` is the same phrase as `review-style`'s own `style review` trigger and goes straight there — the same destination this table names, and likewise for `--architecture`, `--security` and `--performance`. Only `--all`, `--project-conventions` and `--legacy-profiles` name this orchestrator, which is why they are its triggers.
1138
1150
  `--frontend` and `--backend` are the exception: this table fans each out to three reviewers, but a bare `review --frontend` reaches `review-frontend` alone, because `review frontend` and `frontend review` are one phrase to the router and that phrase is the specialist's — two skills may not share a trigger token set (`src/gdskills/catalog-single-source.test.ts`). Ask by name, or use `review --all`, when you want the three-reviewer fan-out; `docs/skills/rejected-skill-changes.md` records the alternatives that were measured and rejected.
1139
1151
 
1140
- ---
1141
-
1142
1152
  ## Stage 1 Gate — Spec Compliance
1143
1153
 
1144
1154
  **Run this FIRST, before dispatching quality reviewers, whenever the change has a
@@ -1178,7 +1188,7 @@ whoever reads the merge commit a year later reads the body. When `review.jev.con
1178
1188
  Dispatch selected reviewers in parallel when independent. Use waves when token budget is tight or when one reviewer needs another result:
1179
1189
 
1180
1190
  1. Wave A - core correctness/risk reviewers: logic, architecture, security/highload when selected.
1181
- 2. Wave B - domain reviewers: frontend/backend/testing/convention reviewers filtered to relevant files. `review-jev-rules` (flow 330), `review-jev-risk`/`review-jev-scenarios` (flow 332), `review-jev-docs`/`review-jev-comments` (flow 333), `review-jev-contract` (flow 335) also run here, CLI-engine not sub-agent, `"engine": "jev"` in `keryx review reviewers --json`, gated on their own opt-in and a resolvable Jev/OpenRouter credential — `SKILL.detail.md` § "CLI-engine reviewers".
1191
+ 2. Wave B - domain reviewers: frontend/backend/testing/convention reviewers filtered to relevant files. `review-jev-rules` (flow 330), `review-jev-risk`/`review-jev-scenarios` (flow 332), `review-jev-docs`/`review-jev-comments` (flow 333), `review-jev-contract` (flow 335) also run here, CLI-engine not sub-agent, `"engine": "jev"` in `keryx review reviewers --json`, gated on their own opt-in and a resolvable Jev/OpenRouter credential — measured verdicts per reviewer (keep off by default, experimental, etc.) in `SKILL.detail.md` § "CLI-engine reviewers".
1182
1192
  3. Wave C - **verification**: `review-verifier` over the consolidated findings, when blockers/majors
1183
1193
  exist, `--verify` is set, or the PR is high-risk. See below.
1184
1194
 
@@ -1333,8 +1343,6 @@ Each reviewer must return a `REVIEW_RESULT` object matching `.metaproject/skills
1333
1343
  | Shared flow/graph abstraction contracts | NO | `review-flow-graph` |
1334
1344
  | Legacy/profile review profiles | NO | `code-ai-review`, `code-learned-review`, `code-style-review`, `code-mobx-store-review` |
1335
1345
 
1336
- ---
1337
-
1338
1346
  ## Sub-Agent Report Quality Gate
1339
1347
 
1340
1348
  Before consolidation, validate every reviewer result:
@@ -1346,8 +1354,6 @@ Before consolidation, validate every reviewer result:
1346
1354
  - `NEEDS_CONTEXT` triggers one targeted context refill. If still unresolved, keep it as an explicit open question, not as a blocker.
1347
1355
  - If a reviewer exceeds `max_findings`, keep blockers/majors first and summarize lower severity findings.
1348
1356
 
1349
- ---
1350
-
1351
1357
  ## Severity (canonical)
1352
1358
 
1353
1359
  **This is the only severity rubric in the review domain.** Reviewers do not carry
@@ -1445,8 +1451,6 @@ inventing a fifth level to express it would put us back where we started.
1445
1451
  `review-security-code` carries a fourth — every security finding states its attack
1446
1452
  vector — which does not generalise and stays there.
1447
1453
 
1448
- ---
1449
-
1450
1454
  ## Finding Format
1451
1455
 
1452
1456
  ### Class scope — required for `blocker` and `major`
@@ -1530,8 +1534,6 @@ All findings from all sub-reviewers must be normalized to this format before con
1530
1534
 
1531
1535
  Severity ordering for sort: `blocker` > `major` > `minor` > `info`.
1532
1536
 
1533
- ---
1534
-
1535
1537
  ### Model Metadata Rules
1536
1538
 
1537
1539
  `adaptive` is a model-assignment outcome recorded when `keryx review tier` printed `inherit: true` and the host picked the model for the tier, not a model name. Never render it as `model: adaptive` or as the PR comment `Model` value.
@@ -1544,8 +1546,6 @@ When writing review report metadata or a PR comment:
1544
1546
  5. If the dispatch's `model` block carried `inherit: true`, write `Model assignment: adaptive` and the model the host actually dispatched on for that tier (or `unknown`).
1545
1547
  6. If the actual model is unknown, write `unknown`; do not substitute `adaptive` or `inherit`.
1546
1548
 
1547
- ---
1548
-
1549
1549
  ## Output Contract
1550
1550
 
1551
1551
  ```
@@ -0,0 +1,3 @@
1
+ {
2
+ "agents": []
3
+ }