@mrciphersmith/keryx 0.2.75 → 0.2.77

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 (54) hide show
  1. package/README.md +15 -10
  2. package/dist/cli.js +11809 -9037
  3. package/dist/proxy-worker.js +12 -12
  4. package/package.json +1 -1
  5. package/src/gdgraph/build.ts +12 -0
  6. package/src/gdgraph/query.ts +51 -1
  7. package/src/gdgraph/types.ts +77 -0
  8. package/src/gdgraph/wiki-layer-no-git.test.ts +73 -0
  9. package/src/gdgraph/wiki-layer.test.ts +211 -0
  10. package/src/gdgraph/wiki-layer.ts +213 -0
  11. package/src/gdskills/bundled/rules/core/api-contracts.mdc +6 -4
  12. package/src/gdskills/bundled/rules/core/model-selection.mdc +4 -5
  13. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.codex.md +4 -38
  14. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.cursor.md +4 -38
  15. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.md +4 -38
  16. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.opencode.md +4 -38
  17. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.zed.md +4 -38
  18. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.codex.md +1 -3
  19. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.cursor.md +1 -3
  20. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.md +1 -3
  21. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.codex.md +35 -34
  22. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.cursor.md +35 -34
  23. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +35 -34
  24. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.opencode.md +35 -34
  25. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.zed.md +35 -34
  26. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/input-contract.schema.json +1 -1
  27. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.codex.md +2 -4
  28. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.cursor.md +2 -4
  29. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +2 -4
  30. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.opencode.md +2 -4
  31. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.zed.md +2 -4
  32. package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +10 -6
  33. package/src/gdskills/bundled/skills/planning/interview/SKILL.codex.md +1 -1
  34. package/src/gdskills/bundled/skills/planning/interview/SKILL.cursor.md +1 -1
  35. package/src/gdskills/bundled/skills/planning/interview/SKILL.md +1 -1
  36. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.codex.md +1 -1
  37. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.cursor.md +1 -1
  38. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +1 -1
  39. package/src/gdskills/bundled/skills/platform/agent-entrypoint-distiller/SKILL.md +4 -0
  40. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +1 -2
  41. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +2 -2
  42. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +1 -2
  43. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +4 -0
  44. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +4 -0
  45. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +4 -0
  46. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +1 -2
  47. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +108 -23
  48. package/src/gdskills/bundled/skills/review/review-orchestrator/review-context.schema.json +175 -0
  49. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +7 -0
  50. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +2 -3
  51. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +2 -3
  52. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +5 -0
  53. package/src/gdskills/bundled/skills/review/review-verifier/SKILL.md +1 -2
  54. package/src/gdskills/contracts/review-finding.schema.json +4 -0
@@ -534,10 +534,8 @@ second copy of a schema is how that happens.
534
534
  9. **DO** verify your work before reporting.
535
535
  10. **DO** make `STATUS: <TOKEN>` the first line of your final message, and put no
536
536
  JSON in the response body. The full JSON result is the file Phase 6.1 writes
