@kontextmind/kxm 0.7.188 → 0.7.190

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 (39) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/docs/README.md +1 -0
  3. package/docs/contributing/ci-and-release.md +1 -1
  4. package/docs/contributing/development.md +2 -2
  5. package/docs/contributing/writing-docs.md +9 -2
  6. package/docs/evals/planner-bakeoff-2026-10/judge/argon.json +18 -0
  7. package/docs/evals/planner-bakeoff-2026-10/judge/journal.json +18 -0
  8. package/docs/evals/planner-bakeoff-2026-10/judge/reviewer.json +18 -0
  9. package/docs/evals/planner-bakeoff-2026-10/judge/weekly.json +18 -0
  10. package/docs/evals/planner-bakeoff-2026-10/judge/wiki.json +18 -0
  11. package/docs/evals/planner-bakeoff-2026-10/judge/writer2.json +18 -0
  12. package/docs/evals/planner-bakeoff-2026-10/prompts/argon.txt +30 -0
  13. package/docs/evals/planner-bakeoff-2026-10/prompts/journal.txt +22 -0
  14. package/docs/evals/planner-bakeoff-2026-10/prompts/reviewer.txt +28 -0
  15. package/docs/evals/planner-bakeoff-2026-10/prompts/shared.txt +20 -0
  16. package/docs/evals/planner-bakeoff-2026-10/prompts/weekly.txt +23 -0
  17. package/docs/evals/planner-bakeoff-2026-10/prompts/wiki.txt +27 -0
  18. package/docs/evals/planner-bakeoff-2026-10/prompts/writer2.txt +40 -0
  19. package/docs/evals/planner-bakeoff-2026-10/raw/argon-fable.txt +68 -0
  20. package/docs/evals/planner-bakeoff-2026-10/raw/argon-sonnet.txt +69 -0
  21. package/docs/evals/planner-bakeoff-2026-10/raw/journal-fable.txt +60 -0
  22. package/docs/evals/planner-bakeoff-2026-10/raw/journal-sonnet.txt +79 -0
  23. package/docs/evals/planner-bakeoff-2026-10/raw/reviewer-fable.txt +74 -0
  24. package/docs/evals/planner-bakeoff-2026-10/raw/reviewer-sonnet.txt +95 -0
  25. package/docs/evals/planner-bakeoff-2026-10/raw/weekly-fable.txt +63 -0
  26. package/docs/evals/planner-bakeoff-2026-10/raw/weekly-sonnet.txt +66 -0
  27. package/docs/evals/planner-bakeoff-2026-10/raw/wiki-fable.txt +72 -0
  28. package/docs/evals/planner-bakeoff-2026-10/raw/wiki-sonnet.txt +79 -0
  29. package/docs/evals/planner-bakeoff-2026-10/raw/writer2-fable.txt +73 -0
  30. package/docs/evals/planner-bakeoff-2026-10/raw/writer2-sonnet.txt +79 -0
  31. package/docs/evals/planner-bakeoff-2026-10/score.py +304 -0
  32. package/docs/evals/planner-bakeoff-2026-10.md +164 -0
  33. package/package.json +2 -2
  34. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  35. package/plugins/kxm/dist/mcp-server.js +1 -1
  36. package/plugins/kxm/package.json +1 -1
  37. package/plugins/kxm/src/mcp-server.ts +1 -1
  38. package/scripts/check-plan-links.d.mts +4 -0
  39. package/scripts/check-plan-links.mjs +234 -0
