@klhapp/skillmux 1.11.2 → 1.13.0

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 (104) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +20 -10
  3. package/bin/skillmux.js +89 -0
  4. package/docs/README.md +4 -4
  5. package/docs/cli.md +15 -5
  6. package/docs/concepts.md +4 -3
  7. package/docs/configuration.md +22 -5
  8. package/docs/deployment.md +3 -3
  9. package/docs/getting-started.md +32 -7
  10. package/docs/releasing.md +17 -2
  11. package/docs/sdd/cli-remote-target-parity/schema-bucket-b.yaml +297 -0
  12. package/docs/sdd/cli-remote-target-parity/spec-bucket-b.md +95 -0
  13. package/docs/sdd/cli-remote-target-parity/spec.md +111 -0
  14. package/docs/sdd/cli-remote-target-parity/think.md +183 -0
  15. package/docs/sdd/cli-surface-consistency/think.md +149 -0
  16. package/docs/sdd/config-authority-rerank-resilience/plan.md +338 -0
  17. package/docs/sdd/config-authority-rerank-resilience/review.md +124 -0
  18. package/docs/sdd/config-authority-rerank-resilience/spec.md +78 -0
  19. package/docs/sdd/feat-packaging-deployment/review.md +95 -0
  20. package/docs/sdd/fetch-outcome-flywheel/review.md +103 -0
  21. package/docs/sdd/fetch-outcome-flywheel/schema.json +347 -0
  22. package/docs/sdd/fetch-outcome-flywheel/spec.md +185 -0
  23. package/docs/sdd/npm-native-binaries/review.md +103 -0
  24. package/docs/sdd/npm-native-binaries/spec.md +148 -0
  25. package/docs/sdd/ranked-shortlist-2/pr3-calibration-removal.md +56 -0
  26. package/docs/sdd/refactor-builtin-target-paths/spec.md +41 -0
  27. package/docs/sdd/runtime-resource-hardening/review.md +86 -0
  28. package/docs/sdd/runtime-resource-hardening/spec.md +43 -0
  29. package/docs/sdd/security-hardening-phase/think.md +129 -0
  30. package/docs/sdd/security-observability/review.md +96 -0
  31. package/docs/sdd/security-observability/spec.md +55 -0
  32. package/docs/sdd/skill-provenance-update/review.md +152 -0
  33. package/docs/sdd/skill-provenance-update/schema.json +193 -0
  34. package/docs/sdd/skill-provenance-update/spec.md +134 -0
  35. package/docs/sdd/supply-chain-hardening/review.md +50 -0
  36. package/docs/sdd/supply-chain-hardening/spec.md +42 -0
  37. package/docs/sdd/target-marker-rehome/spec.md +33 -0
  38. package/docs/skill-management.md +1 -1
  39. package/docs/troubleshooting.md +18 -2
  40. package/package.json +15 -8
  41. package/src/adapters.ts +0 -438
  42. package/src/audit.ts +0 -21
  43. package/src/cli.ts +0 -928
  44. package/src/clients.ts +0 -368
  45. package/src/commands/audit.ts +0 -85
  46. package/src/commands/config.ts +0 -224
  47. package/src/commands/context.ts +0 -104
  48. package/src/commands/core.ts +0 -56
  49. package/src/commands/doctor.ts +0 -97
  50. package/src/commands/eval.ts +0 -88
  51. package/src/commands/init.ts +0 -672
  52. package/src/commands/install.ts +0 -155
  53. package/src/commands/local-vault.ts +0 -60
  54. package/src/commands/models.ts +0 -10
  55. package/src/commands/outdated.ts +0 -115
  56. package/src/commands/project.ts +0 -580
  57. package/src/commands/report.ts +0 -66
  58. package/src/commands/scan.ts +0 -71
  59. package/src/commands/shared.ts +0 -38
  60. package/src/commands/skill.ts +0 -33
  61. package/src/commands/sync.ts +0 -233
  62. package/src/commands/target.ts +0 -225
  63. package/src/commands/update.ts +0 -277
  64. package/src/completions.ts +0 -196
  65. package/src/concurrency-limiter.ts +0 -61
  66. package/src/config-service.ts +0 -398
  67. package/src/config-watcher.ts +0 -253
  68. package/src/config.ts +0 -583
  69. package/src/context.ts +0 -188
  70. package/src/db-audit.ts +0 -286
  71. package/src/db-index.ts +0 -238
  72. package/src/db.ts +0 -3
  73. package/src/deployment.ts +0 -39
  74. package/src/doctor.ts +0 -205
  75. package/src/eval.ts +0 -302
  76. package/src/global-flags.ts +0 -46
  77. package/src/init-agents.ts +0 -329
  78. package/src/init-instructions.ts +0 -192
  79. package/src/init.ts +0 -389
  80. package/src/install.ts +0 -232
  81. package/src/lifecycle.ts +0 -51
  82. package/src/logger.ts +0 -26
  83. package/src/manifest.ts +0 -352
  84. package/src/mcp-registration.ts +0 -89
  85. package/src/metrics.ts +0 -121
  86. package/src/models.ts +0 -20
  87. package/src/output.ts +0 -214
  88. package/src/project-setup.ts +0 -36
  89. package/src/prompts.ts +0 -124
  90. package/src/provenance.ts +0 -99
  91. package/src/rate-limiter.ts +0 -137
  92. package/src/readiness.ts +0 -30
  93. package/src/redact.ts +0 -52
  94. package/src/router-core.ts +0 -666
  95. package/src/rrf.ts +0 -31
  96. package/src/scan.ts +0 -300
  97. package/src/server.ts +0 -930
  98. package/src/setup.ts +0 -145
  99. package/src/snapshot.ts +0 -135
  100. package/src/stats.ts +0 -340
  101. package/src/sync.ts +0 -482
  102. package/src/toml-writer.ts +0 -51
  103. package/src/types.ts +0 -212
  104. package/src/vault.ts +0 -207