537
- and records. (This rule used to say the opposite — "return the JSON result
538
- object as your final message" — which contradicted 6.2, `## Reporting
539
- Results`, and `parseChildResult`, the production function that throws on any
540
- first line that is not a canonical STATUS token.)
537
+ and records. `parseChildResult` throws on any first line that is not a
538
+ canonical STATUS token.
541
539
 
542
540
  ---
543
541
 
@@ -534,10 +534,8 @@ second copy of a schema is how that happens.
534
534
  9. **DO** verify your work before reporting.
535
535
  10. **DO** make `STATUS: <TOKEN>` the first line of your final message, and put no
536
536
  JSON in the response body. The full JSON result is the file Phase 6.1 writes
537
- and records. (This rule used to say the opposite — "return the JSON result
538
- object as your final message" — which contradicted 6.2, `## Reporting
539
- Results`, and `parseChildResult`, the production function that throws on any
540
- first line that is not a canonical STATUS token.)
537
+ and records. `parseChildResult` throws on any first line that is not a
538
+ canonical STATUS token.
541
539
 
542
540
  ---
543
541
 
@@ -3,13 +3,17 @@ name: autodoc-orchestrator
3
3
  description: >
4
4
  Autonomous reverse-engineering documentation pipeline — scans an existing codebase
5
5
  and produces comprehensive developer documentation without user involvement after initial setup.
6
- Use when: "autodoc", "generate docs for my project", "document this codebase",
7
- "reverse engineer documentation", "create project documentation from code",
8
- "сгенерируй документацию проекта", "задокументируй кодовую базу",
9
- "автодок", "autodoc".
10
- Trigger on: user provides a repo path, asks to document existing code, wants
11
- onboarding docs, API reference, or architecture overview generated automatically.
6
+ Use when the user provides a repo path, asks to document existing code, or wants
7
+ onboarding docs, an API reference, or an architecture overview generated automatically.
12
8
  NOT for: writing new PRDs or planning new features (use gproject-orchestrator).
9
+ triggers:
10
+ - "autodoc"
11
+ - "автодок"
12
+ - "document this codebase"
13
+ - "generate docs for my project"
14
+ - "reverse engineer documentation"
15
+ - "задокументируй кодовую базу"
16
+ - "сгенерируй документацию проекта"
13
17
  metadata:
14
18
  version: 1.0.0
15
19
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interview
3
- description: "Use before implementation, design, or migration when requirements are unclear and targeted clarifying questions are needed to gather precise context."
3
+ description: "Use to clarify implementation-specific ambiguities AFTER context has already been collected and the goal is known — the questions that sharpen a plan, not the ones that scope the request. This is the `implement`-intent interview job-orchestrator runs at 0.3. To pin down a vague request before any context is gathered, use `interviewer` instead."
4
4
  triggers:
5
5
  - "/interview"
6
6
  - "Interview"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interview
3
- description: "Use before implementation, design, or migration when requirements are unclear and targeted clarifying questions are needed to gather precise context."
3
+ description: "Use to clarify implementation-specific ambiguities AFTER context has already been collected and the goal is known — the questions that sharpen a plan, not the ones that scope the request. This is the `implement`-intent interview job-orchestrator runs at 0.3. To pin down a vague request before any context is gathered, use `interviewer` instead."
4
4
  triggers:
5
5
  - "/interview"
6
6
  - "Interview"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interview
3
- description: "Use before implementation, design, or migration when requirements are unclear and targeted clarifying questions are needed to gather precise context."
3
+ description: "Use to clarify implementation-specific ambiguities AFTER context has already been collected and the goal is known — the questions that sharpen a plan, not the ones that scope the request. This is the `implement`-intent interview job-orchestrator runs at 0.3. To pin down a vague request before any context is gathered, use `interviewer` instead."
4
4
  triggers:
5
5
  - "/interview"
6
6
  - "Interview"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interviewer
3
- description: "Use when requirements are ambiguous and precise clarification is needed before proceeding with a complex task."
3
+ description: "Use when a request is ambiguous and must be pinned down BEFORE any context is collected — the entry-point interview that turns a vague or expensive ask into a scoped brief. This is the `custom`-intent gate job-orchestrator runs at 0.1.5. For clarifying implementation specifics AFTER context is already collected, use `interview` instead."
4
4
  triggers:
5
5
  - "Interview me"
6
6
  - "Ask me questions"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interviewer
3
- description: "Use when requirements are ambiguous and precise clarification is needed before proceeding with a complex task."
3
+ description: "Use when a request is ambiguous and must be pinned down BEFORE any context is collected — the entry-point interview that turns a vague or expensive ask into a scoped brief. This is the `custom`-intent gate job-orchestrator runs at 0.1.5. For clarifying implementation specifics AFTER context is already collected, use `interview` instead."
4
4
  triggers:
5
5
  - "Interview me"
6
6
  - "Ask me questions"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: interviewer
3
- description: "Use when requirements are ambiguous and precise clarification is needed before proceeding with a complex task."
3
+ description: "Use when a request is ambiguous and must be pinned down BEFORE any context is collected — the entry-point interview that turns a vague or expensive ask into a scoped brief. This is the `custom`-intent gate job-orchestrator runs at 0.1.5. For clarifying implementation specifics AFTER context is already collected, use `interview` instead."
4
4
  triggers:
5
5
  - "Interview me"
6
6
  - "Ask me questions"
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: agent-entrypoint-distiller
3
3
  description: Use when the user asks to split, decompose, distill, or refactor a large AGENTS.md or CLAUDE.md into Metaproject rules and project-specific skills while keeping root entrypoints compact.
4
+ triggers:
5
+ - "distill AGENTS.md"
6
+ - "split CLAUDE.md"
7
+ - "разнеси CLAUDE.md по правилам"
4
8
  metadata:
5
9
  version: "1.0.0"
6
10
  category: platform
@@ -5,8 +5,7 @@ description: |
5
5
  Use when: reviewing code for architectural violations — layer violations, dependency direction
6
6
  mistakes, module boundary coupling, SOLID principle breaches, NestJS module/provider structure,
7
7
  React MVVM boundary violations, or MobX store layer misplacement.
8
- Triggered by: "review architecture", "check architecture", "architectural review",
9
- or dispatched by review-orchestrator with --architecture or --backend.
8
+ Dispatched by review-orchestrator with --architecture or --backend.
10
9
  NOT for: style/naming preferences, logic correctness bugs, or security vulnerabilities.
11
10
  triggers:
12
11
  - "review architecture"
@@ -3,8 +3,8 @@ name: review-backend
3
3
  model_tier: standard
4
4
  description: |
5
5
  Use when: reviewing NestJS backend changes — API design, service layer, DTO validation,
6
- database patterns, and TypeScript correctness. Covers "review backend", "backend review",
7
- "review API", "review NestJS", or dispatched by review-orchestrator with --backend flag.
6
+ database patterns, and TypeScript correctness. Dispatched by review-orchestrator
7
+ with the --backend flag.
8
8
  NOT for: frontend patterns, MobX, React components, general security vulnerabilities
9
9
  (use review-security-code for XSS/injection/auth-bypass), or performance profiling
10
10
  (use review-performance).
@@ -6,8 +6,7 @@ description: |
6
6
  function/class level — meaningful names, small functions, single level of abstraction,
7
7
  argument count, error handling, DRY, comment quality, and SOLID (SRP, OCP, LSP, ISP, DIP)
8
8
  as applied to individual classes and functions.
9
- Triggered by: "review clean code", "check clean code", "Uncle Bob review", "SOLID review",
10
- "review --clean-code", or dispatched by review-orchestrator.
9
+ Dispatched by review-orchestrator.
11
10
  NOT for: architectural layer violations (review-architecture), naming convention formatting
12
11
  (review-style), logic correctness bugs (review-logic), or security (review-security-code).
13
12
  triggers:
@@ -6,6 +6,10 @@ description: |
6
6
  direction, feature-boundary leakage, abstraction stability, composition,
7
7
  and blast-radius risks. Dispatched by review-orchestrator for
8
8
  --core-boundaries, --project-conventions, --all, or src/core/** changes.
9
+ triggers:
10
+ - "review core boundaries"
11
+ - "review --core-boundaries"
12
+ - dispatched by review-orchestrator
9
13
  metadata:
10
14
  author: "MrCipherSmith"
11
15
  version: "1.0.0"
@@ -7,6 +7,10 @@ description: |
7
7
  boundaries, selection lifecycle, and large-graph performance. Dispatched by
8
8
  review-orchestrator for --flow-graph, --project-conventions, --all, or
9
9
  src/core/flow/** / graph abstraction changes.
10
+ triggers:
11
+ - "review flow graph"
12
+ - "review --flow-graph"
13
+ - dispatched by review-orchestrator
10
14
  metadata:
11
15
  author: "MrCipherSmith"
12
16
  version: "1.0.0"
@@ -8,6 +8,10 @@ description: |
8
8
  styling tokens, Storybook expectations, and local tooling rules. Dispatched
9
9
  by review-orchestrator for --frontend-conventions, --project-conventions,
10
10
  --all, or frontend src/**/*.ts(x) changes when local convention docs exist.
11
+ triggers:
12
+ - "review frontend conventions"
13
+ - "review --frontend-conventions"
14
+ - dispatched by review-orchestrator
11
15
  metadata:
12
16
  author: "MrCipherSmith"
13
17
  version: "1.0.0"
@@ -6,8 +6,7 @@ description: |
6
6
  race conditions, connection pool exhaustion, cache invalidation, missing indexes,
7
7
  unbounded queues, missing backpressure, retry storms, idempotency gaps,
8
8
  hot-path blocking I/O, and distributed systems anti-patterns.
9
- Triggered by: "review highload", "review scalability", "highload review",
10
- "review concurrency", "review --highload", or dispatched by review-orchestrator.
9
+ Dispatched by review-orchestrator.
11
10
  NOT for: frontend re-render performance (review-performance), general N+1 queries
12
11
  (review-performance), clean code style (review-clean-code), or NestJS module structure
13
12
  (review-architecture).
@@ -52,7 +52,7 @@ unified report sorted by severity. It does not perform any review logic itself.
52
52
  ```
53
53
  Review Orchestrator Progress:
54
54
  - [ ] Step 0: On a PR target, collect external comments — `keryx review comments collect`
55
- - [ ] Step 1: Build Review Context Pack (PR metadata, scope, rules, context_doc summary)
55
+ - [ ] 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
56
56
  - [ ] Step 2: Detect review mode (diff mode vs. path mode)
57
57
  - [ ] Step 3: Build the bounded scope with `keryx review scope` — never by hand
58
58
  - [ ] 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
@@ -204,9 +204,8 @@ keryx review complete <review-id-or-path>
204
204
  [--finding <id> --disposition <state> --evidence <ref>]...
205
205
  ```
206
206
 
207
- **An unrecognised option is refused, not ignored.** A misspelling used to be
208
- accepted with exit 0, so `review complete --disposition ...` printed
209
- `status: closed` and wrote nothing at all.
207
+ **An unrecognised option is refused, not ignored** — a misspelled flag exits
208
+ non-zero rather than printing `status: closed` and writing nothing at all.
210
209
 
211
210
  `--verifications` takes what `review-verifier` returned. `--scope` takes the
212
211
  whole `--json` output of `keryx review scope`, so the package records what the
@@ -462,8 +461,8 @@ Required content:
462
461
  - Git/PR metadata: repo, branch, base, head, merge-base, PR number/URL when available.
463
462
  - Scope summary: changed files grouped by domain, high-risk files, generated/ignored files.
464
463
  - 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.
464
+ - **The PR's own description**, fetched not assumed: `gh pr view <n> --json title,body`, into the typed `pr.body`. See below.
465
+ - **Cross-repo contracts the diff depends on**, in the typed `cross_repo`: each pinned to the ref you read it at, and each recording whether the producer has merged. See below.
467
466
  - Rules: matched repository rules and convention docs by path.
468
467
  - **Memory: accepted project memory intersecting the changed paths.** See below — this step is required, not best-effort.
469
468
  - Decisions: why each reviewer was selected or skipped.
@@ -487,8 +486,17 @@ and not a pleasantry because unfiled housekeeping is raised again every round an
487
486
  fixed in none — three consecutive rounds of "still worth rewriting" is the
488
487
  recorded outcome of leaving it out of the findings array.
489
488
 
489
+ **The Stage 1 gate files it.** Handing the body to every reviewer is what makes
490
+ the body available; it is not what makes the comparison happen. A rule addressed
491
+ to everyone is owned by no one, and that is the state this finding sat in for
492
+ three rounds. The gate already holds the stated intent and the diff side by side,
493
+ so the comparison belongs there — see `## Stage 1 Gate — Spec Compliance`.
494
+
490
495
  Same class, same severity: an approach that depends on another repository's change
491
- being deployed first, with no deploy note saying so.
496
+ being deployed first, with no deploy note saying so. Note the boundary — that
497
+ `minor` is about the *description*. When the dependency is real and this change
498
+ can merge first, the blocker is filed against the call site instead; see
499
+ `### A producer that has not merged yet`.
492
500
 
493
501
  ### Cross-repo contracts are read, not assumed
494
502
 
@@ -499,15 +507,21 @@ the SHA:
499
507
  ```yaml
500
508
  cross_repo:
501
509
  - repo: vantage-backend
510
+ state: merged
502
511
  sha: f5219d5d4
512
+ merge_order: independent
503
513
  reason: "DQ report payload: which halves are null vs 0"
514
+ facts_pinned_round: 1
504
515
  facts:
505
516
  - "sqlScore/schemaDriftScore stay null when the half is absent"
506
517
  - "sqlWeightPercentage/schemaDriftWeightPercentage init to 0.0 and are set unconditionally"
507
518
  ```
508
519
 
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.
520
+ Put the facts in `review_context.cross_repo` so every reviewer shares one reading,
521
+ and so a later round can tell a contract that moved from a reviewer that misread
522
+ it. The shape is typed in `review-context.schema.json`: `repo`, `reason`, `facts`
523
+ and `state` are required, `state: merged` requires the `sha`, and `state: open`
524
+ requires the `pr`.
511
525
 
512
526
  The rule that follows for reviewers, and that belongs in the dispatch prompt:
513
527
 
@@ -517,9 +531,49 @@ The rule that follows for reviewers, and that belongs in the dispatch prompt:
517
531
  > producer disproves, and a defect missed because the producer's actual default was
518
532
  > assumed rather than read.
519
533
 
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.
534
+ If the other repository is not available to you, record it as
535
+ `state: unavailable` in `cross_repo` and leave the dependent findings at `info`.
536
+ An unavailable producer is a result. Assuming one is not.
537
+
538
+ A finding whose evidence lives in the producer sets `repo` on the finding itself.
539
+ `file` and `line` alone name a path in the repository under review, so without
540
+ `repo` a cross-repo claim cannot say where its evidence is — and the `info` rule
541
+ above then rests on nothing a later round can check.
542
+
543
+ ### A producer that has not merged yet
544
+
545
+ `state: merged` is the easy case: the contract is on the producer's base branch,
546
+ you pin the SHA, and it stays where you pinned it. A **parallel pull request** —
547
+ the backend change your change was written against, still open — is a different
548
+ object, and pinning it the same way is wrong in three separate ways.
549
+
550
+ **Pin the pull request, not just the commit.** An open branch gets rebased and
551
+ squashed. A SHA read from it today names a commit that will not exist after the
552
+ merge, so `state: open` requires `pr` and the SHA becomes a note about when you
553
+ read it rather than an address a later reader can follow.
554
+
555
+ **Merge order is a `blocker`, not a note.** A missing deploy note in the PR body
556
+ is `minor` — that is a documentation finding and it stays where it is. The
557
+ operational case is not that one: when an entry is `state: open` with
558
+ `merge_order: producer_first`, and this change can merge without the producer,
559
+ **production breaks the moment it does**. That is a `blocker` under the existing
560
+ enumeration, not a new shape — the consumer calls what is not there, or reads a
561
+ default the producer has not changed yet, which is shape 1 or shape 2 in
562
+ `### \`blocker\` — merge-blocking, and nothing else`. File it against the consuming
563
+ call site rather than the description, and write the fix as what it is: a merge
564
+ gate, a flag, or a fallback, never an edit to a diff that may be perfectly
565
+ correct. Scope it exactly — both facts have to be recorded, an open producer AND
566
+ a producer-first order, and no gate already holding the merge. A
567
+ `merge_order: unknown` is a question to resolve, not a blocker to file.
568
+
569
+ **Re-read an open producer every round.** `facts` pinned in round 1 are a
570
+ statement about a branch that is still being written; by round 3 the contract may
571
+ have changed under a finding that still cites it. On each round, re-read every
572
+ entry with `state: open` and set `revalidated_round`. An entry whose
573
+ `revalidated_round` is behind the current round has not been checked this round,
574
+ and findings resting on it drop to `info` until it is. This is the same discipline
575
+ `prior_findings` already imposes on the local diff, applied to the one input that
576
+ is most likely to have moved.
523
577
 
524
578
  ### Memory (required)
525
579
 
@@ -624,16 +678,12 @@ A **fix round** is any review of work produced to answer earlier findings. Set
624
678
  `is_fix_round: true` on every reviewer input, and populate `prior_findings` with
625
679
  the earlier findings and the disposition the fix claimed for each.
626
680
 
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.
681
+ **Nothing refuses a dispatch that omits them.** `reviewer-input.schema.json`
682
+ states the rule and no production TypeScript loads that schema; reviewer
683
+ dispatch is an action the host agent takes, not a `keryx` invocation, so there
684
+ is no point at which a malformed dispatch could be rejected. `reviewer-input` is
685
+ also absent from the `CONTRACTS` registry (`src/gdskills/contracts.ts`), so
686
+ `keryx skills contracts validate` cannot be pointed at it either.
637
687
 
638
688
  So this is a requirement on you, unenforced, and the only evidence it was met is
639
689
  the `prior_findings` array the reviewer actually receives. A reviewer that cannot
@@ -1117,7 +1167,8 @@ local frontend conventions reviewer.
1117
1167
 
1118
1168
  ## Stage 1 Gate — Spec Compliance
1119
1169
 
1120
- **Run this FIRST, before dispatching quality reviewers, when an `issue_url` or task doc is provided.**
1170
+ **Run this FIRST, before dispatching quality reviewers, whenever the change has a
1171
+ stated intent — an `issue_url`, a task doc, or a PR body.**
1121
1172
 
1122
1173
  1. Fetch issue or task requirements.
1123
1174
  2. Map changed files and functions to acceptance criteria.
@@ -1125,6 +1176,27 @@ local frontend conventions reviewer.
1125
1176
  4. If there are unimplemented criteria: emit them as `blocker` findings in the final report and note them in `## Blockers`.
1126
1177
  5. Continue dispatching the remaining reviewers regardless (spec gaps + quality issues both belong in the report).
1127
1178
 
1179
+ ### With no issue and no task doc, the PR body is the spec
1180
+
1181
+ A pull request with nothing linked is the common case, not the exception, and the
1182
+ gate used to skip entirely on it — which meant the only written statement of what
1183
+ the change was for went unchecked precisely when it was the only one there. When
1184
+ `issue_url` and `context_doc` are both absent, read `pr.body` as the spec and run
1185
+ steps 2-4 against it. Nothing at all to read — no issue, no task doc, an empty
1186
+ body — is itself the finding: `minor`, that the change states no intent.
1187
+
1188
+ ### This gate owns the description-vs-diff comparison
1189
+
1190
+ The `minor` for a description that promises an approach the diff does not take
1191
+ (see the Context Pack) is **filed here**. It was previously stated as a rule for
1192
+ "every reviewer" and owned by none, which is how it stayed a remark instead of a
1193
+ finding across three rounds. A domain reviewer reviews its domain; the one step
1194
+ that already holds intent and diff side by side is this one.
1195
+
1196
+ Run it on every round, not only the first. The drift the finding catches is
1197
+ created BY the rounds: the code moves to answer findings, the body does not, and
1198
+ whoever reads the merge commit a year later reads the body.
1199
+
1128
1200
  ---
1129
1201
 
1130
1202
  ## Dispatching Reviewers
@@ -1328,6 +1400,18 @@ Everything else is at most `major`. "This will definitely cause problems later"
1328
1400
  is not one of the four. Neither is "this violates the architecture", "this fails
1329
1401
  the linter", or "this is how the last outage started".
1330
1402
 
1403
+ **An unshipped dependency is shape 1 or shape 2, and the list stays closed.**
1404
+ When a producer is recorded `state: open` with `merge_order: producer_first` and
1405
+ nothing stops this change merging first, ask the enumeration's own question —
1406
+ what happens at runtime. The consumer calls what is not there (shape 1) or reads
1407
+ the default the producer has not changed yet (shape 2). That is why it is a
1408
+ `blocker` without a fifth shape being invented for it. Two things follow from
1409
+ its being an ordering fault rather than a coding one: file it against the
1410
+ consuming call site, and say in the fix that the remedy is a merge gate, a flag,
1411
+ or a fallback — never a change to the diff, which may be entirely correct. A
1412
+ missing deploy note with no recorded producer state behind it is not this; that
1413
+ is the `minor` in the Context Pack. See `### A producer that has not merged yet`.
1414
+
1331
1415
  ### `major` / `minor` / `info` — the boundary test
1332
1416
 
1333
1417
  Ask one question, and ask it of the **finding**, not of the code:
@@ -1459,6 +1543,7 @@ All findings from all sub-reviewers must be normalized to this format before con
1459
1543
 
1460
1544
  - **Severity**: blocker | major | minor | info
1461
1545
  - **File**: path/to/file.ts:line
1546
+ - **Repo**: producer repository — only when the evidence is not in the repository under review
1462
1547
  - **Problem**: what is wrong
1463
1548
  - **Why it matters**: impact on correctness / safety / maintainability / UX
1464
1549
  - **Fix**: concrete suggestion
@@ -23,6 +23,58 @@
23
23
  "object",
24
24
  "null"
25
25
  ],
