@mrciphersmith/keryx 0.2.109 → 0.2.111

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.
package/dist/core.js CHANGED
@@ -23887,7 +23887,7 @@ async function createProjectSkill(projectRoot, options) {
23887
23887
  name: skillName,
23888
23888
  target: options.target,
23889
23889
  path: relativeSkillPath,
23890
- version: VERSION,
23890
+ version: options.version ?? VERSION,
23891
23891
  status: "active",
23892
23892
  updatedAt: new Date().toISOString()
23893
23893
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.109",
3
+ "version": "0.2.111",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -155,17 +155,33 @@ The rules `assignTier` applies, in the order it applies them:
155
155
  Floors are applied after downgrades, so "at least `deep`" means at least: a
156
156
  blast-radius round over a twelve-line diff is still a blast-radius round.
157
157
 
158
- The session's provider/model come from the selection `keryx shell` persisted, and
159
- the candidate set from live provider detection. A caller that already holds
160
- either passes `--session-provider`/`--session-model` and `--catalog` instead of
161
- paying for the lookup. **There is no `--tier` flag, and there will not be**:
162
- accepting a hand-written tier would put the arithmetic straight back in the
163
- caller's head.
164
-
165
- When nothing can be worked out — no persisted session, an unrankable catalogue,
166
- an unrankable session model — the block says `inherit: true` and the dispatch
167
- runs on the **caller's own model**. Exit status is still 0: a fallback is an
168
- answer, not a failure.
158
+ The session's provider/model come from the **caller**: `--session-provider`/
159
+ `--session-model`, else `KERYX_SESSION_PROVIDER`/`KERYX_SESSION_MODEL` exported by
160
+ the host (`keryx shell` exports its live session to every `shell_exec` command). The selection `keryx shell` persisted is read only with
161
+ `--from-shell-config`: it is whatever `keryx shell` was last pointed at, not the
162
+ session running the orchestrator, and as a silent default it pinned a `keryx
163
+ shell` model into dispatches authored from Claude Code. The candidate set comes
164
+ from live provider detection (`--catalog` to supply it). **There is no `--tier`
165
+ flag, and there will not be**: accepting a hand-written tier would put the
166
+ arithmetic straight back in the caller's head.
167
+
168
+ ## Adaptive: `inherit: true`
169
+
170
+ A model is named only when discovery assigned one **other than** the session's
171
+ (`tier_resolution: discovered`). In every other case — no session named, ranking
172
+ refused, or the tier resolving to the session's own model — the block carries the
173
+ tier and `inherit: true`, and the **host** resolves it against the models its own
174
+ dispatch tool offers:
175
+
176
+ | Tier | Host dispatches on |
177
+ |---|---|
178
+ | `standard` | its session model |
179
+ | `deep` | its most capable model class, else the session model |
180
+ | `light` | its lighter/faster model class, else the session model |
181
+
182
+ This is how the tier reaches runtimes keryx cannot enumerate (a Claude Code
183
+ `Agent`, a Codex subagent). `light` there is the tier the signals assigned, not a
184
+ fallback. Exit status is always 0.
169
185
 
170
186
  ## Recording the decision
171
187
 
@@ -201,5 +217,6 @@ recording them is one copy rather than four decisions.
201
217
  the resolution code.
202
218
  - Take the candidate set from runtime detection. Never from a literal list of
203
219
  what exists.
204
- - When the candidates cannot be ranked, keep the session model. Never substitute
205
- a cheaper one.
220
+ - When the candidates cannot be ranked, the block is adaptive (`inherit: true`).
221
+ The host never goes below its session model for `standard` or `deep`, and takes
222
+ a lighter class only for a `light` tier.
@@ -1349,7 +1349,7 @@ FOR iteration in [1, 2, 3]:
1349
1349
 
1350
1350
  AFTER THE LAST ROUND ONLY — answer every inbound PR comment, once:
1351
1351
  keryx review comments reply --repo <owner/repo> --pr <n> --outcomes <file> \
1352
- --sha <head-sha> --final [--flow-link <url>]
1352
+ --review <review-id> --sha <head-sha> --final [--flow-link <url>]
1353
1353
 
1354
1354
  IF still NEEDS_FIX after max iterations, or the stuck check broke the loop:
1355
1355
  Log "Unresolved after <N> iterations" with finding list, and say WHICH of the
@@ -189,7 +189,7 @@ If `blocker` or `major` findings exist:
189
189
 
190
190
  After the LAST round only:
191
191
  ```bash
192
- keryx review comments reply --repo <owner/repo> --pr <n> --outcomes <file> --sha <sha> --final
192
+ keryx review comments reply --repo <owner/repo> --pr <n> --outcomes <file> --review <review-id> --sha <sha> --final
193
193
  ```
194
194
 
195
195
  ### Step: REPORT — Generate Final Report
@@ -0,0 +1,45 @@
1
+ # Review Orchestrator — detail
2
+
3
+ Overflow reference for `review/review-orchestrator`, linked from its SKILL.md.
4
+ Read the section SKILL.md points you to; nothing here overrides SKILL.md.
5
+
6
+ ## Project-local reviewers
7
+
8
+ `keryx review reviewers --json` returns every project-skill under module
9
+ `review`. The routing tables in SKILL.md cannot name a project reviewer's
10
+ triggers, so each `project` entry carries its own. Use them; do not re-derive
11
+ them from the reviewer's prose.
12
+
13
+ ### Selecting project reviewers — the same two filters, from the inventory
14
+
15
+ | Field | Use |
16
+ |---|---|
17
+ | `flags` | A flag the user passed that is in this list selects the reviewer **explicitly** — it is then never path-gated, like any flag-selected reviewer. `--all` selects every project reviewer. |
18
+ | `paths` | Its path triggers for the **path gate**. No file in scope A matches → `Skipped reviewers`, reason `no-matching-paths`. |
19
+ | `pathsSource` | `metadata` (declared `metadata.paths`) or `description` (globs read out of its description). `none` means there is nothing to gate on: **dispatch it** — ambiguity includes. |
20
+ | `stackRequires` | Apply stack scoping exactly as for a bundled reviewer carrying `metadata.stack_requires`. |
21
+ | `unresolvedRules` | Rules it cites that the project does not have. Dispatch it anyway, tell it in the prompt which rules are absent, and name them once in the report with the fix (`keryx review import --from <overlay>` copies them). Never a finding against the code. |
22
+
23
+ A description saying another entry point dispatches it ("Dispatched by
24
+ vantage-review …") is its author's routing note, not a restriction: this
25
+ orchestrator dispatches it through the fields above.
26
+
27
+ ### `drift` — the source moved, the reviewer did not
28
+
29
+ A project reviewer built from an external file — a rules file, a review profile,
30
+ a conventions doc — records where it came from and the hash of that file at
31
+ import. `keryx review reviewers` re-reads the source and reports:
32
+
33
+ | `drift` | Meaning | What to do this round |
34
+ |---|---|---|
35
+ | `none` | No external source; written here | Nothing |
36
+ | `clean` | Source matches the import | Nothing |
37
+ | `changed` | Source has moved on since import | Dispatch it, and say so in the report |
38
+ | `missing` | Source can no longer be read | Dispatch it, and say so in the report |
39
+
40
+ **A drifted reviewer still runs.** It is a reviewer built from an older version
41
+ of its source, which is a fact about provenance, not a defect in its findings —
42
+ suppressing it would trade real coverage for tidiness. Record the drift in
43
+ `review_context` and name it once in the report, so the next person knows the
44
+ profile is due a re-read. Never file it as a finding against the code under
45
+ review: it is a fact about the review, not about the diff.
@@ -46,7 +46,7 @@ Review Orchestrator Progress:
46
46
  - [ ] Step 11: Sort by severity, deduplicate, emit unified report
47
47
  - [ ] Step 12: Emit the machine-readable `keryx:findings` block alongside the report
48
48
  - [ ] Step 13: Report the stage counts: dropped by pre-filter, refuted by the verifier, retained
49
- - [ ] 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
49
+ - [ ] Step 14: MANAGED rounds only (NEVER in `lightweight`, which is report-only), AFTER THE FINAL ROUND, on an OPEN pull request at the head you reviewed — answer every external comment once, `keryx review comments reply --final` — never against a pull request the dispatch named as the caller's
50
50
  ```
51
51
 
52
52
  Step 0 runs on **every** round. Step 14 runs **once**, after the last one. They are
@@ -66,12 +66,12 @@ Working it out in your head is exactly the mechanical step that rule moves into
66
66
  code — and it is the step that was documented as running for a whole release
67
67
  while nothing called it.
68
68
 
69
- The command names no model. It ranks whatever your provider reports at runtime
70
- and places the tiers relative to your own model; when ranking fails it still
71
- names the session's own provider and model as a fallback. Only when the session
72
- itself has no provider/model to name does it print `inherit: true` and exit 0,
73
- which means the dispatch runs on the session model. That is a correct answer,
74
- not a failure — never "fix" it by writing a model id into a dispatch.
69
+ It names a model only if you gave it your session (`--session-provider`/
70
+ `--session-model` or `KERYX_SESSION_*`) and discovery found another. Otherwise it prints
71
+ `inherit: true` with the tier — **adaptive**: pick your own runtime's model for
72
+ that tier (`standard` = your session model; `light`/`deep` = your runtime's
73
+ lighter/most capable class if its dispatch tool offers one, else the session
74
+ model). Never "fix" it by writing a model id into a dispatch.
75
75
 
76
76
  ---
77
77
 
@@ -236,7 +236,7 @@ what happened", and it is the single reason the precision figure cannot be read.
236
236
 
237
237
  Managed modes:
238
238
 
239
- - `lightweight`: report-only; no flow or managed review artifacts are created.
239
+ - `lightweight`: report-only; no flow or managed review artifacts are created, and nothing is posted — no `comments reply`.
240
240
  - `attach-review`: write under
241
241
  `.metaproject/flows/<flow-dir>/reviews/<review-id>/`.
242
242
  - `review-flow`: write under `.metaproject/reviews/<review-id>/`.
@@ -274,7 +274,7 @@ here.
274
274
  keryx review comments collect --repo <owner/repo> --pr <n> --sha <head-sha>
275
275
  [--self <login>] [--round <n>] [--out <findings.json>] [--json]
276
276
  keryx review comments reply --repo <owner/repo> --pr <n> --outcomes <file|->
277
- --sha <head-sha> --final [--dry-run]
277
+ --review <review-id> --sha <head-sha> --final [--dry-run]
278
278
  [--max-replies <n>] [--max-sentences <n>] [--max-chars <n>]
279
279
  [--flow-link <url>]
280
280
  ```
@@ -283,12 +283,11 @@ Add `--fixtures <dir>` to either to run the whole loop against JSON on disk —
283
283
  no token, no network, nothing posted. Use it to see what a reply pass would say
284
284
  before it says it.
285
285
 
286
- `--sha` is the commit you collected against, and it is required. The completion
287
- gate compares it to the pull request's head: a collection that ran before the
288
- comments arrived is **stale**, and a gate that could not tell the difference
289
- would pass a flow with unanswered reviewers on it while printing
290
- `0 outstanding`. A record with no SHA reads as "cannot be shown current", never
291
- as "fresh".
286
+ `--sha` is the pull request's **current head**, and it is required. `collect`
287
+ prints the PR's state and head and warns when they disagree; `reply` **refuses** a
288
+ closed or merged PR (`--allow-closed-pr` overrides), an unreadable one, and a `--sha`
289
+ that is not its head. The completion gate compares the recorded SHA as well; a
290
+ record with no SHA reads as "cannot be shown current", never as "fresh".
292
291
 
293
292
  ### What collection does, so you do not do it by hand
294
293
 
@@ -650,7 +649,7 @@ whether it is computed:
650
649
 
651
650
  Rules:
652
651
  - Never write a model id into a dispatch by hand — paste the `model` block `keryx review tier` printed.
653
- - When the session has no provider/model to name it prints `inherit: true` and exits 0; that means the dispatch runs on the session model. Record that as `model_assignment: unsupported`, not as a failure.
652
+ - `inherit: true` is the adaptive answer: dispatch on your runtime's model for the block's `tier` (Step 6). Record `model_assignment: adaptive` and the model you actually chose — not a failure.
654
653
  - With `model_strategy: ask`, present the model plan once before dispatch, then proceed with the computed model.
655
654
 
656
655
  ---
@@ -1035,25 +1034,14 @@ Two things it does NOT get:
1035
1034
  - **No self-verification.** The never-self-verify rule is about the actor, not
1036
1035
  the origin.
1037
1036
 
1038
- #### `drift` — the source moved, the reviewer did not
1039
-
1040
- A project reviewer built from an external file — a rules file, a review profile,
1041
- a conventions doc — records where it came from and the hash of that file at
1042
- import. `keryx review reviewers` re-reads the source and reports:
1043
-
1044
- | `drift` | Meaning | What to do this round |
1045
- |---|---|---|
1046
- | `none` | No external source; written here | Nothing |
1047
- | `clean` | Source matches the import | Nothing |
1048
- | `changed` | Source has moved on since import | Dispatch it, and say so in the report |
1049
- | `missing` | Source can no longer be read | Dispatch it, and say so in the report |
1050
-
1051
- **A drifted reviewer still runs.** It is a reviewer built from an older version
1052
- of its source, which is a fact about provenance, not a defect in its findings —
1053
- suppressing it would trade real coverage for tidiness. Record the drift in
1054
- `review_context` and name it once in the report, so the next person knows the
1055
- profile is due a re-read. Never file it as a finding against the code under
1056
- review: it is a fact about the review, not about the diff.
1037
+ **Select them with the fields the inventory returns, not by reading prose.**
1038
+ Each `project` entry carries `flags` (a passed flag selects it explicitly),
1039
+ `paths` + `pathsSource` (the path gate; `none` → dispatch), `stackRequires`
1040
+ (stack scoping), `unresolvedRules` (dispatch, name the missing rules once in the
1041
+ report) and `drift` (dispatch, name it once in the report). What each means and
1042
+ what to do with it: `SKILL.detail.md` beside this file, section "Project-local
1043
+ reviewers". A description saying another entry point dispatches it is its
1044
+ author's routing note, not a restriction.
1057
1045
 
1058
1046
  ### Convention Reviewer Confirmation
1059
1047
 
@@ -1545,15 +1533,15 @@ Severity ordering for sort: `blocker` > `major` > `minor` > `info`.
1545
1533
 
1546
1534
  ### Model Metadata Rules
1547
1535
 
1548
- `unsupported` is a model-assignment outcome recorded when `keryx review tier` has no session provider/model to name (it prints `inherit: true`), not a model name. Never render it as `model: unsupported` or as the PR comment `Model` value.
1536
+ `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.
1549
1537
 
1550
1538
  When writing review report metadata or a PR comment:
1551
1539
  1. Read `review_context.token_policy.model_plan`.
1552
1540
  2. Set `Model strategy` from `model_plan.strategy` (`ask` or `adaptive`).
1553
1541
  3. Set `Current model` from the first available value: `model_plan.current_model`, detected tool output, current runtime model shown by the platform, or `unknown`.
1554
1542
  4. Record the model actually assigned per reviewer — the `tier` and (`provider`+`model` or `inherit`) from the `model` block `keryx review tier` printed for that dispatch — rather than a fixed set of classes; include `complex_model`, `normal_model`, and `simple_model` too when `model_plan` reports them.
1555
- 5. If model assignment is unsupported (the dispatch's `model` block carried `inherit: true`), write `Model assignment: unsupported` and still write `Current model: <actual model or unknown>`.
1556
- 6. If the actual model is unknown, write `unknown`; do not substitute `unsupported` or `inherit`.
1543
+ 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`).
1544
+ 6. If the actual model is unknown, write `unknown`; do not substitute `adaptive` or `inherit`.
1557
1545
 
1558
1546
  ---
1559
1547
 
@@ -65,7 +65,7 @@ review-pr-feedback Progress:
65
65
  - [ ] Step 7: Explain each comment and name the concrete fix
66
66
  - [ ] Step 8: Build the fix plan — one item per class, ordered, each with an acceptance criterion
67
67
  - [ ] Step 9: --fix only — confirm, then dispatch `flow-orchestrator` with the plan as frozen AC
68
- - [ ] Step 10: --fix only — after the merge, answer every comment once: `keryx review comments reply --final`
68
+ - [ ] Step 10: --fix only — after the FIX merges into the reviewed PR's branch (the reviewed PR itself still OPEN, at its new head), answer every comment once: `keryx review comments reply --final --result <file>`
69
69
  - [ ] Step 11: Learning proposal for configured authors — propose, never apply
70
70
  ```
71
71
 
@@ -143,7 +143,7 @@
143
143
  }
144
144
  },
145
145
  "inherit": {
146
- "description": "Run this dispatch on the caller's own model. `keryx review tier` writes it — in place of `provider`/`model`, never alongside them — when the environment could not be worked out: no persisted session selection, an unrankable catalogue, or an unrankable session model. It is the recorded form of \"never a downgrade\": the alternative is an empty `provider`/`model` pair, which is schema-invalid and still reads like an answer. A `tier` and `tier_reasons` may accompany it, because the tier was assigned from signals even when no model could be named for it.",
146
+ "description": "Adaptive: the host picks the model. `keryx review tier` writes it — in place of `provider`/`model`, never alongside them — whenever it does not name a model other than the session's: no session was named by the caller (flags or KERYX_SESSION_PROVIDER/KERYX_SESSION_MODEL), the catalogue or the session model could not be ranked, or the tier resolved to the session's own model. The host resolves the accompanying `tier` against the models its own dispatch tool offers: `standard` on its session model, `deep` on its most capable class, `light` on its lighter class — each falling back to the session model when the host offers no choice. The alternative, an empty or stale `provider`/`model` pair, is schema-invalid or pins a model the runner may not have.",
147
147
  "type": "boolean"
148
148
  }
149
149
  }