@@ -0,0 +1,149 @@
1
+ # CLI surface consistency: the "target" vocabulary
2
+
3
+ Status: proposal. Nothing implemented yet.
4
+
5
+ ## The problem
6
+
7
+ The word "target" carries four unrelated meanings across 587 occurrences in
8
+ `src/`. The clearest single demonstration:
9
+
10
+ ```sh
11
+ skillmux target list --json
12
+ {"target":"local","data":{"targets":[{"name":"claude-code",...}]}}
13
+ ```
14
+
15
+ The outer `"target"` means "local versus a remote server". The inner
16
+ `"targets"` means "directories skills get delivered into". Same word, same
17
+ payload, unrelated concepts.
18
+
19
+ ### The four meanings
20
+
21
+ 1. **A delivery target.** A named directory recorded as `[targets.<name>]` in
22
+ the vault manifest. This is what `skillmux target` manages, what
23
+ `project --target <name>` references, what `sync` writes into, and what the
24
+ `.skillmux` marker records as `role: "target"`.
25
+ Types: `Target`, `ConfirmedTarget`, `AdoptTargetResult`,
26
+ `ResolvedBuiltInTarget`, `SyncTargetResult`, `SyncTargetOptions`,
27
+ `SyncTargetParams`, `SyncTargetSummary`, `SyncProjectTargetsParams`.
28
+
29
+ 2. **The execution destination.** Local process versus remote admin server,
30
+ selected by `--context`/`--server`.
31
+ Types: `TargetAdapter`, `TargetAdapterOptions`, `createTargetAdapter`,
32
+ `CommandTargetSupport`, `COMMAND_TARGET_SUPPORT`, the JSON envelope's
33
+ `target` field, `renderTargetBanner`, `LocalAdapter`'s `targetName: "local"`.
34
+
35
+ 3. **A file being scanned.** `ScanContentTarget` and `ResolvedScanTargets` in
36
+ `scan.ts`. Internal only, never user-facing.
37
+
38
+ 4. **An output file path.** `eval promote --target <path>`. User-facing.
39
+
40
+ ### Root cause
41
+
42
+ This is not four independent mistakes. Meaning 2 was already being renamed to
43
+ "context" in PR #163, and that rename stopped after `context.ts`. Everything
44
+ downstream still says target:
45
+
46
+ ```
47
+ src/context.ts:20 export type ResolvedContext renamed
48
+ src/adapters.ts:52 export interface TargetAdapter not renamed, same concept
49
+ src/cli.ts:281 let resolvedTarget: ResolvedContext variable and type disagree
50
+ src/cli.ts:97 COMMAND_TARGET_SUPPORT not renamed
51
+ ```
52
+
53
+ `cli.ts:281` is the clearest symptom: a variable named `resolvedTarget` holding
54
+ a `ResolvedContext`. The codebase has been sitting mid-rename since #163.
55
+
56
+ ## Decision
57
+
58
+ **Meaning 1 keeps the word "target".** It is the correct English use: the
59
+ destination a sync writes into. Everything else borrowed it.
60
+
61
+ Renaming `[targets.<name>]` to `[agents.<name>]` was considered and rejected.
62
+ Agents and targets are many-to-one, not one-to-one, and the manifest would
63
+ start asserting things that are false. Evidence:
64
+
65
+ ```sh
66
+ skillmux init --agent opencode --agent github-copilot --agent windsurf --yes
67
+ # produces exactly one target:
68
+ # agent-skills:
69
+ # dir: ~/.agents/skills
70
+ # agents: opencode, github-copilot, windsurf
71
+
72
+ skillmux target add my-scratch --dir ~/scratchdir --yes
73
+ # my-scratch:
74
+ # agents: (custom)
75
+ ```
76
+
77
+ `agent-skills` is not an agent, it is one shared directory serving three of
78
+ them. `my-scratch` belongs to no agent at all. Each target already carries its
79
+ own `agents` list as a field, so renaming the section would collide with that.
80
+
81
+ ## Plan
82
+
83
+ ### Step 1: finish the #163 rename (meaning 2 becomes "context")
84
+
85
+ Mostly mechanical, mostly internal.
86
+
87
+ | From | To |
88
+ |---|---|
89
+ | `TargetAdapter` | `ContextAdapter` |
90
+ | `TargetAdapterOptions` | `ContextAdapterOptions` |
91
+ | `createTargetAdapter` | `createContextAdapter` |
92
+ | `CommandTargetSupport` | `CommandContextSupport` |
93
+ | `COMMAND_TARGET_SUPPORT` | `COMMAND_CONTEXT_SUPPORT` |
94
+ | `renderTargetBanner` | `renderContextBanner` |
95
+ | `resolvedTarget` (variable) | `resolvedContext` |
96
+ | `emitSuccess({ target })` param | `emitSuccess({ context })` |
97
+
98
+ Critical constraint: meaning 1 also uses the identifier `targetName`, in
99
+ `init.ts`, `project.ts`, and `sync.ts`, where it means a delivery target name.
100
+ Those must not be touched. Only `adapters.ts`'s `targetName: "local"` belongs
101
+ to meaning 2. A blind find-and-replace on this codebase would corrupt the
102
+ manifest layer, which is exactly the disease being cured.
103
+
104
+ ### Step 2: the JSON envelope field, additively
105
+
106
+ The envelope's `target` field is public API and documented in `docs/cli.md`.
107
+ Renaming it outright is breaking, and the project is releasing 1.11.0, a minor.
108
+
109
+ Emit `context` alongside `target` with identical content, mark `target`
110
+ deprecated in code and docs, and remove it at the next major. This mirrors
111
+ what PR #177 did for the `init` envelope.
112
+
113
+ ### Step 3: rename meaning 3
114
+
115
+ `ScanContentTarget` becomes `ScanContentFile`, `ResolvedScanTargets` becomes
116
+ `ResolvedScanFiles`. Internal only, so no compatibility concern.
117
+
118
+ ### Step 4: `eval promote --target` becomes `--out`
119
+
120
+ A destination file path is defensible English on its own, but inside this CLI
121
+ "target" is a first-class noun you can `target list`. A `--target` that takes a
122
+ file path and cannot be listed, attached, or synced is the odd one out.
123
+
124
+ Add `--out <path>`, keep `--target` as a deprecated alias, remove the alias at
125
+ the next major.
126
+
127
+ ## End state
128
+
129
+ - **target** means a delivery directory, and nothing else.
130
+ - **context** means local versus remote.
131
+ - `scan` uses its own internal vocabulary.
132
+ - `eval promote` writes to `--out`.
133
+
134
+ ## Compatibility summary
135
+
136
+ | Change | Breaking? | Path |
137
+ |---|---|---|
138
+ | Steps 1 and 3 | No | Internal identifiers only |
139
+ | Step 2 | No | Additive, `target` deprecated |
140
+ | Step 4 | No | `--out` added, `--target` aliased |
141
+
142
+ ## Out of scope
143
+
144
+ Carried over from the earlier surface review, unchanged and still open:
145
+
146
+ - `scan --format json` bypasses the documented envelope.
147
+ - `install` is the only mutating command with no confirmation gate.
148
+ - `sync`, `install`, `update`, and `outdated` document none of their flags.
149
+ - The top-level help's `init` line omits `--show-mcp-setup`/`--register-mcp`.
@@ -0,0 +1,338 @@
1
+ # Skillmux Routing Reliability Plan
2
+
3
+ Status: approved for specification and implementation
4
+
5
+ ## Goal
6
+
7
+ Give Skillmux a predictable OSS configuration contract, a bounded ranking
8
+ pipeline, and visible inference failures. Measure routing behavior before adding
9
+ policy machinery. Ship one foundation release, then adopt it in Bifrost through
10
+ one infra change.
11
+
12
+ ## Problem
13
+
14
+ Skillmux accepts generic environment variables such as `EMBED_MODEL`. A parent
15
+ process can set the same name for another purpose. The inherited value then
16
+ overrides Skillmux's TOML file.
17
+
18
+ Skillmux also reranks the full lexical and vector union. With
19
+ `k_lexical = 15` and `k_vector = 15`, one request can send 30 documents to the
20
+ reranker. The current code catches inference errors and timeouts, then returns a
21
+ degraded retrieval result without the failure reason.
22
+
23
+ The production incident on 2026-08-17 demonstrated both failures. Bifrost's
24
+ `EMBED_MODEL` replaced the model in Skillmux's TOML file, so Infinity returned
25
+ HTTP 400. After environment isolation restored embeddings, a 10-second timeout
26
+ expired before the reranker finished. Infra PRs #45 and #46 restored production
27
+ with child-environment sanitization, smaller recall lanes, and a 30-second
28
+ timeout. Those changes remain safeguards until Bifrost adopts the release from
29
+ this plan.
30
+
31
+ A live reranked request also exposed a separate problem. For a bounded DNS
32
+ command, the semantic reranker placed the broad `cloudflare` mission skill above
33
+ the direct `infra-cli` executor. The result was relevant by topic but wrong by
34
+ operational ownership. This plan measures that failure class before deciding
35
+ whether Skillmux needs routing contracts.
36
+
37
+ ## Target Ranking Pipeline
38
+
39
+ The intended pipeline is:
40
+
41
+ 1. Resolve an exact skill ID or exact title match.
42
+ 2. Retrieve lexical and vector candidates.
43
+ 3. Fuse both ranked lists with reciprocal rank fusion (RRF).
44
+ 4. Send only the top `k_rerank` fused candidates to the semantic reranker.
45
+ 5. Apply routing-contract eligibility if the evidence gate justifies it.
46
+ 6. Apply calibrated decision thresholds and return `matched`, `ambiguous`, or
47
+ `no_match`.
48
+
49
+ RRF is the cheap candidate-generation stage. The reranker performs the more
50
+ expensive semantic comparison. `k_rerank` controls reranker input, while the
51
+ ambiguous candidate limit controls response output. They are separate budgets.
52
+
53
+ The foundation release stops after step 4 and improves the visibility of step
54
+ 6. Step 5 belongs to a later release unless the evaluation report proves that
55
+ ranking quality alone cannot enforce skill ownership.
56
+
57
+ ## Configuration Contract
58
+
59
+ Skillmux uses this precedence when environment overrides are enabled:
60
+
61
+ ```text
62
+ CLI flags
63
+ SKILLMUX_* environment variables
64
+ TOML configuration
65
+ defaults
66
+ ```
67
+
68
+ Skillmux must stop using generic `EMBED_*` and `RERANK_*` variables. The 1.x
69
+ line emits migration warnings. Skillmux 2.0 removes support.
70
+
71
+ Add this TOML policy:
72
+
73
+ ```toml
74
+ [config]
75
+ environment_overrides = true
76
+ ```
77
+
78
+ `true` remains the OSS default. `false` makes TOML authoritative for behavioral
79
+ settings. Skillmux must still read:
80
+
81
+ - `SKILLMUX_CONFIG`, which locates the TOML file
82
+ - secret variables named by `api_key_env`
83
+ - process variables required by the runtime, such as `HOME` and `PATH`
84
+ - explicit CLI flags for the current invocation
85
+
86
+ `SKILLMUX_CONFIG_READONLY` keeps its current meaning. It prevents admin API
87
+ writes to configuration managed outside Skillmux. It does not control
88
+ precedence.
89
+
90
+ ## Rerank Budget
91
+
92
+ Add `recall.k_rerank`:
93
+
94
+ ```toml
95
+ [recall]
96
+ k_lexical = 15
97
+ k_vector = 15
98
+ k_rerank = 5
99
+ ```
100
+
101
+ Skillmux retrieves each lane, fuses the results, truncates the fused list to
102
+ `k_rerank`, and sends that list to the reranker. Decision thresholds run on the
103
+ reranked list.
104
+
105
+ Validation rules:
106
+
107
+ - `k_lexical`, `k_vector`, and `k_rerank` are positive integers.
108
+ - `k_rerank` does not exceed `k_lexical + k_vector` after configuration loads.
109
+ - The default supports existing installations without an invalid config.
110
+ - The generated example and JSON schema state the default and limits.
111
+
112
+ Benchmark `k_rerank` values of 5, 10, 15, and 20. Choose the smallest OSS
113
+ default that meets the candidate-recall and latency gates. Bifrost must set the
114
+ measured value in TOML instead of copying an arbitrary value from the incident
115
+ mitigation.
116
+
117
+ The current `[thresholds].candidate_limit` name is vague because it controls
118
+ only the candidates returned for an ambiguous result. Introduce
119
+ `[output].ambiguous_candidate_limit` and keep the old key as a deprecated 1.x
120
+ alias. Remove the alias in 2.0 with the other configuration migrations.
121
+
122
+ ## Degraded Retrieval Contract
123
+
124
+ Keep safe fallback behavior. Add structured degradation metadata when a later
125
+ retrieval stage fails:
126
+
127
+ ```json
128
+ {
129
+ "outcome": "ambiguous",
130
+ "retrieval": "hybrid",
131
+ "degraded_from": "reranked",
132
+ "degradation_reason": "reranker_timeout",
133
+ "candidates": []
134
+ }
135
+ ```
136
+
137
+ Use stable reason codes:
138
+
139
+ - `embedding_timeout`
140
+ - `embedding_unavailable`
141
+ - `embedding_protocol_error`
142
+ - `reranker_timeout`
143
+ - `reranker_unavailable`
144
+ - `reranker_protocol_error`
145
+
146
+ Return safe codes through MCP. Write detailed errors to service logs. Add one
147
+ metric counter labelled by stage and reason. Audit rows must retain the safe
148
+ reason without storing credentials, response bodies, or endpoint URLs that may
149
+ contain credentials.
150
+
151
+ ## Implementation Work
152
+
153
+ ### Change 1: Configuration authority
154
+
155
+ Update the config types, defaults, TOML loader, environment override layer,
156
+ configuration provenance, JSON schema, CLI documentation, deployment examples,
157
+ and migration notes.
158
+
159
+ The loader must distinguish three inputs:
160
+
161
+ 1. Namespaced behavioral overrides such as `SKILLMUX_EMBED_MODEL`.
162
+ 2. Deprecated generic aliases such as `EMBED_MODEL`.
163
+ 3. Secret variables named by an `api_key_env` field.
164
+
165
+ When `environment_overrides = false`, the loader ignores category 1, warns for
166
+ category 2 during the 1.x migration window, and resolves category 3 at request
167
+ time. `config show --sources` and `doctor` must report the policy and the source
168
+ of each effective behavioral value.
169
+
170
+ ### Change 2: Bounded reranking
171
+
172
+ Add `k_rerank` to the recall type and schema. In `retrieveAndRerank`, fuse the
173
+ lexical and vector results, then slice the fused list before building reranker
174
+ documents. Preserve each candidate's skill ID, title, description, and score.
175
+
176
+ Calibration and evaluation must use the same cap as runtime. Dataset generation
177
+ must record the effective recall and rerank settings so a calibration run cannot
178
+ move between configurations without an error.
179
+
180
+ ### Change 3: Failure visibility
181
+
182
+ Replace broad inference catches with classification that maps
183
+ `RemoteInferenceError.kind`, timeouts, and transport failures to stable reason
184
+ codes. Preserve fallback. Return the degradation fields, write one structured
185
+ log entry, increment metrics, and store the safe code in the audit row.
186
+
187
+ Do not expose raw exception text through MCP.
188
+
189
+ ### Change 4: Routing evidence gate
190
+
191
+ Build a sequential labelled corpus that includes direct execution,
192
+ investigation, cross-system correlation, and non-match prompts. For every case,
193
+ record the fused rank, reranked rank, final outcome, latency, effective ranking
194
+ settings, and degradation state.
195
+
196
+ The foundation is acceptable when:
197
+
198
+ - the expected skill enters the reranker pool for direct and investigative
199
+ prompts
200
+ - at least 99 percent of evaluation cases complete without degraded retrieval
201
+ - p95 latency stays within the published service budget
202
+ - non-match prompts do not become confident false matches
203
+
204
+ If the expected skill reaches the reranker but loses on ownership despite
205
+ matching the topic, classify the case as an ownership failure. That result opens
206
+ the routing-contract phase. Retrieval misses, fusion-order errors, and reranker
207
+ errors remain ranking work.
208
+
209
+ ### Change 5: Routing contracts, gated follow-up
210
+
211
+ Do not implement this change in the foundation release. If the evidence gate
212
+ opens the phase, write a separate specification for generic skill metadata such
213
+ as:
214
+
215
+ ```yaml
216
+ routing:
217
+ accepts: [bounded_execution]
218
+ rejects: [investigation, cross_system_correlation]
219
+ ```
220
+
221
+ Apply eligibility after semantic reranking and before decision thresholds. If
222
+ the request intent is uncertain, return `ambiguous` instead of forcing a match.
223
+ The specification must define intent extraction, schema validation, conflicting
224
+ contracts, metadata provenance, audit output, and compatibility for skills with
225
+ no routing metadata. It must not encode provider names or special cases in the
226
+ Skillmux engine.
227
+
228
+ ## Acceptance Criteria
229
+
230
+ 1. A generic `EMBED_MODEL` cannot change the effective model without a 1.x
231
+ deprecation warning. Skillmux 2.0 rejects or ignores it according to the
232
+ published migration contract.
233
+ 2. `SKILLMUX_EMBED_MODEL` overrides TOML when
234
+ `config.environment_overrides = true`.
235
+ 3. TOML wins when `config.environment_overrides = false`.
236
+ 4. `api_key_env` resolves its named secret under both policies.
237
+ 5. `config show --sources` and `doctor` identify the override policy and each
238
+ behavioral value's source.
239
+ 6. Runtime sends no more than `k_rerank` documents to the reranker.
240
+ 7. Lexical and vector retrieval still use their configured lane sizes before
241
+ fusion and truncation.
242
+ 8. Calibration and runtime use the same `k_rerank` value.
243
+ 9. An embedding failure returns lexical retrieval with the correct safe reason.
244
+ 10. A reranker timeout returns hybrid retrieval with
245
+ `degraded_from = "reranked"` and `reranker_timeout`.
246
+ 11. Successful inference returns `retrieval = "reranked"` without degradation
247
+ fields.
248
+ 12. Logs, metrics, and audit rows record the failure class without secret data.
249
+ 13. Existing installations with no new settings load a documented default.
250
+ 14. The full unit, CLI, MCP, doctor, calibration, and Docker smoke suites pass.
251
+ 15. Evaluation output records each candidate's fused rank, reranked rank, final
252
+ outcome, latency, ranking settings, and degradation state.
253
+ 16. Routing contracts cannot enter the foundation release. A separate
254
+ specification starts only when the evidence gate identifies ownership
255
+ failures.
256
+ 17. `ambiguous_candidate_limit` controls ambiguous response output and the old
257
+ `candidate_limit` alias emits the documented 1.x migration warning.
258
+
259
+ ## Test Plan
260
+
261
+ Add focused tests before each behavior change:
262
+
263
+ - config precedence matrix for TOML, namespaced environment, generic aliases,
264
+ strict policy, and CLI flags
265
+ - secret resolution under both environment policies
266
+ - provenance and doctor output
267
+ - `k_rerank` validation and request-document count
268
+ - ambiguous output-limit migration and behavior
269
+ - calibration metadata compatibility
270
+ - timeout, availability, and protocol fallback codes
271
+ - MCP response, audit row, structured log, and metric output
272
+ - Docker smoke coverage with a polluted parent environment
273
+ - ownership-versus-relevance fixtures where executor and mission skills share a
274
+ provider topic
275
+
276
+ Use fake inference clients for deterministic unit tests. Add one HTTP adapter
277
+ integration test that verifies cancellation and timeout classification.
278
+
279
+ ## Compatibility and Release
280
+
281
+ Ship the foundation work in reviewable PRs, then publish one release:
282
+
283
+ 1. Configuration authority and migration warnings.
284
+ 2. Rerank budget and calibration metadata.
285
+ 3. Degradation responses, logs, metrics, and audit data.
286
+ 4. Documentation, examples, and release notes.
287
+ 5. Sequential evaluation report and selected defaults.
288
+
289
+ Do not publish an intermediate GHCR image for Bifrost. Merge the full set,
290
+ release one Skillmux version through GitHub Actions, and verify the image digest
291
+ and smoke tests before changing infra.
292
+
293
+ Routing contracts use a second release. Start that work only after the
294
+ foundation is running in Bifrost and the evidence report passes the gate.
295
+
296
+ ## Bifrost Adoption
297
+
298
+ Create one follow-up PR in `klhq/infra` after the GHCR release:
299
+
300
+ - update the pinned Skillmux GHCR version
301
+ - set `config.environment_overrides = false`
302
+ - restore `k_lexical = 15` and `k_vector = 15`
303
+ - set `k_rerank` to the measured value from the foundation evaluation
304
+ - retain `timeout_ms = 30000` for the first deployment
305
+ - set `SKILLMUX_CONFIG_READONLY=true`
306
+ - remove unused `SKILLMUX_EMBED_KEY`
307
+ - keep wrapper sanitization for one release as defense in depth
308
+
309
+ Deploy through the Bifrost Forgejo workflow and Komodo. Verify the child
310
+ environment, `doctor`, one live reranked request, and the sequential training
311
+ corpus. Keep wrapper sanitization until strict config mode has production
312
+ evidence, then remove it in a later infra change.
313
+
314
+ Classify the sequential report before opening more implementation work:
315
+
316
+ - retrieval, fusion, or reranker failures return to the ranking pipeline
317
+ - ownership failures open the routing-contract specification
318
+ - a clean report freezes a fresh v2 held-out corpus for later regression tests
319
+
320
+ ## Out of Scope
321
+
322
+ - New embedding or reranker models
323
+ - Threshold calibration for the infra routing corpus
324
+ - Mission-skill renames
325
+ - Removal of generic aliases before the documented major release
326
+ - Provider-specific ownership rules hard-coded in Skillmux
327
+ - Routing-contract implementation inside the foundation release
328
+
329
+ ## Handoff
330
+
331
+ Implement the foundation work in `klhq/skillmux`. Keep configuration authority,
332
+ bounded reranking, failure visibility, and evaluation support in separate
333
+ commits or PRs. Publish one foundation release. Do not edit `klhq/infra` until
334
+ Skillmux publishes that release and its GHCR smoke tests pass.
335
+
336
+ After Bifrost produces the sequential report, apply the evidence gate. If it
337
+ shows ownership failures, create a separate routing-contract specification and
338
+ release plan. Do not fold that design into the foundation implementation.
@@ -0,0 +1,124 @@
1
+ # Review: Configuration Authority and Rerank Resilience
2
+
3
+ Verdict: Code findings resolved. Release evidence remains pending.
4
+
5
+ ## Remediation
6
+
7
+ The 2026-08-17 fix pass resolved findings 1 through 4 and finding 6:
8
+
9
+ - evaluation now uses the production retrieval, RRF, reranker, degradation,
10
+ and decision functions
11
+ - fused and reranked ranks come from the same execution that produces the
12
+ recorded outcome
13
+ - degradation logs no longer contain the raw query
14
+ - calibration evidence persists effective recall settings, and doctor marks a
15
+ run stale when those settings drift
16
+ - doctor receives and reports behavioral configuration provenance
17
+ - strict mode tests cover `SKILLMUX_CONFIG` and `SKILLMUX_CONFIG_READONLY`
18
+
19
+ Finding 5 is release evidence, not a code defect. Run the sequential corpus at
20
+ `k_rerank` values 5, 10, 15, and 20 against the deployed inference service.
21
+ Select the default only after candidate recall, p95 latency, degradation rate,
22
+ and non-match safety meet the gates in the approved plan.
23
+
24
+ Reviewed `main...feat/config-authority-rerank-resilience` against `spec.md` and
25
+ the approved routing reliability plan. Runtime tests pass, but the evaluation
26
+ contract and several observability requirements are incomplete.
27
+
28
+ ## Findings
29
+
30
+ ### 1. High: Evaluation output does not execute the runtime ranking pipeline
31
+
32
+ `src/eval.ts:99` builds lexical and vector results itself. It never calls the
33
+ configured reranker or the decision function. At `src/eval.ts:126`, every case
34
+ is recorded as `outcome: "ambiguous"` and `retrieval: "hybrid"` regardless of
35
+ the real result. `reranked_rank` is declared but never populated, and
36
+ degradation fields cannot be produced by this path.
37
+
38
+ This does not satisfy AC 4.1 and cannot distinguish a retrieval miss, reranker
39
+ failure, threshold error, or ownership failure. Reuse the production retrieval
40
+ and decision path, or extract one shared instrumented pipeline that returns
41
+ fused rank, reranked rank, outcome, latency, and degradation data.
42
+
43
+ ### 2. High: Degradation logs copy the raw user query
44
+
45
+ `src/router-core.ts:558` and `src/router-core.ts:585` write `input.query` into
46
+ service logs when inference fails. A query may contain a credential, signed
47
+ URL, customer data, or other sensitive input. This conflicts with AC 3.3's safe
48
+ sanitization requirement and creates a new disclosure path outside the audit
49
+ store.
50
+
51
+ Remove the raw query from these warning records. Log a request or audit ID,
52
+ stage, safe reason code, and timing instead. If query logging is a supported
53
+ operator feature, it needs an explicit redaction and retention policy.
54
+
55
+ ### 3. Medium: Calibration evidence omits the effective ranking settings
56
+
57
+ The branch adds `recall_settings` only to `src/eval.ts`. The calibration and
58
+ dataset evidence paths contain no `k_lexical`, `k_vector`, or `k_rerank`
59
+ metadata. This leaves AC 2.3 incomplete and permits a calibration artifact to be
60
+ applied under a different candidate budget without detecting the mismatch.
61
+
62
+ Persist the effective recall settings with calibration and dataset evidence.
63
+ Reject or mark stale any run whose settings differ from runtime.
64
+
65
+ ### 4. Medium: Doctor reports policy but not value provenance
66
+
67
+ `src/doctor.ts:111` adds one `config_authority` check. It does not report the
68
+ source of each behavioral value as required by AC 1.5. `config show --sources`
69
+ has a source map, but doctor does not expose equivalent provenance.
70
+
71
+ Share the effective-source map with doctor and report at least every supported
72
+ behavioral override. Include `server.allowed_origins`, which is recognized by
73
+ `isEnvMasked` but absent from the source-map key list at
74
+ `src/config-service.ts:146`.
75
+
76
+ ### 5. Medium: The foundation evidence gate and selected default are absent
77
+
78
+ The approved plan requires benchmarks for `k_rerank` values 5, 10, 15, and 20,
79
+ a sequential labelled evaluation report, and a selected default backed by the
80
+ candidate-recall and latency gates. The branch hard-codes a default of 10 and
81
+ contains no benchmark or sequential report.
82
+
83
+ Complete the evaluation implementation first. Then check in the reproducible
84
+ report or release evidence that selects the OSS default.
85
+
86
+ ### 6. Low: Strict-mode exempt controls lack combined coverage
87
+
88
+ The suite tests `SKILLMUX_CONFIG` and `SKILLMUX_CONFIG_READONLY` in other
89
+ contexts, but it does not verify that both remain effective when
90
+ `config.environment_overrides = false`. Add one strict-mode integration test
91
+ covering these exemptions.
92
+
93
+ ## Verification
94
+
95
+ - `bun test`: PASS, 644 passed and 0 failed
96
+ - `git diff --check main...HEAD`: PASS
97
+ - Build check: SKIPPED, no build command was supplied to the review recipe
98
+ - Performance pass: no finding
99
+ - Security, correctness, and compliance delegated passes hit a temporary model
100
+ rate limit and were completed manually
101
+
102
+ ## AC Status
103
+
104
+ | Criterion | Status | Notes |
105
+ |---|---|---|
106
+ | AC 1.1 Precedence and policy | ✅ Done | Namespaced environment overrides follow the configured policy. |
107
+ | AC 1.2 Strict TOML mode | ✅ Done | Behavioral overrides are ignored in strict mode. |
108
+ | AC 1.3 Exempt variables | ✅ Done | Strict mode covers config location, read-only control, and secret resolution. |
109
+ | AC 1.4 Generic environment and deprecated keys | ✅ Done | Migration warnings and aliases are implemented. |
110
+ | AC 1.5 Provenance and diagnostics | ✅ Done | Config show and doctor report behavioral value sources. |
111
+ | AC 1.6 Output candidate limit | ✅ Done | New output key controls ambiguous results with a legacy alias. |
112
+ | AC 2.1 Schema and validation | ✅ Done | `k_rerank` is typed, defaulted, and bounded against both lanes. |
113
+ | AC 2.2 Runtime fusion and truncation | ✅ Done | The fused list is truncated before reranker input. |
114
+ | AC 2.3 Calibration and evaluation alignment | ✅ Done | Calibration evidence stores recall settings and doctor detects drift. |
115
+ | AC 3.1 Stable error codes | ✅ Done | Error classes map to the specified codes. |
116
+ | AC 3.2 Safe fallback and metadata | ✅ Done | Embedding and reranker failures preserve a surviving lane. |
117
+ | AC 3.3 MCP and safe sanitization | ✅ Done | Failure logs contain safe stage and reason fields without the raw query. |
118
+ | AC 4.1 Evaluation case output | ✅ Done | Evaluation uses production ranking and records actual ranks, outcome, and degradation. |
119
+
120
+ ## Security Escalation
121
+
122
+ A dedicated security review is recommended before shipping because the change
123
+ touches remote network egress, credentials referenced through environment
124
+ variables, public MCP response fields, and persistent audit data.