26
+ "description": "The pull request under review, when there is one. `body` is the author's own statement of what the change does, and it is checkable against the diff — it is typed here rather than left to convention because the Context Pack prose told reviewers to read `pr.body` while the schema declared no such field, so nothing carried it and nothing could tell a body that was never fetched from one that was empty.",
27
+ "properties": {
28
+ "number": {
29
+ "type": [
30
+ "integer",
31
+ "null"
32
+ ]
33
+ },
34
+ "url": {
35
+ "type": [
36
+ "string",
37
+ "null"
38
+ ]
39
+ },
40
+ "title": {
41
+ "type": [
42
+ "string",
43
+ "null"
44
+ ]
45
+ },
46
+ "body": {
47
+ "type": [
48
+ "string",
49
+ "null"
50
+ ],
51
+ "description": "Fetched, not assumed: `gh pr view <n> --json title,body`. Null means the fetch did not happen or returned nothing; an empty string means the author wrote no description, which is a different fact and a reportable one."
52
+ },
53
+ "state": {
54
+ "type": [
55
+ "string",
56
+ "null"
57
+ ],
58
+ "enum": [
59
+ "open",
60
+ "merged",
61
+ "closed",
62
+ null
63
+ ]
64
+ },
65
+ "base": {
66
+ "type": [
67
+ "string",
68
+ "null"
69
+ ]
70
+ },
71
+ "head": {
72
+ "type": [
73
+ "string",
74
+ "null"
75
+ ]
76
+ }
77
+ },
26
78
  "additionalProperties": true
