@mrciphersmith/keryx 0.2.72 → 0.2.74

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 (144) hide show
  1. package/dist/cli.js +33409 -32626
  2. package/package.json +2 -2
  3. package/src/gdskills/bundled/rules/core/gproject-contracts.mdc +1 -1
  4. package/src/gdskills/bundled/rules/core/jobs-documentation.mdc +1 -1
  5. package/src/gdskills/bundled/rules/core/subagent-context-construction.md +1 -1
  6. package/src/gdskills/bundled/skills/core/reviewer-skill-creator/SKILL.md +214 -0
  7. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.codex.md +326 -20
  8. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.cursor.md +320 -22
  9. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.opencode.md +326 -12
  10. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.zed.md +333 -9
  11. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.codex.md +92 -4
  12. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.cursor.md +92 -4
  13. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.opencode.md +92 -4
  14. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.zed.md +92 -4
  15. package/src/gdskills/bundled/skills/orchestration/context-collector/orchestrator-prompt.md +1 -1
  16. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.codex.md +154 -1098
  17. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.cursor.md +154 -1098
  18. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.opencode.md +154 -1098
  19. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.zed.md +154 -1098
  20. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/orchestrator-prompt.md +1 -1
  21. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.codex.md +101 -41
  22. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.cursor.md +101 -41
  23. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +48 -1
  24. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/input-contract.schema.json +70 -4
  25. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.codex.md +115 -49
  26. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.cursor.md +115 -49
  27. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.opencode.md +115 -49
  28. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.zed.md +115 -49
  29. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/orchestrator-prompt.md +1 -1
  30. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.codex.md +15 -6
  31. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.cursor.md +15 -6
  32. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.opencode.md +15 -6
  33. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.zed.md +15 -6
  34. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.codex.md +1 -1
  35. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.cursor.md +1 -1
  36. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +1 -1
  37. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.opencode.md +1 -1
  38. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.zed.md +1 -1
  39. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.codex.md +300 -55
  40. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.cursor.md +300 -55
  41. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +120 -37
  42. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.opencode.md +300 -55
  43. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.zed.md +300 -55
  44. package/src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json +56 -14
  45. package/src/gdskills/bundled/skills/orchestration/task-implementer/orchestrator-prompt.md +50 -23
  46. package/src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json +6 -2
  47. package/src/gdskills/bundled/skills/orchestration/task-implementer/task-request.template.md +18 -12
  48. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.codex.md +1 -1
  49. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.cursor.md +1 -1
  50. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.codex.md +169 -10
  51. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.cursor.md +169 -10
  52. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.md +1 -1
  53. package/src/gdskills/bundled/skills/planning/interview/SKILL.codex.md +7 -1
  54. package/src/gdskills/bundled/skills/planning/interview/SKILL.cursor.md +7 -1
  55. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.codex.md +7 -1
  56. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.cursor.md +7 -1
  57. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.codex.md +216 -10
  58. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.cursor.md +216 -10
  59. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.md +1 -1
  60. package/src/gdskills/bundled/skills/planning/planner/SKILL.codex.md +169 -10
  61. package/src/gdskills/bundled/skills/planning/planner/SKILL.cursor.md +169 -10
  62. package/src/gdskills/bundled/skills/planning/planner/SKILL.md +1 -1
  63. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.codex.md +2 -2
  64. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.cursor.md +2 -2
  65. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.opencode.md +2 -2
  66. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.zed.md +2 -2
  67. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.codex.md +134 -10
  68. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.cursor.md +134 -10
  69. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.md +1 -1
  70. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.codex.md +146 -10
  71. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.cursor.md +146 -10
  72. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.md +1 -1
  73. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.codex.md +211 -10
  74. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.cursor.md +211 -10
  75. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.md +1 -1
  76. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.codex.md +162 -10
  77. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.cursor.md +162 -10
  78. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.md +1 -1
  79. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.codex.md +1 -1
  80. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.cursor.md +1 -1
  81. package/src/gdskills/bundled/skills/platform/hookify/SKILL.codex.md +1 -1
  82. package/src/gdskills/bundled/skills/platform/hookify/SKILL.cursor.md +1 -1
  83. package/src/gdskills/bundled/skills/quality/changelog/SKILL.codex.md +1 -1
  84. package/src/gdskills/bundled/skills/quality/changelog/SKILL.cursor.md +1 -1
  85. package/src/gdskills/bundled/skills/quality/commit/SKILL.codex.md +1 -1
  86. package/src/gdskills/bundled/skills/quality/commit/SKILL.cursor.md +1 -1
  87. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.codex.md +1 -1
  88. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.cursor.md +1 -1
  89. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.codex.md +1 -1
  90. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.cursor.md +1 -1
  91. package/src/gdskills/bundled/skills/quality/deploy/SKILL.codex.md +1 -1
  92. package/src/gdskills/bundled/skills/quality/deploy/SKILL.cursor.md +1 -1
  93. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.codex.md +1 -1
  94. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.cursor.md +1 -1
  95. package/src/gdskills/bundled/skills/quality/pr/SKILL.codex.md +1 -1
  96. package/src/gdskills/bundled/skills/quality/pr/SKILL.cursor.md +1 -1
  97. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.codex.md +15 -1
  98. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.cursor.md +248 -165
  99. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.opencode.md +15 -1
  100. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.zed.md +359 -19
  101. package/src/gdskills/bundled/skills/quality/push/SKILL.codex.md +1 -1
  102. package/src/gdskills/bundled/skills/quality/push/SKILL.cursor.md +1 -1
  103. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.codex.md +1 -1
  104. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.cursor.md +1 -1
  105. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.codex.md +1 -1
  106. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.cursor.md +1 -1
  107. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.codex.md +299 -24
  108. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.cursor.md +296 -31
  109. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.opencode.md +309 -18
  110. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.zed.md +312 -17
  111. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.codex.md +29 -30
  112. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.cursor.md +29 -30
  113. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.opencode.md +29 -30
  114. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.zed.md +29 -30
  115. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.codex.md +21 -30
  116. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.cursor.md +21 -30
  117. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.opencode.md +21 -30
  118. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.zed.md +21 -30
  119. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.codex.md +19 -23
  120. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.cursor.md +19 -23
  121. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.opencode.md +19 -23
  122. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.zed.md +19 -23
  123. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.codex.md +17 -24
  124. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.cursor.md +17 -24
  125. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.opencode.md +17 -24
  126. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.zed.md +17 -24
  127. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +33 -1
  128. package/src/gdskills/bundled/skills/review/review-layout/SKILL.md +217 -0
  129. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +26 -0
  130. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +320 -5
  131. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +644 -113
  132. package/src/gdskills/bundled/skills/review/review-pr-feedback/input-contract.schema.json +79 -0
  133. package/src/gdskills/bundled/skills/review/review-pr-feedback/output-contract.schema.json +375 -0
  134. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +111 -1
  135. package/src/gdskills/bundled/skills/review/review-verifier/SKILL.md +25 -1
  136. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.claude.md +0 -46
  137. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.claude.md +0 -94
  138. package/src/gdskills/bundled/skills/quality/changelog/SKILL.claude.md +0 -45
  139. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.claude.md +0 -40
  140. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.claude.md +0 -45
  141. package/src/gdskills/bundled/skills/quality/deploy/SKILL.claude.md +0 -42
  142. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.claude.md +0 -48
  143. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.claude.md +0 -40
  144. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.claude.md +0 -30
