weavatrix 0.2.12 → 0.2.13

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/README.md CHANGED
@@ -194,6 +194,13 @@ Advanced registrations may still pass an exact comma-separated capability set:
194
194
  a compatibility alias for `advisories,hosted`; new registrations should use the named profiles or
195
195
  the narrower capability names.
196
196
 
197
+ After an upgrade, reconnect the MCP server or start a new agent task before checking its tool list:
198
+ many clients snapshot `tools/list` and input schemas for the lifetime of one connection. The expected
199
+ counts are 31 for `pinned`, 34 for `offline`, 35 for `osv`, and all 38 for `hosted` / `full`. A custom
200
+ capability list must include `crossrepo` to expose `trace_api_contract`; `online` alone adds only the
201
+ legacy advisory/Hosted groups. `graph_stats` reports the running package version, enabled capabilities
202
+ and registered-tool count so a cached process can be distinguished from the installed package.
203
+
197
204
  Or clone it:
198
205
 
199
206
  ```sh
@@ -342,6 +349,24 @@ reconnect. Every MCP response also carries local, transient `_meta["weavatrix/me
342
349
  time, output bytes/token estimate, graph freshness/revision/update and graph-cache status. These
343
350
  metrics are not persisted or transmitted by Weavatrix.
344
351
 
352
+ ### 0.2.13 runtime-integrity and cross-language verification patch
353
+
354
+ - `verified_change` no longer requires `package.json` when no package tests can run. Python, Go,
355
+ Java, Rust and other non-Node repositories now receive `NOT_REQUESTED` or `DISABLED` test evidence
356
+ instead of a false `BLOCKED`; actual package-script execution keeps the same double opt-in and
357
+ allowlist.
358
+ - Release verification starts the packed npm artifact and portable MCPB stage over stdio. It asserts
359
+ the exact profile counts and required 38-tool `full` surface, including `trace_endpoint`,
360
+ `trace_api_contract` and `preview_sync`, so source/package drift cannot publish silently.
361
+ - Runtime diagnostics expose the package version, selected capability groups and registered tool
362
+ count. The documentation now distinguishes an old client connection from an intentional profile
363
+ omission and explains that custom capabilities need `crossrepo` for contract tracing.
364
+ - The bundled skill documents practical CLI/worker/event flows, local target-architecture adoption,
365
+ repository classification, undirected path semantics and the correct release and proof-carrying
366
+ change recipes without reducing Weavatrix to text search.
367
+
368
+ Full patch notes: [docs/releases/v0.2.13.md](docs/releases/v0.2.13.md).
369
+
345
370
  ### 0.2.9 correctness, signal, and consent patch
346
371
 
347
372
  - Express endpoint inventory composes nested imported `router.use(...)` mounts, so a local route such
@@ -0,0 +1,48 @@
1
+ # Weavatrix 0.2.13
2
+
3
+ ## Runtime-integrity and cross-language verification patch
4
+
5
+ 0.2.13 closes two failures found by dogfooding the live MCP on real JavaScript and Python
6
+ applications. A live client could keep an older tool/schema snapshot after the checkout had advanced,
7
+ and `verified_change` treated the absence of a Node manifest as a blocker even when no package test
8
+ was requested. Neither failure is converted into a cosmetic pass: incomplete architecture, coverage,
9
+ API or test evidence still produces `UNKNOWN` where appropriate.
10
+
11
+ ### Cross-language `verified_change`
12
+
13
+ - An empty test request returns `NOT_REQUESTED` before looking for `package.json`.
14
+ - Requested package tests with `run_tests:false` return `DISABLED` without pretending that they ran
15
+ or blocking a Python/Go/Java/Rust repository for lacking an npm manifest.
16
+ - Actual execution still requires both `run_tests:true` and `WEAVATRIX_ALLOW_TEST_RUNS=1`, accepts
17
+ only existing test/check/verify package scripts and rejects shell-sensitive arguments.
18
+ - Regression coverage exercises both plan and verify phases against a Python-only repository.
19
+
20
+ ### Packed-runtime and live-tool integrity
21
+
22
+ - Release verification runs the packed npm artifact and portable MCPB stage as real stdio servers.
23
+ - The smoke gate asserts 34 tools for the offline profile and all 38 for `hosted` / `full`, including
24
+ `trace_endpoint`, `trace_api_contract` and the local-only `preview_sync` approval step.
25
+ - `graph_stats` and initialization diagnostics identify the running package version, enabled
26
+ capabilities and registered tool count. This separates an old client connection from a deliberately
27
+ restricted profile.
28
+ - Existing security boundaries are unchanged: `offline` remains the no-HTTP default; `online` stays
29
+ a compatibility alias for `advisories,hosted`; `crossrepo` is not silently added to a custom list;
30
+ and no network tool is made available by default.
31
+
32
+ MCP clients commonly snapshot `tools/list` for one connection. After upgrading, reconnect or start a
33
+ new task. Expected counts are 31 (`pinned`), 34 (`offline`), 35 (`osv`) and 38 (`hosted` / `full`).
34
+
35
+ ### Skill and architecture workflow
36
+
37
+ The bundled skill now covers non-HTTP entrypoints (CLI, worker, queue, cron and events), explains how
38
+ to review and save a local starter contract, establish an explicit ratchet baseline, apply a reviewed
39
+ exception, and classify generated/test/resource trees through `.weavatrix.json`. It also labels
40
+ `shortest_path` as undirected connectivity rather than directional call proof, uses the correct
41
+ `change_impact base` parameter, and avoids redundant symbol-context calls.
42
+
43
+ ## Compatibility
44
+
45
+ - The 38 tool names, input schemas and `weavatrix.tool.v1` result envelope remain compatible.
46
+ - Hosted sync payload v2/v3, confirmation-token consent and architecture-contract transport are
47
+ unchanged; no hosted application change is required.
48
+ - The public MIT license and local-first network boundary are unchanged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weavatrix",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "type": "module",
5
5
  "description": "Local repository intelligence MCP for AI coding agents: reusable architecture graph for fast application understanding, Health, dead code, clones, history, blast radius and architecture safeguards.",
6
6
  "author": "Sergii Ziborov <sergii.ziborov@gmail.com>",
@@ -26,7 +26,7 @@
26
26
  "skill",
27
27
  "scripts/run-agent-task-benchmark.mjs",
28
28
  "docs/agent-task-benchmark.md",
29
- "docs/releases/v0.2.12.md",
29
+ "docs/releases/v0.2.13.md",
30
30
  "README.md",
31
31
  "SECURITY.md",
32
32
  "LICENSE"
package/skill/SKILL.md CHANGED
@@ -16,15 +16,20 @@ Tools are named `mcp__weavatrix__…`. If none are available, ask the user to re
16
16
  (`claude mcp add -s user weavatrix -- npx -y weavatrix <repoRoot>`; Codex:
17
17
  `codex mcp add weavatrix -- npx -y weavatrix <repoRoot>`), then retry.
18
18
 
19
- If `refresh_advisories`, `preview_sync`, `pull_architecture_contract`, or `sync_graph` is missing, do not diagnose a
20
- broken installation: network tools are intentionally absent from `offline` and `pinned`.
19
+ First compare the selected profile with the `graph_stats` runtime line. Expected catalogs are 31
20
+ tools for `pinned`, 34 for `offline`, 35 for `osv`, and 38 for `hosted` / `full`. If the running
21
+ version/count differs from the installed package, or local tools such as `trace_endpoint` are missing,
22
+ reconnect/start a new agent task because clients commonly cache `tools/list` for one connection. A
23
+ custom capability list needs `crossrepo` for `trace_api_contract`; legacy `online` adds only
24
+ `advisories,hosted`. Missing HTTP tools are intentional only when the selected profile excludes them.
21
25
 
22
26
  Profiles use the same npm package and binary:
23
27
 
24
28
  - `offline` (default): all local analysis and explicit `open_repo`; no HTTP tools.
25
29
  - `pinned`: local analysis with no `open_repo`, no global/cross-repository graph access, and no HTTP tools.
26
30
  - `osv`: `offline` plus explicit `refresh_advisories`.
27
- - `hosted` / `full`: `osv` plus local-only `preview_sync`, `pull_architecture_contract` and `sync_graph`.
31
+ - `hosted` / `full`: `osv` plus local-only `preview_sync` and the explicitly invoked network tools
32
+ `pull_architecture_contract` and confirmed `sync_graph`.
28
33
 
29
34
  The legacy `online` capability remains a compatibility alias for `advisories,hosted`; prefer the
30
35
  named profiles for new registrations.
@@ -45,7 +50,9 @@ projection; expand only when the answer requires it.
45
50
  - **Find high-coupling hubs**: `god_nodes`; repeated call sites do not inflate unique connectivity.
46
51
  - **Inspect one graph entity**: `get_node`; pass an exact node ID when labels are ambiguous.
47
52
  - **Inspect direct one-hop relations**: `get_neighbors`; do not confuse it with transitive impact.
48
- - **Prove a path between two concepts**: `shortest_path`.
53
+ - **Find a connectivity path between two concepts**: `shortest_path`. It traverses the graph as
54
+ undirected reachability, so it is not proof of call/dependency direction; confirm direction with
55
+ `get_neighbors` and `read_source`.
49
56
  - **Explore an unknown entry point or architectural question**: `query_graph`; pin `seed_files` when
50
57
  known, and keep its broad result as orientation evidence.
51
58
  - **Inspect one exact symbol deeply**: `context_bundle` for the bounded edit workset;
@@ -63,15 +70,17 @@ projection; expand only when the answer requires it.
63
70
  a backend change may affect registered clients, and inspect each graph reconciliation state before
64
71
  using the verdict.
65
72
  - **Measure one symbol's transitive blast radius**: `get_dependents`.
66
- - **Review the current branch, diff, or external patch**: `change_impact`; it distinguishes additive
67
- exports from signature/body/removal risk and separates runtime/type-only radius plus available
68
- measured coverage or explicitly static reachability.
73
+ - **Review the current branch, diff, or external patch**: `change_impact`; its explicit baseline
74
+ parameter is `base`, not the `base_ref` used by audit/diff/verification tools. It distinguishes
75
+ additive exports from signature/body/removal risk and separates runtime/type-only radius plus
76
+ available measured coverage or explicitly static reachability.
69
77
  - **Compare structural graph revisions**: `graph_diff base_ref=<merge-base>` for module edges, cycles,
70
78
  orphans and lost callers; without `base_ref`, compare the last rebuild snapshots.
71
79
  - **Use behavioral history**: `git_history` for churn x connectivity, hidden co-change and expected
72
80
  test/source coupling from bounded local Git numstat evidence.
73
- - **Plan and verify a serious change or pre-commit gate**: `verified_change phase=plan` -> edit ->
74
- `verified_change phase=verify base_ref=<same-ref>`. It composes exact context, impact, graph,
81
+ - **Plan and verify a serious change or pre-commit gate**:
82
+ `verified_change task=<same-task> phase=plan base_ref=<merge-base>` -> edit ->
83
+ `verified_change task=<same-task> phase=verify base_ref=<same-ref>`. It composes exact context, impact, graph,
75
84
  architecture, duplicate, optional API and test proof into one PASS/BLOCKED/UNKNOWN envelope. It is
76
85
  a proof layer around an agent's edit, not a source editor or hidden auto-fix.
77
86
 
@@ -101,7 +110,8 @@ projection; expand only when the answer requires it.
101
110
  - **Select rules before editing**: `prepare_change`; **enforce the ratchet after editing**:
102
111
  `verify_architecture`.
103
112
  - **Understand or request an exception**: `explain_architecture_violation` ->
104
- `propose_architecture_exception`; proposals never mutate policy automatically.
113
+ `propose_architecture_exception`; proposals never mutate policy automatically. After human approval,
114
+ the owner must add the returned proposal to the local contract's `exceptions` or approve it in Hosted.
105
115
  - **Pull an owner-approved Hosted target**: `pull_architecture_contract` only in an explicitly enabled
106
116
  Hosted profile.
107
117
  - **Review exactly what Hosted sync would send**: `preview_sync`; only an approved
@@ -195,17 +205,19 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
195
205
 
196
206
  ## Recipes
197
207
 
198
- - **Proof-carrying refactor**: `verified_change task="..." phase=plan base_ref=<merge-base>` -> edit ->
199
- `verified_change task="..." phase=verify base_ref=<same-ref> tests=[{"script":"test","args":[...]}]`.
208
+ - **Proof-carrying refactor**: `verified_change task=<same-task> phase=plan base_ref=<merge-base>` -> edit ->
209
+ `verified_change task=<same-task> phase=verify base_ref=<same-ref> tests=[{"script":"test","args":[...]}]`.
210
+ Repeat `task` on both calls; it is required and is not retained between invocations.
200
211
  Add `run_tests:true` only when test execution was authorized. `BLOCKED` means an evidenced ratchet
201
212
  or test failure; `UNKNOWN` means at least one required proof is incomplete.
202
213
 
203
214
  - **Orient in the configured repo**: `module_map` → `list_communities` → `god_nodes`. Hub ranking
204
215
  is production-only by default; use `include_classified:true` only when tests/generated/build
205
216
  surfaces are deliberately part of the question.
206
- - **Refactor safety for one symbol**: `inspect_symbol` → `context_bundle` `get_dependents`
217
+ - **Refactor safety for one symbol**: `context_bundle` → optional `inspect_symbol` when raw LSP
218
+ occurrences, ambiguity details or the larger source window are needed → `get_dependents` →
207
219
  `coverage_map` (low coverage × many dependents ⇒ write tests first) → edit →
208
- `verified_change phase=verify base_ref=<merge-base>`.
220
+ `verified_change task=<task> phase=verify base_ref=<merge-base>`.
209
221
  - **Performance review**: `hot_path_review` → inspect its local evidence with `read_source` → use
210
222
  `get_dependents` for change risk → confirm with the repository's profiler/benchmark before editing.
211
223
  - **Pre-PR review of your current changes**: `change_impact` (auto merge-base; includes uncommitted
@@ -238,6 +250,10 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
238
250
  - **API inventory**: `list_endpoints` (including mount provenance, Next.js App Router, Rust axum and
239
251
  actix-web). When one exact route is known, use `trace_endpoint` for its composed mount chain,
240
252
  handler and bounded production call graph instead of broad natural-language traversal.
253
+ - **CLI, worker, queue, cron or event flow**: locate the manifest/registration literal with
254
+ `search_code`, then pin the discovered entry file with `query_graph seed_files=[...]`; use
255
+ `context_bundle` on its exact handler plus `get_neighbors` / `get_dependents`, and confirm the
256
+ registration and call sites with `read_source`. Do not force a non-HTTP flow through endpoint tools.
241
257
  - **Cross-repository API impact**: ensure both repositories are in `list_known_repos`, then call
242
258
  `trace_api_contract backend=<uuid-or-label> clients=[<uuid-or-label>]`; narrow with `method`, `path`,
243
259
  or backend `changed_files`. `path` may be a segment-aligned fragment (`/query` can select
@@ -248,8 +264,9 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
248
264
  confidence; only an unambiguously resolved handler node can suppress a dead-method candidate.
249
265
  `POSSIBLE_EXTERNAL_USE`, `UNKNOWN`, and remaining unresolved/dynamic URLs are incomplete evidence,
250
266
  never proof that a method is dead.
251
- - **Release regression gate**: for a Weavatrix source checkout, use `npm test` for the quick
252
- six-language golden corpus and `npm run benchmark` before release for the real MCP
267
+ - **Release regression gate**: for a Weavatrix source checkout, use `npm test` for the full
268
+ unit/integration suite, `npm run benchmark:quick` for the quick six-language golden corpus, and
269
+ `npm run benchmark` before release for the golden corpus plus the real MCP
253
270
  `full -> incremental -> none -> reconnect/none` lifecycle, bounded output and active-target checks.
254
271
  Use `npm run benchmark:real` for available manifest repositories and
255
272
  `npm run benchmark:real:release` only when all six source checkouts are present; `MISSING`,
@@ -259,16 +276,25 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
259
276
  - **Target architecture before editing**: `get_architecture_contract` → `prepare_change` with the
260
277
  intended files → edit and rebuild → `verify_architecture`. A missing contract returns a starter
261
278
  proposal from `get_architecture_contract output_format:"json"`, not an automatically approved
262
- architecture. Without a contract, `prepare_change` still returns provisional no-regression
263
- budgets, but they are guidance rather than enforceable policy. Pull an owner-approved hosted
264
- contract only when the user selected `hosted` and explicitly asks for it.
279
+ architecture. For offline adoption, have the owner review/edit `starterContract`, save it as
280
+ `.weavatrix/architecture.json`, and rerun the lookup. To establish a ratchet over accepted current
281
+ debt, run `verify_architecture output_format:"json"`; only after explicit owner approval, copy the
282
+ accepted `verification.new[*].fingerprint` values into `ratchet.baseline.fingerprints`, save, and
283
+ verify again so accepted debt is `existing` while later debt is `new`. The v1 verifier classifies
284
+ ratchet debt by fingerprints; `ratchet.baseline.metrics` is metadata, not a replacement. An approved local exception
285
+ is applied by adding the exact returned `proposal` to `exceptions`; rerun verification afterward.
286
+ Without a contract, `prepare_change` still returns provisional no-regression budgets, but they are
287
+ guidance rather than enforceable policy. Pull an owner-approved hosted contract only when the user
288
+ selected `hosted` and explicitly asks for it. No Weavatrix tool silently writes either policy.
265
289
  - **Behavioral architecture**: `git_history` ranks churn × connectivity hotspots and hidden
266
290
  co-change coupling from bounded local numstat history. Always set `top_n`; it is enforced across
267
291
  every returned structured collection and JSON reports per-collection truncation. Use it as review
268
292
  evidence, not proof that two files must be merged.
269
293
  - **Machine output**: keep the default `output_format:"text"` for concise agent conversations; opt
270
294
  into `output_format:"json"` only when a workflow consumes the full `weavatrix.tool.v1` envelope.
271
- - **Find code**: `search_code` (regex + glob) → `get_node` → `read_source`.
295
+ - **Find code**: `search_code` (regex + glob) →
296
+ `read_source path=<match-path> start_line=<match-line>`; add `get_node` / `get_neighbors` only after
297
+ identifying an exact graph symbol.
272
298
  - **Another repo**: `list_known_repos` → `open_repo <path>`
273
299
  (builds or upgrades the graph when needed; `build:false` probes without building).
274
300
 
@@ -276,9 +302,29 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
276
302
 
277
303
  Weavatrix understands nearest workspace manifests, nested `tsconfig`/`jsconfig` aliases,
278
304
  framework-owned runtime peers such as Next.js + `react-dom`, generated NAPI-RS platform loaders,
279
- and Next.js App Router route exports. For project-specific entry points, reusable template catalogs,
280
- or Python dependencies supplied by an external runtime, add `.weavatrix-deps.json` at the repository
281
- root:
305
+ and Next.js App Router route exports. Use repository-root `.weavatrix.json` to correct ambiguous
306
+ production classification without deleting graph evidence:
307
+
308
+ ```json
309
+ {
310
+ "classify": {
311
+ "generated": ["src/generated/**"],
312
+ "test": ["qa/**"],
313
+ "product": ["benchmarks/core/**"]
314
+ },
315
+ "exclude": ["resources/snapshots/**"]
316
+ }
317
+ ```
318
+
319
+ Use `generated` / `test` (or `e2e`, `mock`, `story`, `docs`, `benchmark`, `temp`) for non-production
320
+ code, top-level `exclude` for resource/catalog roots that should stay visible in the graph but not
321
+ drive production-first Health/query ranking, and `product` only to opt a verified benchmark/temp path
322
+ back into production review. `product` does not override an explicit generated/test classification or
323
+ `exclude`. Use `.weavatrixignore` instead only when a path must be removed consistently from graph,
324
+ audit and duplicate scans.
325
+
326
+ For project-specific entry points, reusable template catalogs, or Python dependencies supplied by an
327
+ external runtime, add `.weavatrix-deps.json` at the repository root:
282
328
 
283
329
  ```json
284
330
  {
@@ -19,29 +19,40 @@ function packageManager(repoRoot) {
19
19
  return 'npm'
20
20
  }
21
21
 
22
- export function validateTestRequests(repoRoot, requests = []) {
23
- const manifest = manifestAt(repoRoot)
24
- if (!manifest) return {ok: false, reason: 'package.json is missing or unreadable', tests: []}
22
+ function normalizeTestRequests(requests = []) {
25
23
  const tests = []
26
- for (const request of requests.slice(0, 5)) {
24
+ for (const request of (Array.isArray(requests) ? requests : []).slice(0, 5)) {
27
25
  const script = String(request?.script || '')
28
26
  const args = Array.isArray(request?.args) ? request.args.slice(0, 40).map(String) : []
29
27
  if (!SAFE_SCRIPT.test(script)) return {ok: false, reason: `script ${script || '(missing)'} is outside the test/check/verify allowlist`, tests}
30
- if (!Object.hasOwn(manifest.scripts || {}, script)) return {ok: false, reason: `package.json has no script named ${script}`, tests}
31
28
  if (args.some((arg) => arg.length > 300 || UNSAFE_SHELL_ARG.test(arg))) return {ok: false, reason: `script ${script} has an invalid or shell-sensitive argument`, tests}
32
29
  tests.push({script, args})
33
30
  }
31
+ return {ok: true, tests}
32
+ }
33
+
34
+ export function validateTestRequests(repoRoot, requests = []) {
35
+ const normalized = normalizeTestRequests(requests)
36
+ if (!normalized.ok || !normalized.tests.length) return normalized
37
+ const manifest = manifestAt(repoRoot)
38
+ if (!manifest) return {ok: false, reason: 'package.json is missing or unreadable', tests: []}
39
+ for (const test of normalized.tests) {
40
+ if (!Object.hasOwn(manifest.scripts || {}, test.script)) return {ok: false, reason: `package.json has no script named ${test.script}`, tests: []}
41
+ }
42
+ const tests = normalized.tests
34
43
  return {ok: true, tests, packageManager: packageManager(repoRoot)}
35
44
  }
36
45
 
37
46
  export async function runAllowedTests(repoRoot, requests = [], {enabled = false, timeoutMs = 60_000} = {}) {
38
- const checked = validateTestRequests(repoRoot, requests)
39
- if (!checked.ok) return {state: 'BLOCKED', reason: checked.reason, results: []}
40
- if (!checked.tests.length) return {state: 'NOT_REQUESTED', reason: 'no package scripts were requested', results: []}
47
+ const normalized = normalizeTestRequests(requests)
48
+ if (!normalized.ok) return {state: 'BLOCKED', reason: normalized.reason, results: []}
49
+ if (!normalized.tests.length) return {state: 'NOT_REQUESTED', reason: 'no package scripts were requested', plan: [], results: []}
41
50
  if (!enabled || process.env.WEAVATRIX_ALLOW_TEST_RUNS !== '1') return {
42
51
  state: 'DISABLED', reason: 'set WEAVATRIX_ALLOW_TEST_RUNS=1 and pass run_tests:true to execute allowlisted package scripts',
43
- plan: checked.tests, results: [],
52
+ plan: normalized.tests, results: [],
44
53
  }
54
+ const checked = validateTestRequests(repoRoot, normalized.tests)
55
+ if (!checked.ok) return {state: 'BLOCKED', reason: checked.reason, results: []}
45
56
  const results = []
46
57
  const timeout = Math.max(1000, Math.min(300_000, Number(timeoutMs) || 60_000))
47
58
  for (const test of checked.tests) {
@@ -169,6 +169,7 @@ export async function loadHotApi(version, capsArg) {
169
169
  import(new URL(`./tools-verified-change.mjs${v}`, import.meta.url).href),
170
170
  ])
171
171
  const raw = capsArg == null ? 'offline' : String(capsArg).trim()
172
+ const profile = Object.hasOwn(PROFILE_CAPS, raw) ? raw : 'custom'
172
173
  const selected = PROFILE_CAPS[raw] || raw.split(',').map((s) => s.trim()).filter(Boolean)
173
174
  .flatMap((cap) => cap === 'online' ? ['advisories', 'hosted'] : [cap])
174
175
  const caps = new Set(selected)
@@ -178,6 +179,7 @@ export async function loadHotApi(version, capsArg) {
178
179
  tools,
179
180
  byName: new Map(tools.map((t) => [t.name, t])),
180
181
  caps,
182
+ profile,
181
183
  stalenessLine,
182
184
  resetStalenessCache,
183
185
  }
@@ -40,6 +40,7 @@ export function tGraphStats(g, ctx) {
40
40
  const precision = g.precision || {state: 'UNAVAILABLE', verifiedEdges: 0, candidates: 0, queried: 0, reason: 'no revision-matched precision overlay'}
41
41
  return [
42
42
  `Graph summary`,
43
+ ctx?.runtime ? `- Weavatrix runtime: v${ctx.runtime.version}; profile ${ctx.runtime.profile}; ${ctx.runtime.toolCount} registered tools; capabilities: ${ctx.runtime.capabilities.join(',') || '(none)'}` : null,
43
44
  ctx?.repoRoot ? `- Repo: ${ctx.repoRoot}` : null,
44
45
  ctx?.graphPath ? `- Graph: ${ctx.graphPath}` : null,
45
46
  `- Build mode: ${g.graphBuildMode || 'full'}`,
@@ -126,10 +126,18 @@ export async function tVerifiedChange(g, args = {}, ctx = {}, tools = {}, permis
126
126
  })
127
127
  : {model: 'bounded call-argument-to-parameter evidence (not CFG or taint analysis)', status: 'UNAVAILABLE', reason: 'source capability is not enabled', edges: [], unsupportedEdges: 0, capped: false}
128
128
  const suggestedTests = targetTests(impact)
129
- const checkedTests = validateTestRequests(ctx.repoRoot, args.tests || [])
130
- const testProof = phase === 'verify'
131
- ? await runAllowedTests(ctx.repoRoot, args.tests || [], {enabled: args.run_tests === true, timeoutMs: args.test_timeout_ms})
132
- : {state: checkedTests.ok ? 'PLANNED' : 'BLOCKED', reason: checkedTests.reason, plan: checkedTests.tests || [], results: []}
129
+ const requestedTests = Array.isArray(args.tests) ? args.tests : []
130
+ let testProof
131
+ if (!requestedTests.length) {
132
+ testProof = {state: 'NOT_REQUESTED', reason: 'no package scripts were requested', plan: [], results: []}
133
+ } else if (args.run_tests !== true) {
134
+ testProof = await runAllowedTests(ctx.repoRoot, requestedTests, {enabled: false, timeoutMs: args.test_timeout_ms})
135
+ } else if (phase === 'verify') {
136
+ testProof = await runAllowedTests(ctx.repoRoot, requestedTests, {enabled: true, timeoutMs: args.test_timeout_ms})
137
+ } else {
138
+ const checkedTests = validateTestRequests(ctx.repoRoot, requestedTests)
139
+ testProof = {state: checkedTests.ok ? 'PLANNED' : 'BLOCKED', reason: checkedTests.reason, plan: checkedTests.tests || [], results: []}
140
+ }
133
141
  const testCoverageState = testCoverage(testProof, args.tests || [], suggestedTests)
134
142
 
135
143
  const architectureValue = phase === 'verify'
@@ -85,11 +85,21 @@ function hotVersion(hotFiles) {
85
85
  async function main() {
86
86
  let catalog = await loadCatalog()
87
87
  let api = await catalog.loadHotApi(0, CAPS_ARG)
88
+ const runtimeInfo = () => ({
89
+ version: PKG_VERSION,
90
+ profile: api.profile || 'custom',
91
+ capabilities: [...api.caps],
92
+ toolCount: api.tools.length,
93
+ })
94
+ const runtimeInstructions = () => {
95
+ const runtime = runtimeInfo()
96
+ return `Weavatrix ${runtime.version}; profile=${runtime.profile}; tools=${runtime.toolCount}; capabilities=${runtime.capabilities.join(',') || '(none)'}. If this differs from the client-visible tool list, reconnect the MCP client to discard its cached schema.`
97
+ }
88
98
  let graph = null
89
99
  let graphError = null
90
100
  // ctx owns the CURRENT target: rebuild_graph reloads it, open_repo retargets graphPath/repoRoot
91
101
  // at runtime. loadInto always reads ctx.graphPath so both paths share one loader.
92
- const ctx = {graphPath: GRAPH_PATH, repoRoot: REPO_ROOT, reload: null}
102
+ const ctx = {graphPath: GRAPH_PATH, repoRoot: REPO_ROOT, reload: null, runtime: runtimeInfo()}
93
103
  const loadInto = () => { graph = loadGraph(ctx.graphPath, {repoRoot: ctx.repoRoot}); graphError = null; return graph }
94
104
  ctx.reload = () => { api.resetStalenessCache(); try { return loadInto() } catch (e) { graphError = e.message; return null } }
95
105
  try {
@@ -229,6 +239,7 @@ async function main() {
229
239
  const nextApi = await nextCatalog.loadHotApi(v, CAPS_ARG)
230
240
  catalog = nextCatalog
231
241
  api = nextApi
242
+ ctx.runtime = runtimeInfo()
232
243
  loadedVersion = v
233
244
  log(`hot-reloaded tool implementations from changed source (${api.tools.length} tools)`)
234
245
  send({jsonrpc: '2.0', method: 'notifications/tools/list_changed'})
@@ -247,14 +258,17 @@ async function main() {
247
258
  }
248
259
  if (method === 'initialize') {
249
260
  if (params?.protocolVersion) protocolVersion = String(params.protocolVersion)
250
- return reply(id, {protocolVersion, capabilities: {tools: {listChanged: true}}, serverInfo: SERVER_INFO})
261
+ return reply(id, {protocolVersion, capabilities: {tools: {listChanged: true}}, serverInfo: SERVER_INFO, instructions: runtimeInstructions()})
251
262
  }
252
263
  if (method === 'notifications/initialized' || method === 'initialized') return
253
264
  if (method === 'ping') return reply(id, {})
254
265
  if (method === 'tools/list') {
255
266
  await maybeHotReload()
256
267
  if (shuttingDown) return
257
- return reply(id, {tools: api.tools.map(({name, description, inputSchema, outputSchema}) => ({name, description, inputSchema, outputSchema}))})
268
+ return reply(id, {
269
+ tools: api.tools.map(({name, description, inputSchema, outputSchema}) => ({name, description, inputSchema, outputSchema})),
270
+ _meta: {'weavatrix/runtime': runtimeInfo()},
271
+ })
258
272
  }
259
273
  if (method === 'tools/call') {
260
274
  await maybeHotReload()
@@ -1,45 +0,0 @@
1
- # Weavatrix 0.2.12
2
-
3
- ## Agent workflow routing and cross-repository API clarity
4
-
5
- 0.2.12 incorporates a second hands-on evaluation across Weavatrix, BranchPilot,
6
- controller-rest-api and its registered clients. It does not reduce the product to a short list: the
7
- skill still maps all 38 methods across application understanding, graph views, Health, dependencies,
8
- dead code, duplicates, coverage, history, endpoints, impact, architecture and Hosted governance.
9
-
10
- The skill now makes three high-leverage routing decisions explicit:
11
-
12
- - prefer `trace_api_contract` over disconnected per-repository searches when a backend change can
13
- affect registered clients;
14
- - use `change_impact` as a diff-risk classifier that separates additive exports from
15
- signature/body/removal risk, runtime/type-only radius and honest coverage evidence;
16
- - treat `verified_change` as a proof layer around an agent's edit, never a hidden source editor or
17
- auto-fix.
18
-
19
- The one-symbol refactor workflow now carries exact context, dependents and coverage through the
20
- post-edit `verified_change` ratchet. The public site also surfaces cross-repository API contract
21
- tracing as a first-class graph capability rather than hiding it under generic multi-repository mode.
22
-
23
- ## Worked examples and public benchmark evidence
24
-
25
- The README and public site now show four concrete dogfood scenarios instead of relying on feature
26
- names alone: orienting inside a 1,076-file backend and tracing one of 462 observed routes; proving
27
- external handler use across three registered repositories; classifying a BranchPilot change before
28
- editing; and turning Health plus clone evidence into a bounded review queue. The examples preserve
29
- uncertainty for dynamic URLs, advisory coverage and review-required findings.
30
-
31
- The public benchmark section reports reproducible fixture and revision-pinned real-repository
32
- regression gates with dates, environment, commands and explicit limits. It does not present these
33
- machine-dependent local measurements as competitor benchmarks. A lightweight CSS motion sequence
34
- illustrates the graph-to-verdict workflow and respects `prefers-reduced-motion`; no synthetic product
35
- screenshots are used.
36
-
37
- ## Compatibility and verification
38
-
39
- - Runtime implementation, tool names, schemas and result envelopes are unchanged from 0.2.11.
40
- - Hosted sync payload v2/v3 and architecture-contract transport are unchanged.
41
- - Skill inventory: all 38 current methods are routed; 0 missing.
42
- - Full Node suite baseline: 506 tests, 503 passed, 3 platform skips, 0 failed.
43
- - Six-language fixture, cross-repository and lifecycle benchmark: `PASS`.
44
- - Six locally available revision-pinned real-repository baselines: `PASS`.
45
- - Release metadata, 99-character MCP Registry description and MCPB validation: `PASS`.