@@ -0,0 +1,79 @@
1
+ ## Outcome
2
+
3
+ Status: the Runtime journal and retrospective are **blocked**. S5 is still open because its interactive browser login witness is outstanding. The delivery queue forbids any event-store or hub-store schema change in S0 through S5, and a Runtime journal needs a new store.
4
+
5
+ Allowed now (no schema change, no new store):
6
+ - A design note for the Runtime journal.
7
+ - Tests that lock the current refusal, so the gap stays honest and cannot be papered over.
8
+ - A tracking entry that names the gap, the trigger, and the owner.
9
+
10
+ I would **not** land a store before S5 closes. I see no existing store version I can bump without breaking the queue rule. The packet gives no schema version numbers, and any new Runtime journal table is by definition a schema change. So the answer to "which version would I bump" is none.
11
+
12
+ ## Files
13
+
14
+ - New: `docs/design/runtime-journal.md` (design note, marked "not implemented, blocked on S5").
15
+ - Edit: `plans/implementation-plan.md` (Tracking → Still open). Record the gap, the trigger (S5 closes), and the owner (current writer route, planner planning).
16
+ - Edit: the test file that covers the journal route. I can't name it without reading the repo, so the writer finds the existing `workflow_not_found` and journal-route test file.
17
+ - Edit: the test file for the improvement report, to lock its webhook-only scope.
18
+ - No changes to store, schema, migration, hub-route, or CLI source.
19
+
20
+ ## Tests
21
+
22
+ Characterization tests only, with no new behavior:
23
+ - `POST /v1/workflows/:id/journal` with a `kxm run` id returns `workflow_not_found`, and no journal row is written anywhere.
24
+ - `kxm workflow record` and `kxm_workflow_record` with a Runtime run id fail closed with the same error, and the CLI exits non-zero.
25
+ - A terminal Runtime run produces no retrospective export. Assert the absence, not a stub.
26
+ - The improvement report's ranked signals include only hub webhook runs. A Runtime run with matching content contributes nothing.
27
+ - A guard test fails if the schema version constants or table list change while S5 is open. Prefer an existing queue-rule check. If none exists, add a narrow snapshot of the schema surface, but only if that is cheap. Otherwise leave it to the open question below.
28
+ - Existing webhook journal behavior is unchanged: all ten categories are accepted and a record is bound to a stage id.
29
+
30
+ ## Docs
31
+
32
+ The design note covers:
33
+ - The problem: hub and Runtime are different stores.
34
+ - The decision: do not relabel Runtime runs as webhook runs and do not widen the existing route's lookup silently.
35
+ - A proposed shape, kept to non-binding options:
36
+ - A Runtime-owned journal store, separate from the hub store.
37
+ - The same ten categories, with each record bound to a stage id.
38
+ - A retrospective export for terminal Runtime runs, reusing the webhook export format where it fits.
39
+ - Either a distinct route or an explicit run-kind discriminator, with a typed error for an unknown kind.
40
+ - Promotion rules: no auto-promotion of skills or gates from telemetry, and no schema field for private handoff notes.
41
+ - An explicit statement that the improvement report's scope stays webhook-only until the store exists, and that any extension is a separate, reviewed change.
42
+ - The trigger and owner, copied from the packet.
43
+
44
+ Update the Tracking text so the "Runtime runs have no journal" line points at the note and the refusal tests.
45
+
46
+ ## Risks and guards
47
+
48
+ - Schema drift: no store, migration, or version edits. The tests above enforce this.
49
+ - Relabeling: refuse any change that makes a Runtime run resolve through the webhook-run lookup.
50
+ - Silent widening: the improvement report must not start mixing in Runtime runs without a deliberate decision.
51
+ - Stub retrospectives: refuse to emit an empty or fake export for Runtime runs. Absence is the honest state.
52
+ - Doc drift: the note must not say "shipped" or "planned for date X". It says "blocked on S5".
53
+ - Wrong tests: the refusal tests describe today's behavior. When the store lands, the writer must update them deliberately, not delete them.
54
+ - Cost: no model-driven work is needed. Verify with `npm run verify`.
55
+
56
+ ## Sequence
57
+
58
+ 1. Add the refusal and scope characterization tests. Confirm they pass against the current tree.
59
+ 2. Write the design note.
60
+ 3. Update Tracking in the implementation plan.
61
+ 4. Run `npm run verify`, then do the review round with both designated critics, as the process requires.
62
+ 5. Hold. When S5 closes, a later task designs the concrete store from the note, starting with a schema-version decision made with the real numbers in hand.
63
+
64
+ ## Non-goals
65
+
66
+ - Any Runtime journal store, table, or migration.
67
+ - Changes to the hub route, CLI, or MCP tool behavior.
68
+ - Retrospective export for Runtime runs.
69
+ - Improvement-report changes.
70
+ - Auto-promotion of skills or gates.
71
+ - A private-notes field.
72
+ - Closing S5 or changing its witness requirements.
73
+
74
+ ## Open questions
75
+
76
+ - What are the current event-store and hub-store schema version numbers? The packet does not say. They are needed only after S5 closes.
77
+ - Is there already a test or gate that enforces "zero schema change in S0 through S5"? If so, reuse it instead of adding a snapshot guard.
78
+ - Should the future Runtime journal use a new route or a run-kind discriminator on the existing one? Decide in the later task.
79
+ - Where should the design note live under the repo's docs conventions? The writer should follow the existing docs lint rules.
@@ -0,0 +1,74 @@
1
+ ## Outcome
2
+
3
+ - `reviewer-cli` roster, permission read-only, becomes:
4
+ 1. `codex-gpt-6-1-sol`, effort low — primary required CLI critic. Native harness `codex`, model `gpt-6.1-sol`, vendor openai, selector `openai/gpt-6.1-sol`.
5
+ 2. `pi-qwen3-8-flash-openrouter`, effort low — different-vendor fallback (unchanged).
6
+ 3. `codex-gpt-5-6-sol`, effort low — kept admitted as last fallback, not deleted.
7
+ - `gpt-6.1-sol` exists in inventory (`kxm.model.v2`) before the routes change; `kxm routes admit` accepts it.
8
+ - `.kxm/prices.yaml` gains one dated, re-pinned row for `gpt-6.1-sol` with `openai/gpt-6.1-sol-pro` as an alias on that row, not a second model.
9
+ - Cost recording: ChatGPT `authMethod` → `costBasis: unmetered`, `priceRef: subscription:codex`; API-key login → `unknown`.
10
+ - Architecture review stays `claude-fable` then a different-vendor Pi fallback. Two critics still required for acceptance.
11
+
12
+ ## Files
13
+
14
+ - Model inventory file for `gpt-6.1-sol` (schema `kxm.model.v2`): id `gpt-6.1-sol`, vendor openai, harness `codex`, selector `openai/gpt-6.1-sol`, reasoning efforts `low|medium|high|xhigh|max`, ceiling `reviewer-cli`. No `pro` effort value.
15
+ - `.kxm/routes.yaml` (`kxm.routes.v2`): add route `codex-gpt-6-1-sol`; reorder `reviewer-cli` roster as above; move the "required CLI critic" comment to the new primary; writer, planner, reviewer-arch rosters untouched.
16
+ - `.kxm/prices.yaml`: add `gpt-6.1-sol` row — $2 in / $10 out per 1M through 272000 prompt tokens, then $4 / $15; cache read $0.10, cache write $2.50 both tiers; alias `openai/gpt-6.1-sol-pro`; update date and sha256 pin.
17
+ - Any harness-run script hardcoding `gpt-5.6-sol` / `codex-gpt-5-6-sol` as the critic model: switch to the new id (locate by grep; names unknown from packet).
18
+ - Roster policy tests (see below).
19
+
20
+ ## Tests
21
+
22
+ - Roster policy test: `reviewer-cli` primary is `codex-gpt-6-1-sol`, effort low, permission read-only; `codex-gpt-5-6-sol` still admitted and last; position 2 is a non-openai vendor.
23
+ - Route id derivation: `codex` + `gpt-6.1-sol` → `codex-gpt-6-1-sol` (dots → dashes).
24
+ - Native-vendor brake: `openai-codex/gpt-6.1-sol` (Pi) and `openrouter openai/gpt-6.1-sol` and `openai/gpt-6.1-sol-pro` via OpenRouter are refused.
25
+ - Ceiling: admitting `gpt-6.1-sol` to `reviewer-arch` fails; `reviewer-arch` primary remains `claude-fable`.
26
+ - Effort validation: `pro` is rejected for the role; `low` accepted; one-shot shape resolves to `codex exec --json` with an effort flag.
27
+ - Prices loader: new row loads with pinned hash; hash mismatch refuses; `openai/gpt-6.1-sol-pro` resolves to the same row/price; tier boundary at 272000 prompt tokens.
28
+ - Cost basis: ChatGPT auth → `unmetered` + `subscription:codex`; API-key → `unknown`.
29
+ - Acceptance gate: still requires both critics; single-critic result is triage only.
30
+ - `kxm routes admit` ordering: refuses when the model is absent from inventory.
31
+ - Docs brake test: no remaining `gpt-5.6-sol` described as "primary" CLI critic.
32
+
33
+ ## Docs
34
+
35
+ Same change: `AGENTS.md` role table (Review row → "Codex gpt-6.1-sol"), `docs/reference/harness-routing.md`, `docs/reference/config-reference.md`, `docs/reference/cli-reference.md`, `docs/contributing/assignment-runner.md`, `docs/contributing/harness-routing-internals.md`, `CHANGELOG.md`, `plans/implementation-plan.md` Tracking → Decided (new admission, 5.6 demoted to last fallback, pro alias note, refused routes).
36
+
37
+ ## Risks and guards
38
+
39
+ - Billing OpenAI through Pi (`openai-codex`) or OpenRouter: native-vendor brake stays fail-closed; test it.
40
+ - Price hash mismatch silently underquoting: loader refuses mismatch; re-pin exactly once with the date.
41
+ - Adding `gpt-6.1-sol-pro` as a second model: refuse; alias only.
42
+ - Reasoning `pro` leaking into role effort: schema rejects it.
43
+ - Codex logged out or API-key login: no fallback to Pi same vendor; next eligible is the different-vendor Qwen route; cost recorded `unknown` for API key, never `unmetered`.
44
+ - Dropping or weakening the architecture critic: refuse; acceptance keeps both PASS records.
45
+ - Deleting `codex-gpt-5-6-sol`: refuse; demote only.
46
+ - Harness preferences overlay: refuse.
47
+ - Order of operations: inventory before `kxm routes admit`, or admit fails.
48
+
49
+ ## Sequence
50
+
51
+ 1. Add `gpt-6.1-sol` to model inventory; verify with `kxm harness list` / `pi auth check` not needed (native codex).
52
+ 2. Add price row + alias; update date and sha256; run loader test.
53
+ 3. Add route via `kxm routes admit`; reorder `reviewer-cli`; keep 5.6 last.
54
+ 4. Update hardcoded critic model in harness-run scripts.
55
+ 5. Update roster policy tests and add new tests above.
56
+ 6. Update all listed docs, CHANGELOG, Tracking.
57
+ 7. `npm run verify`; confirm dist matches if CLI changed.
58
+ 8. Record admission decision in Tracking → Decided.
59
+
60
+ ## Non-goals
61
+
62
+ - No change to writer, planner, or `reviewer-arch` rosters.
63
+ - No pro architecture-review route; no `gpt-6.1-sol` on `reviewer-arch`.
64
+ - No new model entry for pro; no OpenRouter/Pi OpenAI routes.
65
+ - No effort change (stays low); no preferences overlay; no third verify gate.
66
+ - No deletion of GPT-5.6 Sol.
67
+
68
+ ## Open questions
69
+
70
+ - Exact filename/path of the model inventory file for `kxm.model.v2`.
71
+ - Which harness-run script(s) hardcode the critic model.
72
+ - Exact codex `exec` effort flag name (packet gives values, not the flag).
73
+ - Whether `kxm routes admit` reorders rosters or ordering must be hand-edited in `routes.yaml`.
74
+ - Whether `plans/kxm-roadmap/state.json` needs a row for this admission.
@@ -0,0 +1,95 @@
1
+ ## Outcome
2
+ - `codex-gpt-6-1-sol` (harness `codex`, model `gpt-6.1-sol`, vendor `openai`, effort `low`, read-only) becomes the reviewer-cli primary.
3
+ - `codex-gpt-5-6-sol` stays admitted as the last fallback. It is not deleted.
4
+ - The Pi different-vendor fallback stays in the middle. It must remain a non-OpenAI vendor.
5
+ - Final reviewer-cli roster:
6
+ 1. `codex-gpt-6-1-sol`, low
7
+ 2. `pi-qwen3-8-flash-openrouter`, low
8
+ 3. `codex-gpt-5-6-sol`, low
9
+ - The architecture reviewer, writer and planner rosters do not change.
10
+ - GPT-6.1 Sol does not go onto `reviewer-arch`.
11
+
12
+ ## Files
13
+ - Model inventory entry for `gpt-6.1-sol` (schema `kxm.model.v2`). It must exist before admission, and the selector is `openai/gpt-6.1-sol`.
14
+ - `.kxm/routes.yaml` (schema `kxm.routes.v2`): admit the `codex-gpt-6-1-sol` route using `kxm routes admit`. Don't hand-edit if the command can do it.
15
+ - `.kxm/prices.yaml`:
16
+ - Add the price row for `gpt-6.1-sol`.
17
+ - Use the list prices from the packet: $2 input and $10 output per 1M tokens through 272000 prompt tokens, then $4 and $15. Cache read is $0.10 and cache write is $2.50 on both tiers.
18
+ - Alias the pro id on the same row. Do not add a second model.
19
+ - Update the date and the sha256 pin together.
20
+ - Reviewer-cli role definition (roster order and the "required CLI critic" comment).
21
+ - Any harness-run script that hardcodes the critic model. Find it with a search for `gpt-5.6-sol` and `codex-gpt-5-6-sol`, then read the role roster instead of a literal if the script allows it.
22
+ - Roster policy tests.
23
+
24
+ ## Tests
25
+ - Roster policy test:
26
+ - Primary is `codex-gpt-6-1-sol`.
27
+ - The read-only permission is unchanged.
28
+ - Effort is `low`.
29
+ - Roster order is as above.
30
+ - A different-vendor Pi fallback is still present.
31
+ - `codex-gpt-5-6-sol` is still admitted as the last fallback.
32
+ - Test that `reviewer-arch` contains no `gpt-6.1-sol` route, and that `claude-fable` is still its primary.
33
+ - Admission brakes:
34
+ - `kxm routes admit` is refused when the model is absent from inventory.
35
+ - `openai-codex` Pi provider routes and `openrouter/openai/gpt-6.1-sol` are refused by the native-vendor brake.
36
+ - The pro mode is not accepted as a role effort value.
37
+ - Prices:
38
+ - A hash mismatch is refused.
39
+ - The pro alias resolves to the same row.
40
+ - The tier boundary at 272000 prompt tokens prices correctly.
41
+ - Cost basis:
42
+ - ChatGPT auth records `unmetered` with `priceRef` `subscription:codex`.
43
+ - API-key auth records `unknown`.
44
+ - Codex one-shot command shape: `codex exec --json` with a mandatory effort, rejecting an empty or invalid value.
45
+ - Docs lint and the version check. Finish with `npm run verify`.
46
+
47
+ ## Docs
48
+ Update these in the same change:
49
+ - `AGENTS.md` role table
50
+ - `docs/reference/harness-routing.md`
51
+ - `docs/reference/config-reference.md`
52
+ - `docs/reference/cli-reference.md`
53
+ - `docs/contributing/assignment-runner.md`
54
+ - `docs/contributing/harness-routing-internals.md`
55
+ - `CHANGELOG.md`
56
+ - The `plans/implementation-plan.md` Tracking section (Decided entry for the admission, and the new primary)
57
+
58
+ Wording must keep the rule that both critics are required for acceptance and a single critic is triage only.
59
+
60
+ ## Risks and guards
61
+ - Billing through Pi or OpenRouter is refused. Keep the native-vendor brake and add the tests above.
62
+ - A stale price hash must fail the loader. Never edit the row without re-pinning.
63
+ - Pro is a reasoning mode, not a model and not a role effort. Refuse `pro` as an effort and refuse a separate pro route in the codex ceiling.
64
+ - The codex ceiling is reviewer-cli only. Do not widen it.
65
+ - An API-key login must not be recorded as unmetered.
66
+ - Don't leave stale `gpt-5.6-sol` literals in scripts or docs that call it the primary.
67
+ - Don't create dual naming or compatibility aliases for the old route.
68
+ - Refuse to add a harness preferences overlay.
69
+ - Refuse to drop or weaken the architecture critic.
70
+
71
+ ## Sequence
72
+ 1. Confirm `gpt-6.1-sol` is in inventory. If it isn't, refresh the inventory through the supported updater.
73
+ 2. Add the price row and alias, then re-pin the hash.
74
+ 3. Run `kxm routes admit` for the new route.
75
+ 4. Reorder the reviewer-cli roster.
76
+ 5. Update scripts that hardcode the critic.
77
+ 6. Write the tests first or alongside, and confirm they fail against the old roster.
78
+ 7. Update the docs, CHANGELOG and Tracking.
79
+ 8. Run `npm run verify`.
80
+ 9. Run the fixed witness, then get both critic PASS records before acceptance.
81
+
82
+ ## Non-goals
83
+ - No change to the writer, planner or `reviewer-arch` rosters.
84
+ - No pro architecture-review route.
85
+ - No Pi or OpenRouter OpenAI route.
86
+ - No effort change above `low` for this role.
87
+ - No overlay, and no new schema fields.
88
+ - No hosting or provider migration.
89
+
90
+ ## Open questions
91
+ - Is the `gpt-6.1-sol` inventory entry already present, and which updater supplies it?
92
+ - Does the Pi fallback stay second in the roster, or should the order between the Pi fallback and `codex-gpt-5-6-sol` be flipped? I assumed the Pi fallback stays second.
93
+ - Are the packet's list prices complete enough to pin, or does the price feed need a dated source?
94
+ - Which harness-run scripts hardcode the critic? The packet doesn't name them.
95
+ - Is the model's comment text ("required CLI critic") carried over verbatim to the new primary?
@@ -0,0 +1,63 @@
1
+ ## Outcome
2
+
3
+ A weekly GitHub Actions job refreshes `.kxm/models/inventory.yaml` and `.kxm/prices.yaml` from the public OpenRouter models API (plus the Nous catalog the existing refresh already reads), and opens exactly one pull request only when the catalog bytes changed. The PR body lists added, removed, and repriced model ids. A human reviews and merges. The job never touches `.kxm/routes.yaml`, never admits or disables routes, never drops CLI-only inventory rows, and never changes writer/planner/reviewer rosters.
4
+
5
+ ## Files
6
+
7
+ - `.github/workflows/catalog-refresh.yml` (new): weekly `schedule` plus `workflow_dispatch`; no secrets; `permissions: contents: write, pull-requests: write` only.
8
+ - A deterministic refresh entry point reused by CI and locally, in the existing `kxm models` command module (exact path per repo layout): adds a `prices` refresh step beside `inventory-refresh`, computes the diff, and writes a PR-body markdown file.
9
+ - A small diff/PR-body module (new, same package as the prices loader): compares old vs new `prices.yaml` and `inventory.yaml`, emits `added`, `removed`, `repriced` lists, and a boolean `changed`.
10
+ - `.kxm/prices.yaml`, `.kxm/models/inventory.yaml`: changed only by the PR the job opens, never by the workflow definition itself.
11
+ - `docs/reference/harness-routing.md`, the contributing CI page under `docs/contributing/`, `CHANGELOG.md`.
12
+ - `plans/implementation-plan.md` Tracking: one line noting the weekly job exists and that it is not a route-admission path.
13
+
14
+ ## Tests
15
+
16
+ Unit tests next to the existing prices-loader and inventory-refresh tests (same test runner, no network: fixture JSON for the OpenRouter response):
17
+
18
+ - Unchanged catalog: refresh produces identical bytes, `changed=false`, `date` and `sha256` untouched, no PR body written.
19
+ - Changed catalog: `date` and `sha256` both update, and only together; a test that mutates one without the other is rejected by the loader.
20
+ - PR body names added ids and removed ids verbatim and lists repriced ids with old/new values; body contains no `OPENROUTER_API_KEY`-style strings (assert against a fixture environment with a planted fake secret).
21
+ - CLI-only rows preserved: run the merge with `pi`, `grok`, and `agy` absent from `PATH`; assert those inventory rows survive byte-for-byte. A refresh that drops them must throw, not warn.
22
+ - routes.yaml refusal: the refresh step is handed a fake filesystem; assert `.kxm/routes.yaml` is never opened for write and no roster field changes.
23
+ - Token guard: if the OpenRouter response is 401/403 or demands auth, the step exits non-zero with a message that says a token would be required, rather than retrying with any env var.
24
+ - Workflow lint: a test or docs-lint rule asserting the workflow file contains no `secrets.` reference other than the default `GITHUB_TOKEN` and no model-calling step.
25
+
26
+ ## Docs
27
+
28
+ - `docs/reference/harness-routing.md`: new subsection "Weekly catalog refresh": what changes, what does not (routes, rosters), that stale prices still show in the routing report so operators check `date`, and how to run the same refresh locally with `--dry-run`.
29
+ - Contributing CI page: add the job to the workflow table; state it is not a required status check and does not call a model; name the schedule as an operator choice.
30
+ - `CHANGELOG.md`: one entry under unreleased.
31
+
32
+ ## Risks and guards
33
+
34
+ - **Silent underquote**: if fetch fails or is partial, write nothing and exit non-zero; never write a `prices.yaml` with today's `date` over stale models.
35
+ - **Hash drift**: compute `sha256` over the canonical serialized `models` block, then write `date` and hash in one atomic write; the loader already refuses mismatch.
36
+ - **CLI-only row loss**: merge, do not replace; refuse if the post-merge inventory lacks any row that existed and is not sourced from OpenRouter/Nous.
37
+ - **Accidental admission**: the job's write allowlist is exactly two files; any other diff fails the step.
38
+ - **Token creep**: no `secrets.*` beyond `GITHUB_TOKEN`; fail closed with a clear message if the API ever requires auth.
39
+ - **PR spam**: open one PR on a fixed branch name and update it if it already exists; no PR when `changed=false`.
40
+ - **Auto-merge**: no `gh pr merge`, no `--auto`, no auto-approve.
41
+ - I would refuse to: add a token to work around an auth wall, make the job a required check, let it edit `routes.yaml`, or widen rosters.
42
+
43
+ ## Sequence
44
+
45
+ 1. Diff module and PR-body renderer, with fixtures and tests.
46
+ 2. Prices refresh step with atomic date+hash write and CLI-only row preservation guard; tests.
47
+ 3. Workflow file; schedule choice: Monday 06:00 UTC (a choice, not a discovered fact); dry-run locally against fixtures.
48
+ 4. Docs and CHANGELOG; Tracking line.
49
+ 5. `npm run verify`; commit; push; one manual `workflow_dispatch` to confirm "no PR when unchanged".
50
+
51
+ ## Non-goals
52
+
53
+ - Admitting, disabling, or ranking routes; editing rosters.
54
+ - Nous Portal price fetching if it requires auth (inventory ids only, as today).
55
+ - Changing the routing report's stale-price behavior.
56
+ - Any model call in CI.
57
+
58
+ ## Open questions
59
+
60
+ - Does the public OpenRouter models endpoint return pricing without a key for all models the inventory lists? If not, which are excluded and how is that surfaced in the PR body?
61
+ - Exact field names in `prices.yaml` `models` entries for repricing comparison.
62
+ - Whether PR creation should use `GITHUB_TOKEN` directly or an existing repo convention; `GITHUB_TOKEN`-opened PRs do not trigger PR CI, so the reviewer may need to re-run checks.
63
+ - Whether the existing `inventory-refresh` already preserves CLI-only rows, or that guard must be added there too.
@@ -0,0 +1,66 @@
1
+ ## Outcome
2
+ A scheduled GitHub Actions workflow runs weekly. It fetches the public OpenRouter models API, refreshes the price catalog and the model inventory, and opens one pull request only when the bytes changed. A human reviews and merges it. The job never edits `routes.yaml`, never admits or disables routes, and never touches rosters.
3
+
4
+ ## Files
5
+ - `.github/workflows/catalog-refresh.yml` (new).
6
+ - Triggers: `schedule` and `workflow_dispatch`.
7
+ - Schedule is a **choice, not a discovered fact**: Monday 06:00 UTC (`0 6 * * 1`).
8
+ - Permissions: `contents: write` and `pull-requests: write` only.
9
+ - Steps: checkout, install with `npm ci`, run the refresh script, and open a PR only if the diff is non-empty. There is no token for the OpenRouter fetch. The default `GITHUB_TOKEN` is used only for the PR.
10
+ - It must not be a required status check and must not call a model.
11
+ - `scripts/catalog-refresh.*` (new). It is a deterministic orchestrator that does the following.
12
+ 1. Fetch the public models endpoint. A 401 or 403 is a hard failure with the message "token required; refusing to proceed".
13
+ 2. Build the new prices file, with the date and sha256 recomputed only when the model bytes differ.
14
+ 3. Run `kxm models inventory-refresh --json`. Use the `--dry-run` result to compute the diff.
15
+ 4. Run the guards.
16
+ 5. Write the PR body from the diff.
17
+ - `.kxm/prices.yaml` and `.kxm/models/inventory.yaml` are the only outputs the job may change.
18
+ - A small, testable module for diffing (added, removed, repriced) and for rendering the PR body, so the logic is not buried in YAML.
19
+
20
+ ## Tests
21
+ Put these under the Node unit suite (`npm test`) so existing PR CI picks them up. They use fixtures, not the network.
22
+ - **Unchanged:** identical API fixture produces an empty diff, so no PR is requested and prices.yaml is byte-identical (date and sha unchanged).
23
+ - **PR body:** added and removed ids appear by name, repriced ids show old and new values, and the body contains no env or secret values.
24
+ - **CLI-only rows:** run with no `pi`, `grok`, or `agy` on PATH. Rows that came from those binaries must survive. Any deletion fails the run.
25
+ - **Routes:** the job fails if `.kxm/routes.yaml` has any diff, and the script never invokes `routes admit` or `routes disable`.
26
+ - **Price hash:** date and sha256 change together or not at all, and the loader still refuses a mismatch.
27
+ - **Auth failure:** a 401 or 403 fixture fails closed.
28
+ - **Workflow lint:** a test asserts the workflow has no secrets reference for the fetch, minimal permissions, and no model-calling step.
29
+
30
+ ## Docs
31
+ - `docs/reference/harness-routing.md`: describe the weekly job, the stale-price behavior (`priceCatalogStale`), and that admission stays an operator action.
32
+ - The contributing CI page: add the new workflow, its schedule marked as a choice, and a note that it is not required.
33
+ - `CHANGELOG.md`: add an entry.
34
+ - Run docs lint, because the repo has a docs brake.
35
+
36
+ ## Risks and guards
37
+ - **CLI-only row loss:** the runner has no local harness binaries. Guard: the script merges refreshed OpenRouter and Nous rows into the existing file and never rewrites absent-source rows. Abort if the row count by source drops without a matching removal in the diff.
38
+ - **Route drift:** after the refresh, assert that `routes.yaml` is unchanged. A new inventory id does not imply a route.
39
+ - **Silent underquoting:** if the fetch fails or returns a suspiciously empty or short list, fail without writing. Never write a partial catalog.
40
+ - **Duplicate PRs:** use a fixed branch name and update the existing PR instead of opening a second one.
41
+ - **Secrets:** the PR body is built from ids and numbers only.
42
+ - **Generated `dist`:** if any CLI source changes, `npm run verify` must stay green.
43
+ - **Refuse to:** add a token, call a model, edit routes or rosters, auto-merge, or add a required check.
44
+
45
+ ## Sequence
46
+ 1. Write the diff and body module and its fixture tests first, and see them fail.
47
+ 2. Write the orchestrator with the guards.
48
+ 3. Add the workflow.
49
+ 4. Add the workflow lint test.
50
+ 5. Update the docs and the changelog.
51
+ 6. Run `npm run verify`, then do a `workflow_dispatch` dry run.
52
+
53
+ ## Non-goals
54
+ - Auto-admission of routes, roster changes, or auto-merge.
55
+ - Nous price fetching beyond what `inventory-refresh` already does.
56
+ - A model-based review of the diff.
57
+ - Changing the loader semantics or the schema.
58
+ - Backfilling CLI harness discovery.
59
+
60
+ ## Open questions
61
+ - Does `kxm models inventory-refresh` already preserve rows by source, or does the script need to enforce that?
62
+ - Which Nous endpoint does the refresh use, and is it public?
63
+ - Is `--dry-run` output stable enough to diff?
64
+ - What is the exact shape of the OpenRouter price fields (units), and how does the `models` map in `prices.yaml` store them?
65
+ - Does the repo's branch-protection setup let `GITHUB_TOKEN`-created PRs trigger CI? If not, a different mechanism is needed.
66
+ - Where do the sha256 inputs come from: the canonical bytes, or the models block only?
@@ -0,0 +1,72 @@
1
+ ## Outcome
2
+
3
+ A small, hand-authored Markdown knowledge wiki under `.kxm/knowledge/` that operators can read for current architecture, routing decisions, glossary pointers, CI/release patterns, and a few runbooks. It is explicitly authored, not compiled; it does not select wiki ingest or compile, touches no hub schema, routes, rosters, prices, npm scripts, or CI jobs, and passes markdownlint. Four existing docs gain one link line each.
4
+
5
+ ## Files
6
+
7
+ New (all under `.kxm/knowledge/handbook/` to avoid colliding with the compiler's `.kxm/knowledge/wiki/` output):
8
+
9
+ - `index.md` — table of contents; a header note stating these pages are authored by hand, not generated, and not the authoritative store.
10
+ - `architecture-overview.md` — hub, local Runtime, SQLite at `.kxm/state/kxm.db`, single node, at-least-once.
11
+ - `decisions/native-harness-wins.md` — Fable plans and reviews architecture; Grok writes; Codex reviews CLI/docs; Pi only for vendors without an authenticated native harness; Google route per Tracking (see open questions); fail closed when logged out.
12
+ - `glossary.md` — short summary of key terms, each linking to `docs/glossary.md`; no new definitions.
13
+ - `patterns/ci.md` — PRs run docs lint, typecheck, Node unit tests, Python control-plane suite; `CI / required` aggregates.
14
+ - `runbooks/release.md` — npm package `@kontextmind/kxm`, changelog update, existing verify/CI gates; no new command.
15
+ - `runbooks/failed-release.md` — high level: stop, inspect CI, do not re-tag, fix forward via normal PR loop.
16
+ - `runbooks/model-routes.md` — `kxm routes list`; admit/disable are reviewed actions; `prices.yaml` hash must match or the route fails closed.
17
+ - `runbooks/browser.md` — Obscura is the default Playwright browser; Steel is for human takeover, MFA, live viewer only; no flags beyond `KXM_BROWSER=steel`, which the packet supports.
18
+
19
+ Edited (one line each):
20
+
21
+ - `docs/README.md`
22
+ - the architecture index under `docs/` (exact filename to confirm)
23
+ - the context-and-memory guide
24
+ - the config reference
25
+
26
+ ## Tests
27
+
28
+ - No new test files. Run existing `npm run verify` (includes `lint:docs` / markdownlint and the docs brake for product names).
29
+ - If the docs lint has a link checker, the four new relative links must resolve; the handbook's own relative links to `docs/glossary.md` must resolve from `.kxm/knowledge/handbook/`.
30
+ - Manually confirm no page is picked up by anything that would treat it as compiled output (it lives outside `wiki/`).
31
+
32
+ ## Docs
33
+
34
+ - The four link lines read, for example: "Hand-authored operator handbook: `.kxm/knowledge/handbook/index.md` (not generated)."
35
+ - Sentence-case titles, relative links, product name KXM only. No "Mesh".
36
+ - No links from `docs/` into `plans/`; the handbook also avoids linking into `plans/`.
37
+ - Context-and-memory guide line must restate: wiki compile/ingest remain unselected; the handbook is not compiler output.
38
+
39
+ ## Risks and guards
40
+
41
+ - **Authority confusion**: a reader may treat handbook pages as compiled truth. Guard: index banner plus a one-line footer on each page ("authored; verify against code and Tracking").
42
+ - **Collision with compiler**: writing into `.kxm/knowledge/wiki/` would be overwritten or mistaken for generated. Guard: use `handbook/` subdirectory.
43
+ - **Glossary fork**: duplicating definitions creates drift. Guard: summarize and link only; refuse to define new terms.
44
+ - **Stale admissions**: listing admitted routes would repeat the drift AGENTS.md already suffered. Guard: the decision page names the rotation shape and points to Tracking → Decided and `kxm harness list` for current admissions.
45
+ - **Invented facts**: refuse to add prices, model ids, release commands, or browser flags not in the packet.
46
+ - **Secrets/hosts**: refuse hostnames, tokens, private box names.
47
+ - **Scope creep**: refuse to fix the three known compiler gaps, add npm scripts, CI jobs, schema, or route changes.
48
+ - markdownlint failure blocks commit; fix the Markdown, not the lint config.
49
+
50
+ ## Sequence
51
+
52
+ 1. Confirm exact filenames of the architecture index, context-and-memory guide, and config reference.
53
+ 2. Create `handbook/index.md` with authority banner.
54
+ 3. Write architecture, decision, glossary, CI pages.
55
+ 4. Write the four runbooks.
56
+ 5. Add the four one-line links.
57
+ 6. Run `npm run verify`; fix lint.
58
+ 7. Commit as `docs: seed hand-authored knowledge handbook`; push; PR via normal loop.
59
+
60
+ ## Non-goals
61
+
62
+ - Running `kxm context wiki-compile` or `wiki-lint`; selecting ingest.
63
+ - Fixing the `.kxm/memory` lookup path, unreviewed-journal inclusion, or temporal-state index link.
64
+ - Editing routes, rosters, `prices.yaml`, hub schema, npm scripts, CI.
65
+ - A second glossary or any Phase 4/11 router content.
66
+
67
+ ## Open questions
68
+
69
+ - Exact filenames of the architecture index, context-and-memory guide, and config reference.
70
+ - Google route wording: the packet says "agy, not OpenRouter"; current Tracking → Decided may phrase it as the `antigravity` Pi provider with `agy` as a catalog helper. Writer must copy the Tracking text verbatim rather than choose.
71
+ - Whether `.kxm/` is excluded by `.gitignore` or markdownlint config, which would require an explicit include.
72
+ - Whether docs lint resolves links in files outside `docs/`.
@@ -0,0 +1,79 @@
1
+ ## Outcome
2
+
3
+ A small hand-written wiki lives under `.kxm/knowledge/`. It has an `index.md` and about eight short pages. The pages cover architecture, the routing decision, a glossary pointer, the CI pattern, release and failed-release runbooks, a model-route runbook, and a browser runbook. Each page opens with one line saying it is authored Markdown, a reviewable operator view, and not generated or authoritative. Pages link to the authoritative docs. Nothing selects wiki-compile or ingest, and there are no schema, CLI, script, CI, route, roster, or price changes.
4
+
5
+ ## Files
6
+
7
+ New, under `.kxm/knowledge/`:
8
+ - `index.md`: lists the pages in a table with a one-line purpose each. It states the authored status and that wiki-compile and wiki-lint are unselected.
9
+ - `architecture-overview.md`: hub, local Runtime, SQLite at `.kxm/state/kxm.db`, single node, at-least-once delivery.
10
+ - `decision-native-harness.md`:
11
+ - A provider's native harness wins when it is installed and logged in.
12
+ - Claude Fable plans and does architecture review.
13
+ - Grok writes.
14
+ - Codex reviews CLI and docs.
15
+ - Google goes through agy, not OpenRouter.
16
+ - Pi is for vendors with no native harness.
17
+ - Admissions live in Tracking and `kxm harness list`, not in this page.
18
+ - `glossary-pointer.md`: a short summary of the key terms plus a link to `docs/glossary.md`. No new definitions.
19
+ - `pattern-ci.md`: pull requests run docs lint, typecheck, Node unit tests, and the Python control-plane suite. `CI / required` is the aggregate check.
20
+ - `runbook-release.md`: npm package `@kontextmind/kxm`, changelog, and pointers to existing release docs.
21
+ - `runbook-failed-release.md`: triage steps at a high level, with no new commands.
22
+ - `runbook-model-routes.md`: `kxm routes list`; admit and disable are reviewed; the `prices.yaml` hash must match.
23
+ - `runbook-browser.md`: Obscura is the default Playwright browser. Steel is only for human takeover. No flags.
24
+
25
+ Edited, one line each:
26
+ - `docs/README.md`
27
+ - the architecture index in docs
28
+ - the context-and-memory guide
29
+ - the config reference
30
+
31
+ ## Tests
32
+
33
+ - No new tests. Run `npm run verify`, which includes `lint:docs`, the markdownlint gate.
34
+ - Check that every relative link resolves. Run the existing docs link check if there is one.
35
+ - Confirm the four doc links point only to `.kxm/knowledge/` and that nothing under `docs/` links into `plans/`.
36
+ - Confirm that `.kxm/knowledge/` is not gitignored. Then confirm that markdownlint covers or deliberately excludes it, and that the docs brake against Mesh names passes on it.
37
+ - Run a grep over the new pages for secrets, tokens, private hostnames, and "Mesh".
38
+
39
+ ## Docs
40
+
41
+ - The four one-line links are the only edits to existing docs.
42
+ - Add a changelog entry only if the changelog convention covers docs-only changes.
43
+ - Do not edit `plans/implementation-plan.md`, since no phase gate changes.
44
+
45
+ ## Risks and guards
46
+
47
+ - **Authority confusion:** a banner on every page and in the index says the pages are authored and non-authoritative. Link to the source docs rather than restating them.
48
+ - **Drift:** the routing page must not list current admissions. It points to Tracking → Decided and `kxm harness list`, as AGENTS.md does.
49
+ - **Wiki-compile collision:** the compiler writes to `.kxm/knowledge/wiki/`. Keep authored pages at the `.kxm/knowledge/` top level, not in `wiki/`, so a compile run cannot overwrite them. Also check whether any tool treats `.kxm/knowledge/` as generated output or cleans it.
50
+ - **Glossary fork:** summarize only, and use glossary terms exactly.
51
+ - **KontextMind confusion:** never describe the wiki as a KontextMind mind or km_ surface.
52
+ - Refuse to add flags, commands, prices, model ids, or hostnames that are not in the packet or existing docs. Refuse to add `.kxm/memory` files or touch the compiler gaps.
53
+ - Refuse to add dual or legacy product names.
54
+
55
+ ## Sequence
56
+
57
+ 1. Confirm that `.kxm/knowledge/` is tracked and that markdownlint, link checks, and the docs brake cover it. Record the answer.
58
+ 2. Write `index.md` and the architecture and glossary pages.
59
+ 3. Write the decision and CI pages.
60
+ 4. Write the four runbooks, taking details only from existing docs.
61
+ 5. Add the four one-line links.
62
+ 6. Run the secret and name grep, then `npm run verify`.
63
+ 7. Commit.
64
+
65
+ ## Non-goals
66
+
67
+ - Running or fixing wiki-compile or wiki-lint.
68
+ - Fixing the `.kxm/memory` lookup, the unreviewed-entry inclusion, or the temporal-state index path.
69
+ - Wiki ingest or any hub schema change.
70
+ - New npm scripts, CI jobs, or a release command.
71
+ - Edits to routes, rosters, or prices.
72
+ - Links from docs into plans.
73
+
74
+ ## Open questions
75
+
76
+ - Are the `.kxm/` paths ignored by git, or by the markdownlint config? If so, which exception is needed?
77
+ - Which existing doc is the architecture index, and which doc is the canonical release source?
78
+ - Does the changelog require entries for docs-only changes?
79
+ - Does the existing release doc have a failed-release procedure to link to, or must the page stay at the level of "stop and escalate to the operator"?
@@ -0,0 +1,73 @@
1
+ ## Outcome
2
+
3
+ - Writer #2 becomes `pi-qwen3-coder-next-openrouter` (model `openrouter/qwen/qwen3-coder-next`, vendor alibaba, harness pi, permission edit, effort medium). Alias `qwen-openrouter-pi` moves to the new route.
4
+ - Why this candidate: it is the direct successor to the retired coder route, the cheapest in the packet (0.12 / 0.80), Qwen is explicitly allowed through OpenRouter, and its 262144 context has no long-context premium tier to misquote. `qwen3.7-plus` is rejected for the 256000-token price step and higher base price; `qwen3-coder-flash` is the fallback if coder-next fails the tool-support check (see Open questions).
5
+ - `pi-qwen3-coder-plus-openrouter` is retired, not deleted: off the admitted list and roster, price row kept, inventory and routes carry a retired comment.
6
+ - Writer #1 and routes 3–6 unchanged, same order.
7
+
8
+ ## Files
9
+
10
+ - New model file, `kxm.model.v2`, for `pi-qwen3-coder-next-openrouter` (same directory as the existing `pi-qwen3-coder-plus-openrouter` model file).
11
+ - Inventory: add the new id; mark the old id `retired` with a dated comment (404 on 2026-10-17).
12
+ - Routes / admitted list: remove old id, add new id with permission edit; retired comment on the old entry.
13
+ - Writer roster, effort medium: replace position 2 only.
14
+ - `.kxm/prices.yaml`: keep `qwen/qwen3-coder-plus` row at last list price with a retired note; add `qwen/qwen3-coder-next` 0.12 / 0.80, context 262144; bump date to 2026-10-17 and recompute sha256 in the same change.
15
+ - `plans/evidence/` new note: OpenRouter 404 for the old slug, candidate table, price source date, selection rationale, tool-support verification result.
16
+ - `plans/implementation-plan.md` Tracking → Decided: record the writer #2 swap and the brake reasoning.
17
+ - Docs: harness-routing, config reference, CLI reference, assignment runner, glossary (only if it names the route), changelog.
18
+ - `dist/`: regenerate only if a test or grep shows the old route id or slug embedded in a bundle.
19
+
20
+ ## Tests
21
+
22
+ - Roster-policy tests: writer #2 expectations switch to the new id; assert the old id is absent from admitted and roster but present in inventory as retired.
23
+ - Prices loader test: fixture with the new date/hash passes; a mismatched sha256 is refused.
24
+ - Inventory-before-admit test: admitting an id not in inventory fails closed.
25
+ - Brake test: `openrouter/moonshotai/...` as a writer is refused with the native-harness reason; a meta slug is refused as unadmitted.
26
+ - Model-file schema test for the new file (v2, harness pi, vendor alibaba, edit present).
27
+ - Docs brake / lint:docs: no doc still names `qwen3-coder-plus` as a live writer.
28
+ - `npm run verify` after `npm ci`.
29
+
30
+ ## Docs
31
+
32
+ - harness-routing: roster table row 2, retired-route note, pricing tier note (none for coder-next).
33
+ - Config reference: prices.yaml example rows and the date/sha pin rule.
34
+ - CLI reference: any example output showing writer #2.
35
+ - Assignment runner: default writer rotation example.
36
+ - Glossary: alias `qwen-openrouter-pi` target, if listed.
37
+ - Changelog: "writer #2 replaced; old route retired, price history kept."
38
+
39
+ ## Risks and guards
40
+
41
+ - Tool support unverified from this packet. Guard: the writer must run a real `pi auth check --provider openrouter` and a one-shot edit smoke on the new model before admitting; if the model cannot call tools, do not admit, fall back to `qwen3-coder-flash` under the same check.
42
+ - Moonshot via OpenRouter is refused: kimi has a native harness, so this is the native-vendor-through-Pi case the brake exists for. Not selected.
43
+ - Meta via OpenRouter is an admission question, not in scope; not selected.
44
+ - prices.yaml hash drift: date and sha256 updated in the same commit; loader refuses mismatch, so verify runs it.
45
+ - Ordering: inventory edit lands before routes admit, in the same change, so no intermediate state admits an unknown id.
46
+ - History: no deletion of the old price row or inventory entry.
47
+ - Refuse: editing writer #1, planner, reviewer-cli, reviewer-arch; reordering Argon/Flash; adding a harness preferences overlay; inventing supported_parameters or prices.
48
+
49
+ ## Sequence
50
+
51
+ 1. Evidence note under `plans/evidence/` with the 404 and candidate table.
52
+ 2. New model file; inventory add + retire old.
53
+ 3. prices.yaml rows, date, sha256.
54
+ 4. Routes/admitted + roster swap; alias move.
55
+ 5. Tests (roster, loader, brake, inventory, schema).
56
+ 6. Docs and changelog; Tracking entry.
57
+ 7. Tool-support smoke on the new route; fail closed if it cannot edit.
58
+ 8. `npm ci && npm run verify`; regenerate `dist` only if embedded strings changed.
59
+ 9. One commit per logical change (evidence/model, prices, routes+tests, docs).
60
+
61
+ ## Non-goals
62
+
63
+ - No change to writer #1, critics, or Gemini positions.
64
+ - No Meta or Moonshot admission.
65
+ - No catalog feed, price refresh tooling, or routing report changes.
66
+ - No alias compatibility shim for the old route id; it brakes.
67
+
68
+ ## Open questions
69
+
70
+ - Does `qwen/qwen3-coder-next` advertise tool calling on OpenRouter (`supported_parameters` absent from packet)? Assumption labeled: yes; blocking if false.
71
+ - Exact directory names for model files, inventory, routes, and roster-policy tests in this repo.
72
+ - Does `dist` embed the roster or route ids?
73
+ - Should the alias `qwen-openrouter-pi` follow the new route or be retired with the old one? Assumed: follows.