@@ -33,7 +33,7 @@ triggers:
33
33
  - "review --mobx-store"
34
34
  metadata:
35
35
  author: "MrCipherSmith"
36
- version: "1.8.0"
36
+ version: "1.9.0"
37
37
  category: "review"
38
38
  compatible_harnesses: "cursor,codex,zed,opencode,claude"
39
39
  license: "MIT"
@@ -66,7 +66,7 @@ Review Orchestrator Progress:
66
66
  - [ ] Step 11: Sort by severity, deduplicate, emit unified report
67
67
  - [ ] Step 12: Emit the machine-readable `keryx:findings` block alongside the report
68
68
  - [ ] Step 13: Report the stage counts: dropped by pre-filter, refuted by the verifier, retained
69
- - [ ] Step 14: AFTER THE FINAL ROUND ONLY — answer every external comment once, `keryx review comments reply --final`
69
+ - [ ] Step 14: AFTER THE FINAL ROUND ONLY — answer every external comment once, `keryx review comments reply --final` — never against a pull request the dispatch named as the caller's
70
70
  ```
71
71
 
72
72
  Step 0 runs on **every** round. Step 14 runs **once**, after the last one. They are
@@ -394,6 +394,41 @@ problem, mark its outcome `escalate: true`: it leaves the reply queue, is report
394
394
  to the operator immediately, and the command exits non-zero. Answering a blocking
395
395
  question at the end answers the wrong question late.
396
396
 
397
+ ### A round never answers a pull request another skill is answering
398
+
399
+ `review-pr-feedback` is the entry point for the other direction of this pipe: a
400
+ human or a bot has already reviewed pull request `#A`, and someone wants those
401
+ comments interpreted, checked against the code, fixed and answered. Under its
402
+ `--fix` mode it dispatches `flow-orchestrator`, which opens a **second** pull
403
+ request `#B` carrying the fix, based on `#A`'s own head branch, and dispatches
404
+ **this** orchestrator on every round against `#B`.
405
+
406
+ `#B` is its own conversation. Collect and reply on it exactly as always: someone
407
+ reviewing the fix deserves an answer from the run that made the fix, and its
408
+ record is filed under `#B`'s own number, so nothing about `#A` is touched.
409
+
410
+ The rule is about the other pull request:
411
+
412
+ - **Never run a reply pass against a pull request the dispatch named as the
413
+ caller's.** When `constraints` says the caller owns the reply for `#A` — or
414
+ the target resolves onto a pull request another skill declared — collect if the
415
+ round needs the record and stop there. `review-pr-feedback` answers `#A` once,
416
+ after the merge, from the outcomes its own verdicts produced.
417
+
418
+ The harm is not a duplicate. `collectPrComments` skips a comment whose record
419
+ carries a `reply_url` as `already-handled`, rescuing it only when somebody else
420
+ posts later in the thread — so a round that answered mid-loop writes that record
421
+ FIRST, and the post-merge reply citing the merge SHA is then skipped as already
422
+ answered. The reviewer keeps the interim answer, which by then has stopped being
423
+ true, and `replies.posted` counts only what went out. A suppressed correction is
424
+ worse than a duplicate, because nothing shows it is missing.
425
+ - **Absent such a constraint this orchestrator owns the reply**, as it always
426
+ has. A top-level review of a pull request is the normal case; a caller holding
427
+ the conversation is the exception, and the exception declares itself.
428
+ - The reply is the only thing that moves. Collection, severity classification,
429
+ the refusal to let the verifier refute an external comment, and the cap
430
+ exemption are unchanged in both shapes.
431
+
397
432
  ---