27
79
  },
28
80
  "scope": {
@@ -71,6 +123,129 @@
71
123
  "type": "string"
72
124
  }
73
125
  },
126
+ "cross_repo": {
127
+ "type": "array",
128
+ "description": "Contracts owned by another service that this diff consumes — a payload shape, a status enum, a timeout, a permission, a default. Each entry is one reading of the producer, shared by every reviewer, so that a later round can tell a contract that moved from a reviewer that misread it. An entry is a RECORD OF READING: an unavailable producer is a result and belongs here as `state: unavailable`, whereas an assumed one belongs nowhere.",
129
+ "items": {
130
+ "type": "object",
131
+ "required": [
132
+ "repo",
133
+ "reason",
134
+ "facts",
135
+ "state"
136
+ ],
137
+ "properties": {
138
+ "repo": {
139
+ "type": "string",
140
+ "minLength": 1
141
+ },
142
+ "reason": {
143
+ "type": "string",
144
+ "minLength": 1,
145
+ "description": "What this diff needs from the producer, in one line."
146
+ },
147
+ "facts": {
148
+ "type": "array",
149
+ "minItems": 1,
150
+ "items": {
151
+ "type": "string"
152
+ },
153
+ "description": "What the producer actually says, read at the pinned ref. A claim about another service's behaviour with no `file:line` behind it at a pinned ref is `info`, not `major`, however confident — both failure modes are recorded: a finding the producer disproves, and a defect missed because the producer's real default was assumed rather than read."
154
+ },
155
+ "state": {
156
+ "type": "string",
157
+ "enum": [
158
+ "merged",
159
+ "open",
160
+ "unavailable"
161
+ ],
162
+ "description": "Where the contract lives right now. `merged` is on the producer's own base branch and is pinned by `sha`. `open` is a parallel pull request that has not landed: its branch will be rebased or squashed, so a sha pinned today names a commit that will not exist after the merge, and the contract itself can still change. `unavailable` means the producer could not be read."
163
+ },
164
+ "sha": {
165
+ "type": [
166
+ "string",
167
+ "null"
168
+ ],
169
+ "description": "The commit the facts were read at. Required when `state` is `merged`."
170
+ },
171
+ "pr": {
172
+ "type": [
173
+ "string",
174
+ "null"
175
+ ],
176
+ "description": "The producer's pull request, when the contract is not merged yet."
177
+ },
178
+ "branch": {
179
+ "type": [
180
+ "string",
181
+ "null"
182
+ ]
183
+ },
184
+ "merge_order": {
185
+ "type": "string",
186
+ "enum": [
187
+ "producer_first",
188
+ "consumer_first",
189
+ "independent",
190
+ "unknown"
191
+ ],
192
+ "default": "unknown",
193
+ "description": "Which side has to ship first for production to stay correct. `producer_first` on a `state: open` entry is the case where merging THIS change first breaks production, and it is a blocker rather than the `minor` filed for a missing deploy note."
194
+ },
195
+ "facts_pinned_round": {
196
+ "type": [
197
+ "integer",
198
+ "null"
199
+ ],
200
+ "description": "The review round the facts were read in."
201
+ },
202
+ "revalidated_round": {
203
+ "type": [
204
+ "integer",
205
+ "null"
206
+ ],
207
+ "description": "The last round the producer was re-read. An entry with `state: open` that was pinned in round 1 and never revalidated is stale by round 3: a parallel pull request is precisely the thing that moves between rounds."
208
+ }
209
+ },
210
+ "allOf": [
211
+ {
212
+ "if": {
213
+ "properties": {
214
+ "state": {
215
+ "const": "merged"
216
+ }
217
+ },
218
+ "required": [
219
+ "state"
220
+ ]
221
+ },
222
+ "then": {
223
+ "required": [
224
+ "sha"
225
+ ]
226
+ }
227
+ },
228
+ {
229
+ "if": {
230
+ "properties": {
231
+ "state": {
232
+ "const": "open"
233
+ }
234
+ },
235
+ "required": [
236
+ "state"
237
+ ]
238
+ },
239
+ "then": {
240
+ "required": [
241
+ "pr"
242
+ ]
243
+ }
244
+ }
245
+ ],
246
+ "additionalProperties": true
247
+ }
248
+ },
74
249
  "memory": {
75
250
  "type": "object",
76
251
  "required": [
@@ -60,6 +60,13 @@
60
60
  "info"
61
61
  ]
62
62
  },