398
433
 
399
434
  ## Everything written to GitHub is brief
@@ -427,12 +462,65 @@ Required content:
427
462
  - Git/PR metadata: repo, branch, base, head, merge-base, PR number/URL when available.
428
463
  - Scope summary: changed files grouped by domain, high-risk files, generated/ignored files.
429
464
  - Requirements: issue URL, linked task docs, acceptance criteria extracted from `context_doc` when available.
465
+ - **The PR's own description**, fetched not assumed: `gh pr view <n> --json title,body`. See below.
466
+ - **Cross-repo contracts the diff depends on**, each pinned to the SHA you read it at. See below.
430
467
  - Rules: matched repository rules and convention docs by path.
431
468
  - **Memory: accepted project memory intersecting the changed paths.** See below — this step is required, not best-effort.
432
469
  - Decisions: why each reviewer was selected or skipped.
433
470
  - Token policy: effective budget, truncation decisions, files summarized instead of fully inlined.
434
471
  - Legacy/profile reviewer availability and selection state.
435
472
 
473
+ ### The PR description is evidence, not decoration
474
+
475
+ Fetch the body into `review_context.pr.body` and hand it to every reviewer. It is
476
+ the author's own statement of what the change does, and it is checkable against
477
+ the diff.
478
+
479
+ **A description that promises an approach the diff does not take is a `minor`
480
+ finding** — file it, do not merely mention it. The failure this catches is
481
+ specific: over a multi-round review the code moves and the description does not,
482
+ so by round three the PR body describes an approach that was deleted in round one.
483
+ Whoever reads the merge commit a year later reads the description, not the rounds.
484
+
485
+ It is `minor` and not `major` because nothing at runtime is wrong. It is a finding
486
+ and not a pleasantry because unfiled housekeeping is raised again every round and
487
+ fixed in none — three consecutive rounds of "still worth rewriting" is the
488
+ recorded outcome of leaving it out of the findings array.
489
+
490
+ Same class, same severity: an approach that depends on another repository's change
491
+ being deployed first, with no deploy note saying so.
492
+
493
+ ### Cross-repo contracts are read, not assumed
494
+
495
+ When the diff consumes a contract owned by another service — a payload shape, a
496
+ status enum, a timeout, a permission, a default — **read the producer** and pin
497
+ the SHA:
498
+
499
+ ```yaml
500
+ cross_repo:
501
+ - repo: vantage-backend
502
+ sha: f5219d5d4
503
+ reason: "DQ report payload: which halves are null vs 0"
504
+ facts:
505
+ - "sqlScore/schemaDriftScore stay null when the half is absent"
506
+ - "sqlWeightPercentage/schemaDriftWeightPercentage init to 0.0 and are set unconditionally"
507
+ ```
508
+
509
+ Put the facts in `review_context` so every reviewer shares one reading, and so a
510
+ later round can tell a contract that moved from a reviewer that misread it.
511
+
512
+ The rule that follows for reviewers, and that belongs in the dispatch prompt:
513
+
514
+ > **A claim about another service's behaviour, with no `file:line` at a pinned SHA
515
+ > behind it, is `info`.** Not `major`, however confident. The two failure modes are
516
+ > symmetric and both recorded: a finding asserted from the consuming side that the
517
+ > producer disproves, and a defect missed because the producer's actual default was
518
+ > assumed rather than read.
519
+
520
+ If the other repository is not available to you, say so in `cross_repo` and leave
521
+ the dependent findings at `info`. An unavailable producer is a result. Assuming
522
+ one is not.
523
+
436
524
  ### Memory (required)
437
525
 
438
526
  Run, once, per review:
@@ -534,9 +622,22 @@ Rules:
534
622
 
535
623
  A **fix round** is any review of work produced to answer earlier findings. Set
536
624
  `is_fix_round: true` on every reviewer input, and populate `prior_findings` with
537
- the earlier findings and the disposition the fix claimed for each — the schema
538
- rejects the dispatch otherwise. A reviewer that cannot see what the fix was
539
- answering cannot tell whether the fix is complete.
625
+ the earlier findings and the disposition the fix claimed for each.
626
+
627
+ **Nothing refuses a dispatch that omits them, and this file used to say
628
+ otherwise.** `reviewer-input.schema.json` states the rule and no production
629
+ TypeScript loads that schema; reviewer dispatch is an action the host agent
630
+ takes, not a `keryx` invocation, so there is no point at which a malformed
631
+ dispatch could be rejected. `reviewer-input` is also absent from the `CONTRACTS`
632
+ registry (`src/gdskills/contracts.ts`), so `keryx skills contracts validate`
633
+ cannot be pointed at it either. The sentence that stood here until flow 209 told
634
+ you the schema would reject a dispatch without `prior_findings`; it asserted an
635
+ enforcement that has never existed, which is the same class of claim this whole
636
+ package was written to delete.
637
+
638
+ So this is a requirement on you, unenforced, and the only evidence it was met is
639
+ the `prior_findings` array the reviewer actually receives. A reviewer that cannot
640
+ see what the fix was answering cannot tell whether the fix is complete.
540
641
 
541
642
  Two scope rules apply, and they exist because breaking them is what produced
542
643
  seven rounds on PR #215 and four on PR #216:
@@ -558,6 +659,62 @@ Recording the enumeration matters as much as doing it: a round that searched and
558
659
  found nothing is a different fact from a round that never searched, and only the
559
660
  recorded list distinguishes them.
560
661
 
662
+ #### Every prior finding leaves the round with a disposition
663
+
664
+ A fix round that reports only new findings is unreadable: the author cannot tell
665
+ which of their fixes landed. Close the loop explicitly — one line per prior
666
+ finding, in the report, before the new findings:
667
+
668
+ | Disposition | Meaning |
669
+ |---|---|
670
+ | `closed` | Checked against the code, not against the commit message, and the defect is gone |
671
+ | `open` | The fix does not reach the defect; say what is still true |
672
+ | `partial` | One site of the class was fixed and the enumeration named others |
673
+ | `regressed` | The fix removed this defect and introduced another — file the new one separately |
674
+ | `withdrawn` | The finding was wrong. See below |
675
+
676
+ **Check the code, not the commit message.** A commit titled *"report an abandoned
677
+ sync as abandoned"* is a claim; the disposition is whether the branch it renamed
678
+ is reachable and pinned. On a recorded round, two such commits asserted behaviour
679
+ on lines no test could reach.
680
+
681
+ #### A fix is a change, and changes get reviewed
682
+
683
+ The most expensive class in a multi-round review is **the defect the fix
684
+ introduced**. It is systematically under-found, for a structural reason: the fix
685
+ arrives framed as the answer to a finding, so it is read as an answer rather than
686
+ as new code. It is new code.
687
+
688
+ So scope A of a fix round includes the fix, reviewed on its own merits, and the
689
+ report carries its own section:
690
+
691
+ ```markdown
692
+ ## Regressions the fixes introduced
693
+ <[F-NNN] — the finding it was answering, and the new defect it created>
694
+ ```
695
+
696
+ Recorded shapes, all from fixes that correctly closed the finding they answered:
697
+ an early return added to stop a fall-through, which then skipped the work the
698
+ caller needed; a persistence call added to save expanded state, which then
699
+ persisted the broken state on the error path too. Both were closed correctly and
700
+ both shipped a new bug in the same commit.
701
+
702
+ #### Withdrawing your own earlier finding
703
+
704
+ A finding from a previous round that this round disproves is **withdrawn**,
705
+ explicitly, at the top of the report, with the evidence — before any new finding.
706
+
707
+ This is not a courtesy. An uncorrected wrong finding costs the author a fix they
708
+ did not need, and it stays in `prior_findings` steering later rounds. Withdrawal
709
+ is also the one self-correction this pipeline permits, and it is permitted because
710
+ it is asymmetric: it *deletes* a claim, so it cannot inflate the finding count,
711
+ which is the failure mode that removed the re-scoring pass from Wave C.
712
+
713
+ State what made the original claim wrong, in one sentence, and if the same
714
+ reasoning error has now happened twice in one review, say that too. A reviewer
715
+ that names its own recurring error is calibrating; one that quietly drops a
716
+ finding is hiding a result.
717
+
561
718
  ### Step 1: Determine Review Mode
562
719
 
563
720
  Before anything else, determine whether the request is **diff mode** or **path mode**:
@@ -753,6 +910,7 @@ If the repository has local convention docs such as `CLAUDE.md`, `AGENTS.md`,
753
910
  | `**/*.test.*`, `**/*.spec.*`, `**/*.integration.test.*`, `**/*.msw.ts`, `src/test/**`, `test/**`, `e2e/**` | `review-testing-practices` |
754
911
  | `src/core/**`, `core/**`, `shared/**`, `foundation/**` | `review-core-boundaries` |
755
912
  | `src/core/flow/**`, `src/graph/**`, `src/shared/flow/**` | `review-flow-graph` |
913
+ | A `.tsx`/`.jsx`/`.css`/`.scss` hunk that adds or changes a sizing or spacing utility on a rendered element — `w-*`, `min-w-*`, `max-w-*`, `flex-*`, `basis-*`, `grid-cols-*`, `truncate`, `line-clamp-*`, `overflow-*`, `p*`/`m*`/`gap-*` and their logical `ps-*`/`pe-*`/`ms-*`/`me-*` forms, or an inline `style` carrying a dimension | `review-layout` |
756
914
 
757
915
  These convention reviewers are additive: keep the generic reviewers selected by normal detection,
758
916
  then add the matching convention pass. Deduplicate reviewer names before dispatch.
@@ -784,6 +942,84 @@ reviewer wrongly skipped hides a real defect, and that asymmetry is not close.
784
942
  Record the exclusions with their reasons alongside the pre-filter drops. A
785
943
  reviewer silently absent from a report reads as "it had nothing to say".
786
944
 
945
+ ### Path gate — the second filter, same asymmetry
946
+
947
+ Stack scoping asks *does this repository have the thing*. The path gate asks *does
948
+ this diff*. A reviewer whose path triggers match **no file in scope A** is not
949
+ dispatched; it goes to `Skipped reviewers` with reason `no-matching-paths`.
950
+
951
+ This is worth its own step because `--all` is the common case and it is where the
952
+ waste is: a run of sixteen reviewers over a fourteen-file frontend diff dispatched
953
+ `review-core-boundaries` and `review-flow-graph` against a diff containing no
954
+ `src/core/**` file at all. Two agents, full prompt each, guaranteed empty.
955
+
956
+ Three bounds keep it from deleting coverage:
957
+
958
+ - **Only path-triggered reviewers.** A reviewer selected by an explicit flag, or
959
+ one whose scope is the whole change rather than a path set — `review-logic`,
960
+ `review-regression`, `review-verifier` — is never path-gated.
961
+ - **Scope A only.** Scope B is the blast radius; it is *supposed* to name files the
962
+ diff never touched.
963
+ - **Ambiguity includes.** If you cannot decide whether a path matches, dispatch.
964
+ Same asymmetry as stack scoping: a needless reviewer costs tokens, a missing one
965
+ costs a defect.
966
+
967
+ Record every gated reviewer with the trigger set that found nothing. "Skipped:
968
+ no matching paths" is a result the reader can check; an absent reviewer is not.
969
+
970
+ ### Project-local reviewers — ask, do not assume
971
+
972
+ The routing table below names the reviewers **keryx ships**. A project may also
973
+ define its own, and before this step existed they were invisible to every round:
974
+ a team could write a reviewer, register it, and watch nothing dispatch it.
975
+
976
+ So the reviewer set is asked for, not recited:
977
+
978
+ ```bash
979
+ keryx review reviewers --json
980
+ ```
981
+
982
+ It returns two halves. `bundled` is the installed gdskills review tree — the set
983
+ this project's install profile actually produced, which is not everything keryx
984
+ ships. `project` is every project-skill under module `review`, living at
985
+ `.metaproject/project-skills/review/<name>/` so that it sits beside
986
+ `.metaproject/skills/gdskills/review/<name>/` and needs no other marking.
987
+
988
+ **Dispatch the project half alongside the bundled one.** A project reviewer is a
989
+ reviewer: it returns `REVIEW_RESULT`, its findings merge with everyone else's,
990
+ it is bound by the canonical severity rubric and the shared laws, and it is
991
+ verified in Wave C like any other. It is not advisory and not a second-class
992
+ pass — a team that wrote down how it reviews has said something about this
993
+ codebase that no shipped reviewer knows.
994
+
995
+ Two things it does NOT get:
996
+
997
+ - **No exemption from the contract.** A project reviewer whose output does not
998
+ conform is handled by the Sub-Agent Report Quality Gate exactly as a bundled
999
+ one would be. Local authorship is not evidence.
1000
+ - **No self-verification.** The never-self-verify rule is about the actor, not
1001
+ the origin.
1002
+
1003
+ #### `drift` — the source moved, the reviewer did not
1004
+
1005
+ A project reviewer built from an external file — a rules file, a review profile,
1006
+ a conventions doc — records where it came from and the hash of that file at
1007
+ import. `keryx review reviewers` re-reads the source and reports:
1008
+
1009
+ | `drift` | Meaning | What to do this round |
1010
+ |---|---|---|
1011
+ | `none` | No external source; written here | Nothing |
1012
+ | `clean` | Source matches the import | Nothing |
1013
+ | `changed` | Source has moved on since import | Dispatch it, and say so in the report |
1014
+ | `missing` | Source can no longer be read | Dispatch it, and say so in the report |
1015
+
1016
+ **A drifted reviewer still runs.** It is a reviewer built from an older version
1017
+ of its source, which is a fact about provenance, not a defect in its findings —
1018
+ suppressing it would trade real coverage for tidiness. Record the drift in
1019
+ `review_context` and name it once in the report, so the next person knows the
1020
+ profile is due a re-read. Never file it as a finding against the code under
1021
+ review: it is a fact about the review, not about the diff.
1022
+
787
1023
  ### Convention Reviewer Confirmation
788
1024
 
789
1025
  When convention reviewers are auto-detected and the user did not explicitly pass
@@ -867,6 +1103,7 @@ Skipped reviewers:
867
1103
  | `--testing-practices` | `review-testing-practices` |
868
1104
  | `--core-boundaries` | `review-core-boundaries` |
869
1105
  | `--flow-graph` | `review-flow-graph` |
1106
+ | `--layout` | `review-layout` |
870
1107
  | `--all` | all reviewers above (including `review-clean-code`, `review-highload`, applicable legacy/profile reviewers, and project convention reviewers when local convention docs exist) |
871
1108
  | `--verify` | `review-verifier`, AFTER all others; checks the consolidated findings by running something. Delete-only. |
872
1109
  | (auto) | detected from diff file extensions — see Auto-detection table |
@@ -899,6 +1136,20 @@ Dispatch selected reviewers in parallel when independent. Use waves when token b
899
1136
  3. Wave C - **verification**: `review-verifier` over the consolidated findings, when blockers/majors
900
1137
  exist, `--verify` is set, or the PR is high-risk. See below.
901
1138
 
1139
+ **Execution belongs to both B and C, and they execute for opposite reasons.**
1140
+ Wave C runs a command to *decide the fate of a finding that exists*; it is
1141
+ delete-only and can produce nothing. Wave B runs commands to *make findings* —
1142
+ `review-testing-practices` deletes each gate the diff added and records whether
1143
+ the suite goes red, and `review-layout` measures rendered geometry in a real
1144
+ engine.
1145
+
1146
+ The consequence is directional and easy to get wrong: **a surviving mutation is
1147
+ not something Wave C can hand you.** If Wave B skips its mutation pass, that
1148
+ finding class is unreachable for the entire round, and no amount of verification
1149
+ downstream recovers it. When a testing reviewer returns without a mutation table,
1150
+ treat it the way you would treat a reviewer that returned without findings *and*
1151
+ without evidence: ask once, then record that the pass did not run.
1152
+
902
1153
  ### Wave C — verification, and what it replaced
903
1154
 
904
1155
  Wave C used to run `review-strict`: a meta-pass that re-read the consolidated
@@ -1165,6 +1416,42 @@ is a claim that the class has exactly one member — make it deliberately, becau
1165
1416
  `minor` and `info` may omit it: enumerating the class for every low-severity
1166
1417
  observation is theatre, not rigour.
1167
1418
 
1419
+ #### Negative enumeration — the empty set is also a class scope
1420
+
1421
+ Some of the strongest findings assert that something is **absent**: nothing clears
1422
+ this state, nothing reads this field, this prop can never fire, no test builds this
1423
+ shape. Those are claims about a set being empty, and an empty set is exactly as
1424
+ enumerable as a full one — the same `class_scope` machinery carries it.
1425
+
1426
+ ```yaml
1427
+ class_scope:
1428
+ sites: []
1429
+ enumeration_method: "all 5 clearSubmitExecutionState() call sites are onUnmount,
1430
+ setActiveControl, setActiveTemplate, submitActiveControl, resetActiveControlForm;
1431
+ none reachable from a check-section edit, and there is no reaction/autorun"
1432
+ ```
1433
+
1434
+ The `enumeration_method` is the whole finding here, so it carries more weight than
1435
+ usual: it must name the complete candidate set and why each member fails to apply.
1436
+ "I looked and did not find one" is not that. A search that returned nothing, with
1437
+ the query, is.
1438
+
1439
+ This form covers a class of defect nothing else in this pipeline reaches:
1440
+
1441
+ - **The inert change.** The diff adds a prop, a guard, a field or a branch that
1442
+ nothing can reach — a `disabled` prop on a component its parent unmounts instead
1443
+ of disabling; a field added to two type `Pick`s and never read; a `=== undefined`
1444
+ guard against a producer that never emits `undefined`. The diff looks like it
1445
+ does something and does nothing, and the reviewer that checks whether the change
1446
+ is *correct* passes it, because it is.
1447
+ - **The missing clear.** State is set on one path and no path unsets it.
1448
+ - **The unreachable branch.** A value the code handles that its producer cannot
1449
+ emit.
1450
+
1451
+ An inert change is `minor` when it is merely dead, and `major` when its deadness
1452
+ means the bug it was added to fix is still live — the second is the common case
1453
+ when the change was written to answer an earlier round's finding.
1454
+
1168
1455
  All findings from all sub-reviewers must be normalized to this format before consolidation:
1169
1456
 
1170
1457
  ```markdown
@@ -1259,10 +1546,38 @@ STATUS: DONE | DONE_WITH_CONCERNS
1259
1546
  ## Minor & Info
1260
1547
  <[F-NNN] findings with severity=minor or info>
1261
1548
 
1549
+ ## Checked and cleared
1550
+ <Required whenever a reviewer tested a hypothesis and it did not hold. One line
1551
+ each: the defect that was looked for, and the evidence that rules it out. Not a
1552
+ list of virtues — a list of hypotheses that died, so no later round spends a
1553
+ reviewer re-raising them.>
1554
+
1262
1555
  ## Positive Notes
1263
1556
  <Optional. Highlight things done well. Keep brief.>
1264
1557
  ```
1265
1558
 
1559
+ ### Why `Checked and cleared` is separate from `Positive Notes`
1560
+
1561
+ They read alike and do opposite work. "Both entry points read the score from the
1562
+ same report" is a virtue; it tells a later round nothing, because no round was
1563
+ going to claim otherwise. "The drift bar cannot contradict the drift badge —
1564
+ `schema-drift-table.ts:61` always seeds `ddl` and `distributed` is a primitive
1565
+ boolean that is always serialized, so a backend match implies a `ddlTextDiffers`
1566
+ match" is a **retired hypothesis**: it names the bug that was hunted and the fact
1567
+ that kills it.
1568
+
1569
+ The cost of omitting them is paid in rounds. A plausible-but-wrong finding that
1570
+ was investigated and dropped in round 1 is investigated again in round 2 by a
1571
+ different reviewer, and the author answers it twice. Writing the negative down
1572
+ once ends that loop; it is also the only artifact that distinguishes *checked and
1573
+ clean* from *never looked at*, which is the distinction an approving verdict rests
1574
+ on.
1575
+
1576
+ Entries come from the reviewers, not from you: a reviewer that dropped a candidate
1577
+ returns it with the evidence, and consolidation collects them. A reviewer that
1578
+ returns zero findings and zero cleared hypotheses has told you nothing about the
1579
+ code, and should be asked once what it examined.
1580
+
1266
1581
  ---
1267
1582
 
1268
1583
  ## Skill Learning Handoff