63
+ "repo": {
64
+ "type": [
65
+ "string",
66
+ "null"
67
+ ],
68
+ "description": "Which repository `file` and `line` are in. Null, the default, means the repository under review. A cross-repo claim names the producer here and pins the ref it was read at in `evidence`; without this field a finding about another service's behaviour could not say where its evidence lived, so the rule that such a claim is `info` unless it has a `file:line` at a pinned ref could not be checked by anything but the reviewer's word. Kept identical to src/gdskills/contracts/review-finding.schema.json, which is stricter (additionalProperties: false) and would reject a finding carrying `repo` if the property were declared only here."
69
+ },
63
70
  "file": {
64
71
  "type": [
65
72
  "string",
@@ -4,9 +4,8 @@ model_tier: standard
4
4
  description: |
5
5
  Use when: a developer has received PR review comments and wants to understand them,
6
6
  check whether they are still true of the code, act on them, or extract patterns
7
- from them. Covers "analyze PR comments", "review PR feedback", "what did reviewers
8
- say", "parse PR #N", "explain PR comments", and — with `--fix` — validating every
9
- comment, planning the fix, driving it to a merged state and answering each reviewer.
7
+ from them. With `--fix`, also validates every comment, plans the fix, drives it to
8
+ a merged state and answers each reviewer.
10
9
  NOT for: reviewing code directly — this skill reads human or bot PR feedback and
11
10
  makes it actionable. To review code, use the domain review skills.
12
11
  triggers: