weavatrix 0.2.13 → 0.2.15

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 (145) hide show
  1. package/README.md +99 -39
  2. package/SECURITY.md +2 -2
  3. package/docs/releases/v0.2.15.md +37 -0
  4. package/package.json +2 -2
  5. package/skill/SKILL.md +57 -38
  6. package/src/analysis/architecture/contract-graph.js +119 -0
  7. package/src/analysis/architecture/contract-schema.js +110 -0
  8. package/src/analysis/architecture/contract-storage.js +35 -0
  9. package/src/analysis/architecture/contract-verification.js +168 -0
  10. package/src/analysis/architecture-contract.js +16 -343
  11. package/src/analysis/change-classification/diff-parser.js +103 -0
  12. package/src/analysis/change-classification/options.js +40 -0
  13. package/src/analysis/change-classification/symbol-classifier.js +177 -0
  14. package/src/analysis/change-classification.js +120 -519
  15. package/src/analysis/dead-code-review/policy.js +23 -0
  16. package/src/analysis/dead-code-review.js +9 -19
  17. package/src/analysis/dep-check.js +14 -71
  18. package/src/analysis/dep-rules.js +10 -303
  19. package/src/analysis/dependency/conventions.js +16 -0
  20. package/src/analysis/dependency/scoped-dependencies.js +45 -0
  21. package/src/analysis/dependency/source-references.js +21 -0
  22. package/src/analysis/duplicates.tokenize.js +12 -2
  23. package/src/analysis/endpoints/common.js +62 -0
  24. package/src/analysis/endpoints/extract.js +107 -0
  25. package/src/analysis/endpoints/inventory.js +84 -0
  26. package/src/analysis/endpoints/mounts.js +129 -0
  27. package/src/analysis/endpoints-java.js +80 -3
  28. package/src/analysis/endpoints.js +3 -448
  29. package/src/analysis/git-history/analytics.js +177 -0
  30. package/src/analysis/git-history/collector.js +109 -0
  31. package/src/analysis/git-history/options.js +68 -0
  32. package/src/analysis/git-history.js +128 -577
  33. package/src/analysis/health-capabilities.js +82 -0
  34. package/src/analysis/http-contracts/analysis.js +169 -0
  35. package/src/analysis/http-contracts/client-call-detection.js +81 -0
  36. package/src/analysis/http-contracts/client-call-parser.js +255 -0
  37. package/src/analysis/http-contracts/graph-context.js +143 -0
  38. package/src/analysis/http-contracts/matching.js +61 -0
  39. package/src/analysis/http-contracts/shared.js +86 -0
  40. package/src/analysis/http-contracts.js +6 -822
  41. package/src/analysis/internal-audit/dependency-health.js +111 -0
  42. package/src/analysis/internal-audit/python-manifests.js +65 -0
  43. package/src/analysis/internal-audit/repo-files.js +55 -0
  44. package/src/analysis/internal-audit/supply-chain.js +132 -0
  45. package/src/analysis/internal-audit.collect.js +5 -106
  46. package/src/analysis/internal-audit.reach.js +20 -0
  47. package/src/analysis/internal-audit.run.js +114 -200
  48. package/src/analysis/jvm-dependency-evidence.js +69 -0
  49. package/src/analysis/source-correctness/retry-patterns.js +93 -0
  50. package/src/analysis/source-correctness.js +225 -0
  51. package/src/analysis/structure/dependency-graph.js +156 -0
  52. package/src/analysis/structure/findings.js +142 -0
  53. package/src/analysis/task-retrieval.js +3 -14
  54. package/src/graph/builder/go-receiver-resolution.js +112 -0
  55. package/src/graph/builder/js/queries.js +48 -0
  56. package/src/graph/builder/lang-go.js +89 -4
  57. package/src/graph/builder/lang-js.js +4 -44
  58. package/src/graph/builder/pass2-resolution.js +68 -0
  59. package/src/graph/freshness-probe.js +2 -1
  60. package/src/graph/incremental-refresh.js +3 -2
  61. package/src/graph/internal-builder.build.js +22 -183
  62. package/src/graph/internal-builder.pass2.js +161 -0
  63. package/src/graph/internal-builder.resolvers.js +2 -105
  64. package/src/graph/resolvers/rust.js +117 -0
  65. package/src/mcp/actions/advisories.mjs +18 -0
  66. package/src/mcp/actions/graph-lifecycle.mjs +148 -0
  67. package/src/mcp/actions/graph-sync.mjs +195 -0
  68. package/src/mcp/actions/hosted-architecture.mjs +57 -0
  69. package/src/mcp/architecture-bootstrap.mjs +168 -0
  70. package/src/mcp/architecture-starter.mjs +234 -0
  71. package/src/mcp/catalog.mjs +20 -6
  72. package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
  73. package/src/mcp/evidence/duplicate-member-order.mjs +8 -0
  74. package/src/mcp/evidence/package-graph-common.mjs +115 -0
  75. package/src/mcp/evidence/package-lock-graph.mjs +92 -0
  76. package/src/mcp/evidence-snapshot.duplicates.mjs +3 -7
  77. package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
  78. package/src/mcp/git-output.mjs +10 -0
  79. package/src/mcp/graph/context-core.mjs +111 -0
  80. package/src/mcp/graph/context-seeds.mjs +197 -0
  81. package/src/mcp/graph/context-state.mjs +86 -0
  82. package/src/mcp/graph/reverse-reach.mjs +42 -0
  83. package/src/mcp/graph/tools-core.mjs +143 -0
  84. package/src/mcp/graph/tools-query.mjs +223 -0
  85. package/src/mcp/graph-context.mjs +4 -496
  86. package/src/mcp/health/audit-format.mjs +172 -0
  87. package/src/mcp/health/audit.mjs +171 -0
  88. package/src/mcp/health/dead-code.mjs +110 -0
  89. package/src/mcp/health/duplicates.mjs +83 -0
  90. package/src/mcp/health/endpoints.mjs +42 -0
  91. package/src/mcp/health/structure.mjs +219 -0
  92. package/src/mcp/runtime-version.mjs +32 -0
  93. package/src/mcp/server/auto-refresh.mjs +66 -0
  94. package/src/mcp/server/runtime-config.mjs +43 -0
  95. package/src/mcp/server/shutdown.mjs +40 -0
  96. package/src/mcp/sync/evidence-architecture.mjs +54 -0
  97. package/src/mcp/sync/evidence-common.mjs +88 -0
  98. package/src/mcp/sync/evidence-duplicates.mjs +97 -0
  99. package/src/mcp/sync/evidence-health.mjs +56 -0
  100. package/src/mcp/sync/evidence-packages.mjs +95 -0
  101. package/src/mcp/sync/payload-common.mjs +97 -0
  102. package/src/mcp/sync/payload-v2.mjs +53 -0
  103. package/src/mcp/sync/payload-v3.mjs +79 -0
  104. package/src/mcp/sync-evidence.mjs +7 -402
  105. package/src/mcp/sync-payload.mjs +10 -244
  106. package/src/mcp/tools-actions.mjs +18 -414
  107. package/src/mcp/tools-architecture.mjs +18 -70
  108. package/src/mcp/tools-context.mjs +56 -15
  109. package/src/mcp/tools-endpoints.mjs +4 -1
  110. package/src/mcp/tools-graph.mjs +17 -331
  111. package/src/mcp/tools-health.mjs +24 -705
  112. package/src/mcp/tools-impact-change.mjs +2 -38
  113. package/src/mcp/tools-impact.mjs +2 -43
  114. package/src/mcp-server.mjs +35 -146
  115. package/src/path-classification.js +14 -0
  116. package/src/precision/lsp-client/constants.js +12 -0
  117. package/src/precision/lsp-client/environment.js +20 -0
  118. package/src/precision/lsp-client/errors.js +15 -0
  119. package/src/precision/lsp-client/lifecycle.js +127 -0
  120. package/src/precision/lsp-client/message-parser.js +81 -0
  121. package/src/precision/lsp-client/protocol.js +212 -0
  122. package/src/precision/lsp-client/registry.js +58 -0
  123. package/src/precision/lsp-client/repo-uri.js +60 -0
  124. package/src/precision/lsp-client/stdio-client.js +151 -0
  125. package/src/precision/lsp-client.js +10 -682
  126. package/src/precision/lsp-overlay/build.js +238 -0
  127. package/src/precision/lsp-overlay/contract.js +61 -0
  128. package/src/precision/lsp-overlay/reference-results.js +108 -0
  129. package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
  130. package/src/precision/lsp-overlay/source-session.js +134 -0
  131. package/src/precision/lsp-overlay/store.js +150 -0
  132. package/src/precision/lsp-overlay/target-index.js +147 -0
  133. package/src/precision/lsp-overlay/target-query.js +55 -0
  134. package/src/precision/lsp-overlay.js +11 -868
  135. package/src/precision/typescript-lsp-provider.js +12 -682
  136. package/src/precision/typescript-provider/client.js +69 -0
  137. package/src/precision/typescript-provider/discovery.js +124 -0
  138. package/src/precision/typescript-provider/project-host.js +249 -0
  139. package/src/precision/typescript-provider/project-safety.js +161 -0
  140. package/src/precision/typescript-provider/reference-usage.js +53 -0
  141. package/src/security/malware-heuristics.sweep.js +1 -1
  142. package/src/security/registry-sig.classify.js +2 -1
  143. package/src/security/registry-sig.rules.js +3 -3
  144. package/src/version.js +7 -0
  145. package/docs/releases/v0.2.13.md +0 -48
package/README.md CHANGED
@@ -34,8 +34,8 @@ Weavatrix answers questions a text index cannot:
34
34
  depends on them — with test coverage attached, so the **untested part of the blast radius** stands
35
35
  out before you ship.
36
36
  - *"Who calls this function?"* → `inspect_symbol` returns exact bounded TS/JS occurrences plus
37
- source context; `context_bundle` adds grouped graph relations, exact re-export sites, and a
38
- smaller source workset. `get_dependents` walks the symbol-level reverse graph transitively. Opt into
37
+ source context; `context_bundle` adds production-first graph relations, exact re-export sites,
38
+ diverse call-site excerpts, and a smaller source workset. `get_dependents` walks the symbol-level reverse graph transitively. Opt into
39
39
  `include_container_importers:true` only when a broader module-import radius is intended.
40
40
  - *"Did my refactor actually decouple anything?"* → `graph_diff base_ref=HEAD~1` builds an immutable
41
41
  baseline graph without checking it out, then reports the structural delta: new module
@@ -116,6 +116,43 @@ find_duplicates
116
116
  Every dead-code, orphan, dependency and duplicate item remains review evidence. Confirm framework
117
117
  conventions and source use before editing; Weavatrix does not auto-delete or merge findings.
118
118
 
119
+ `run_audit` also returns an explicit capability matrix. `STRUCTURE CHECKED` and a supported package
120
+ ecosystem do not imply `RUNTIME_CORRECTNESS` or `CONCURRENCY` is complete. Maven/Gradle manifests are
121
+ reported `NOT_SUPPORTED`/`PARTIAL` for import-to-artifact verification rather than as a false clean
122
+ `0 declared / 0 external`; bounded Go/Java correctness checks disclose that they are neither compiler
123
+ proof nor a race detector.
124
+
125
+ ### Trace an event, queue, worker, cron or CLI flow
126
+
127
+ ```text
128
+ query_graph
129
+ seed_symbols=["handleAttackEvents"]
130
+ relation_filter=["calls", "references"]
131
+ flow_direction="both"
132
+ -> exact listener plus bounded producers and consumers
133
+ context_bundle label="handleAttackEvents"
134
+ -> production callers first and diverse excerpts around decisive call sites
135
+ ```
136
+
137
+ Exact symbol seeds avoid fuzzy routing noise and work for non-HTTP entry points without adding a
138
+ special-purpose tool for every framework. A narrow `search_code` registration check is still useful
139
+ when the handler name is not known; it is a discovery aid, not the graph.
140
+
141
+ ### Establish an architecture contract without silently changing policy
142
+
143
+ ```text
144
+ get_architecture_contract action=preview baseline_mode=none
145
+ -> adaptive Maven/Gradle/monorepo territories
146
+ -> observed dependency directions labelled OBSERVED_NOT_ENFORCED
147
+ -> exact proposed file, verification, hash and short-lived token
148
+ get_architecture_contract action=approve confirm_token=<reviewed-token>
149
+ -> creates only a missing .weavatrix/architecture.json
150
+ prepare_change -> edit -> verify_architecture
151
+ ```
152
+
153
+ Use `baseline_mode=accept-current` only when the owner explicitly accepts current deterministic debt.
154
+ Approval rechecks the graph and never overwrites an existing local or Hosted policy.
155
+
119
156
  ## Benchmarks
120
157
 
121
158
  Two different gates ship in the repository:
@@ -126,7 +163,7 @@ Two different gates ship in the repository:
126
163
  0.2.1 relation baseline. It fails on unexplained signal loss; `MISSING`, `STALE` and `UNBASELINED`
127
164
  remain incomplete, not green.
128
165
 
129
- Latest local release run (Windows x64, Node 24.15.0, July 18, 2026):
166
+ Representative local regression run (Windows x64, Node 24.15.0, July 18, 2026):
130
167
 
131
168
  | Gate | Result | Selected evidence |
132
169
  |---|---:|---|
@@ -218,7 +255,7 @@ No graph yet? Ask the agent to call `rebuild_graph`; it builds the missing graph
218
255
  With the default `offline` profile (or an explicit capability set containing `retarget`),
219
256
  `open_repo` can change the active repository
220
257
  and builds a missing graph automatically. A normal
221
- `open_repo` also upgrades graphs that predate current typed-edge/provenance metadata; `build:false`
258
+ `open_repo` also upgrades graphs that predate current typed-edge/provenance/physical-LOC metadata; `build:false`
222
259
  probes without building and refuses a legacy graph. Retargeting is offline but intentionally changes
223
260
  the filesystem boundary for subsequent tools; select `pinned` when that boundary must not move.
224
261
 
@@ -240,8 +277,8 @@ Every current edge carries versioned provenance. The parser emits `EXTRACTED`, `
240
277
  confirmed by its bundled `typescript-language-server` + TypeScript runtime to `EXACT_LSP`.
241
278
  `CONFLICT` means evidence disagrees. `graph_stats` reports the provenance breakdown and the semantic
242
279
  provider's `COMPLETE`, `PARTIAL`, `UNAVAILABLE`, or `OFF` state; `OFF` means precision was explicitly
243
- disabled and only static evidence is active. Java and Rust language-server providers are not bundled
244
- in 0.2.9: their edges never become `EXACT_LSP`, even when a mixed repository reports a complete
280
+ disabled and only static evidence is active. Java and Rust language-server providers are not bundled:
281
+ their edges never become `EXACT_LSP`, even when a mixed repository reports a complete
245
282
  TypeScript/JavaScript overlay.
246
283
 
247
284
  The bounded JS/TS provider is enabled by default for new graphs. Set `WEAVATRIX_PRECISION=off`
@@ -252,19 +289,21 @@ choice as **TypeScript/JavaScript semantic precision**.
252
289
  **search / source** — `search_code` (ripgrep-backed, pure-Node fallback, with repository-relative
253
290
  path globs on Windows/macOS/Linux), `read_source` (a
254
291
  symbol's actual code in one hop), `context_bundle` (definition plus grouped inbound/outbound
255
- containers, exact re-export sites, call-site/target provenance and bounded excerpts around decisive
292
+ containers ranked production-first, exact re-export sites, call-site/target provenance and diverse bounded excerpts around decisive
256
293
  edges), `inspect_symbol` (one exact
257
294
  bounded TS/JS reference query, logical containers, impact and source excerpts), `list_endpoints` (HTTP route inventory:
258
295
  Express/Fastify/Nest/Flask/FastAPI/Go mux/Rust axum and actix-web, including nested Express
259
- `router.use(...)` mount composition, declaration/reachability counts and mount provenance),
296
+ `router.use(...)` mount composition, declaration/reachability counts, mount provenance, and Spring
297
+ conditional/default-active state),
260
298
  `trace_endpoint` (one exact composed route → handler → bounded production call graph with call-site excerpts)
261
299
 
262
300
  **health** — `find_dead_code` (bounded review queue for statically unreferenced and test-only files,
263
301
  functions, methods, and symbols, with evidence tiers, completed/remaining verification and explicit
264
302
  public/framework/dynamic caveats),
265
- `run_audit` (unused files/exports/dependencies with per-finding manifest/indexed-source/script/config verification;
303
+ `run_audit` (an explicit capability matrix plus unused files/exports/dependencies with per-finding manifest/indexed-source/script/config verification;
266
304
  `category:dependencies` isolates missing/unused/duplicate declarations, unresolved imports and lockfile drift,
267
- missing npm/Go/Python deps, runtime
305
+ missing npm/Go/Python deps, honest Maven/Gradle `NOT_SUPPORTED`/`PARTIAL` import verification, bounded
306
+ Go/Java correctness candidates, runtime
268
307
  cycles, type-only/compile-only coupling, orphans, boundary rules, offline OSV vulnerabilities + typosquat +
269
308
  lockfile drift; accepts an immutable `base_ref`, `changed_files`, and `debt: new|existing|all` for
270
309
  review-scoped results; production paths are the default and `include_classified:true` opts into
@@ -318,8 +357,10 @@ not CFG, value-propagation, or taint analysis.
318
357
  **crossrepo** *(included in `offline`; absent from `pinned`; reads only registered local graphs)* —
319
358
  `trace_api_contract`; reconciles the selected backend/client graphs and joins routes to client callsites
320
359
 
321
- `query_graph` accepts optional `seed_files` when an architectural question must start from exact
322
- entry points. Resolved explicit seeds are exclusive by default; set `augment_seeds:true` only when
360
+ `query_graph` accepts optional `seed_files` and exact `seed_symbols` when an architectural or
361
+ event-driven question must start from known entry points. `relation_filter` limits edge kinds and
362
+ `flow_direction:forward|backward|both` turns the same graph into a bounded producer/consumer view.
363
+ Resolved explicit seeds are exclusive by default; set `augment_seeds:true` only when
323
364
  question-derived seeds are also wanted. A code-shaped identifier such as `startMitigate` is treated
324
365
  as a stronger bounded seed than surrounding words such as controller/service/flow; all exact
325
366
  same-name declarations are retained instead of adding unrelated concept seeds. Broad
@@ -329,7 +370,7 @@ and fixture matches. Production-first classification also applies during travers
329
370
  tests/generated/docs/benchmarks do not leak back from a production seed; name a class in the
330
371
  question or set `include_classified:true` to include it. Unreferenced unmatched constant/field leaves
331
372
  are hidden unless `include_low_signal:true`. Broad ranking remains orientation evidence; use
332
- `seed_files`, an exact endpoint, or `inspect_symbol` when the intended entry point is already known.
373
+ `seed_files`, `seed_symbols`, an exact endpoint, or `inspect_symbol` when the intended entry point is already known.
333
374
  Instruction words such as “REST”, “path”, and “inspect” do not become fuzzy code seeds.
334
375
 
335
376
  **advisories** *(network, explicit opt-in)* — `refresh_advisories`
@@ -347,25 +388,45 @@ disclosed instead of silently guessed; and the server **hot-reloads its watched
347
388
  modules and catalog** when those files change — other MCP helpers and analysis engines require a
348
389
  reconnect. Every MCP response also carries local, transient `_meta["weavatrix/metrics"]` with elapsed
349
390
  time, output bytes/token estimate, graph freshness/revision/update and graph-cache status. These
350
- metrics are not persisted or transmitted by Weavatrix.
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).
391
+ metrics are not persisted or transmitted by Weavatrix. If a source checkout's package version moves
392
+ while an old daemon remains alive, `initialize`, `tools/list`, and tool calls fail loudly with
393
+ `STALE_RUNTIME` until the client reconnects; the opt-out is reserved for deliberate development.
394
+
395
+ ### 0.2.15 self-audit precision patch
396
+
397
+ - Dependency review now scopes nested manifests correctly, recognizes framework peer packages and
398
+ package references assembled from bounded dynamic path fragments, and avoids misclassifying
399
+ dependency-owned source as an unused root declaration.
400
+ - Reachability follows source-owned HTML asset references, so maintained browser entry scripts and
401
+ styles remain part of the production surface instead of appearing as dead files.
402
+ - Malware heuristics distinguish inert placeholders, comments, documentation URLs, and ordinary
403
+ Unicode text from executable registry or download behavior while retaining explicit review
404
+ evidence for actionable patterns.
405
+ - Duplicate review ignores policy-like numeric tables and stable ordered-member declarations where
406
+ repetition is intentional, and the remaining reverse-reach, Git-output, member-order, path-term,
407
+ and retrieval logic now uses shared owners instead of drifting copies.
408
+
409
+ Full patch notes: [docs/releases/v0.2.15.md](docs/releases/v0.2.15.md).
410
+
411
+ ### 0.2.14 typed flows, honest Health, and architecture bootstrap
412
+
413
+ - Go call resolution now follows receiver types through parameters, locals, constructor returns,
414
+ imported types and struct fields. It links calls such as `bgpSpeaker.RemoveMitigator(update)` to
415
+ `(*Speaker).RemoveMitigator` without guessing across ambiguous same-name receivers.
416
+ - `query_graph` adds exact `seed_symbols`, `relation_filter`, and directed traversal for generic
417
+ event/queue/worker/cron/CLI flows. `context_bundle` ranks production callers before tests and uses
418
+ diverse edge-centered excerpts. `FlowSpec` no longer accidentally requests test traversal.
419
+ - Health exposes per-capability completeness. Maven/Gradle support is honest instead of returning a
420
+ clean zero, and bounded Go/Java correctness findings never claim compiler, runtime, race, or
421
+ concurrency proof. Spring endpoints expose conditional/default-inactive controllers.
422
+ - Architecture bootstrap adapts to Maven/Gradle/monorepo source roots and uses a reviewable
423
+ preview/approve handshake. A stale daemon now refuses analysis when its runtime version differs
424
+ from the package on disk.
425
+ - The MCP implementation and static site are split into owner-focused modules/assets. A release test
426
+ enforces a physical 300-line maximum for JavaScript/TypeScript under `src`, `bin`, `scripts`, and
427
+ `test`, plus maintained HTML/CSS/JavaScript under `site`.
428
+
429
+ Full patch notes: [docs/releases/v0.2.14.md](docs/releases/v0.2.14.md).
369
430
 
370
431
  ### 0.2.9 correctness, signal, and consent patch
371
432
 
@@ -752,10 +813,10 @@ The benchmark checks representative graph correctness, complete edge provenance,
752
813
  HTTP tracing, output bytes, latency, freshness, reconnect and active-target stability. Its budgets, semantics and intentionally
753
814
  limited claims are documented in [docs/benchmarking.md](docs/benchmarking.md).
754
815
 
755
- Refactoring target: keep focused implementation modules near 300 lines and split larger concerns
756
- into dotted-suffix modules behind a slim facade (`foo.js` re-exports `foo.parse.js`,
757
- `foo.report.js`, …). A few older orchestration modules remain above that target; new work should
758
- reduce them instead of growing new monoliths. The MCP layer lives
816
+ Maintained JavaScript/TypeScript files under `src`, `bin`, `scripts`, and `test`, plus HTML/CSS/JavaScript
817
+ under `site`, have a hard physical 300-line ceiling enforced by the release suite. Larger concerns are
818
+ split into owner-focused modules behind slim stable facades (`foo.js` re-exports `foo.parse.js`,
819
+ `foo.report.js`, …). The MCP layer lives
759
820
  in `src/mcp/` (graph context, tool entry modules, focused helpers, and the catalog/hot-reload
760
821
  loader) behind the thin stdio entry `src/mcp-server.mjs`.
761
822
 
@@ -763,9 +824,8 @@ loader) behind the thin stdio entry `src/mcp-server.mjs`.
763
824
 
764
825
  - **Public 0.2.2 regression foundation** now has the permanent six-language golden corpus,
765
826
  cross-repository wrapper/liveness fixture, framework/convention fixture, full MCP lifecycle gate
766
- and a portable real-repository runner. Five source-free 0.2.1 real-repository baselines are
767
- recorded; edge provenance is gated end-to-end. The unavailable Rust source checkout is the only
768
- explicit local gap preventing the strict six-repository release command from passing here.
827
+ and a portable real-repository runner. Six source-free 0.2.1 real-repository baselines are
828
+ recorded; edge provenance is gated end-to-end and the strict six-repository release command passes.
769
829
  - **Wrapper-aware API contracts** shipped in 0.2.2: persistent/ad-hoc configuration,
770
830
  conservative discovery, cross-repository handler liveness and explicit unknown states. The next
771
831
  hosted increment joins privacy-safe contract identities across separately synced services.
package/SECURITY.md CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  |---|---|
7
- | `0.2.9.x` | Yes |
8
- | `0.2.8` and older | Upgrade to the latest release |
7
+ | `0.2.15.x` | Yes |
8
+ | `0.2.14` and older | Upgrade to the latest release |
9
9
 
10
10
  Security fixes are provided for the latest published version of Weavatrix. Upgrade before reporting
11
11
  an issue that may already be resolved.
@@ -0,0 +1,37 @@
1
+ # Weavatrix 0.2.15
2
+
3
+ 0.2.15 is a focused self-audit precision release. It keeps the 38-tool MCP surface and all wire and
4
+ security boundaries stable while removing false-positive dependency, dead-code, malware, and
5
+ duplicate findings discovered by running Weavatrix against its own repository.
6
+
7
+ ## Dependency and reachability precision
8
+
9
+ - Dependency verification now respects the owning nested manifest before deciding whether an import
10
+ is missing or a declaration is unused.
11
+ - Framework peer dependencies and bounded package paths assembled from static string fragments are
12
+ recognized without treating arbitrary runtime values as proof.
13
+ - Source-owned HTML asset references participate in reachability, protecting maintained browser
14
+ scripts and styles from false dead-file findings.
15
+
16
+ ## Safer review queues
17
+
18
+ - Malware scanning distinguishes placeholders, comments, documentation URLs, and ordinary Unicode
19
+ text from executable registry/download behavior. Static heuristic evidence remains review-only and
20
+ does not claim execution or compromise.
21
+ - Duplicate detection suppresses policy-like numeric tables and stable ordered declarations where
22
+ repeated structure carries meaning, while preserving clone evidence for executable code.
23
+ - Reverse reachability, Git output parsing, ordered-member comparison, path terminology, task
24
+ retrieval, and duplicate evidence now share focused owners instead of maintaining divergent copies.
25
+
26
+ ## Compatibility and security
27
+
28
+ - There are no MCP tool-schema, capability-profile, Hosted payload, sync-consent, or architecture
29
+ contract changes in this release.
30
+ - The default profile remains offline and local-first. Advisory and Hosted network capabilities
31
+ remain explicit opt-ins.
32
+
33
+ ## Verification
34
+
35
+ The release is gated by the full Node suite, six-language fixture benchmark, six-repository semantic
36
+ regression gate, release-manifest verification, packed npm and MCPB stdio checks, and npm audit. The
37
+ exact counts and artifacts are recorded by the immutable GitHub release workflow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weavatrix",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
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.13.md",
29
+ "docs/releases/v0.2.15.md",
30
30
  "README.md",
31
31
  "SECURITY.md",
32
32
  "LICENSE"
package/skill/SKILL.md CHANGED
@@ -17,10 +17,11 @@ Tools are named `mcp__weavatrix__…`. If none are available, ask the user to re
17
17
  `codex mcp add weavatrix -- npx -y weavatrix <repoRoot>`), then retry.
18
18
 
19
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
20
+ tools for `pinned`, 34 for `offline`, 35 for `osv`, and 38 for `hosted` / `full`. Weavatrix refuses
21
+ `initialize`, `tools/list`, and tool calls when the running package version differs from the
22
+ `package.json` version on disk, with a loud `STALE_RUNTIME` error; restart/reconnect rather than using
23
+ an old daemon. `WEAVATRIX_ALLOW_STALE_RUNTIME=1` is only for deliberate source development. A custom
24
+ capability list needs `crossrepo` for `trace_api_contract`; legacy `online` adds only
24
25
  `advisories,hosted`. Missing HTTP tools are intentional only when the selected profile excludes them.
25
26
 
26
27
  Profiles use the same npm package and binary:
@@ -53,8 +54,10 @@ projection; expand only when the answer requires it.
53
54
  - **Find a connectivity path between two concepts**: `shortest_path`. It traverses the graph as
54
55
  undirected reachability, so it is not proof of call/dependency direction; confirm direction with
55
56
  `get_neighbors` and `read_source`.
56
- - **Explore an unknown entry point or architectural question**: `query_graph`; pin `seed_files` when
57
- known, and keep its broad result as orientation evidence.
57
+ - **Explore an unknown entry point or architectural question**: `query_graph`; pin `seed_files` or
58
+ exact `seed_symbols` when known. Use `relation_filter` plus `flow_direction` for a bounded event,
59
+ worker, queue, cron, CLI, or data-flow view; keep a broad natural-language result as orientation
60
+ evidence.
58
61
  - **Inspect one exact symbol deeply**: `context_bundle` for the bounded edit workset;
59
62
  `inspect_symbol` for the raw point query and on-demand JS/TS reference evidence.
60
63
  - **Confirm graph evidence in source**: `read_source`; use `search_code` only for a narrow regex/glob
@@ -86,11 +89,14 @@ projection; expand only when the answer requires it.
86
89
 
87
90
  ### Health, debt and testing scenarios
88
91
 
89
- - **Run a whole-repository Health review**: `run_audit debt=all`.
92
+ - **Run a whole-repository Health review**: `run_audit debt=all`, then read its capability matrix.
93
+ `STRUCTURE CHECKED` and `DEPENDENCIES CHECKED` do not imply runtime or concurrency correctness.
90
94
  - **Gate only newly introduced branch debt**: `run_audit base_ref=<merge-base> debt=new`; old debt in
91
95
  a changed file remains existing.
92
96
  - **Review dependency declarations/imports**: `run_audit category=dependencies`; it includes missing,
93
97
  unused, duplicate, unresolved-import and lockfile-drift evidence without relabelling identities.
98
+ Maven/Gradle manifests are inventoried but unsupported import-to-artifact verification is reported
99
+ `NOT_SUPPORTED`/`PARTIAL`, never a false clean `0 declared / 0 external`.
94
100
  - **Refresh vulnerability evidence when explicitly authorized**: `refresh_advisories`, then
95
101
  `run_audit category=vulnerability`. `NOT_CHECKED` is unknown, never clean.
96
102
  - **Review dead files, functions, methods and symbols**: `find_dead_code`; every result remains a
@@ -104,9 +110,15 @@ projection; expand only when the answer requires it.
104
110
 
105
111
  ### Intended architecture and Hosted governance
106
112
 
107
- - **Read or establish intended architecture**: `get_architecture_contract`. A returned starter is a
108
- product-code-only territory proposal (not tests, docs, benchmarks, generated output or repository
109
- configs), not automatically approved policy.
113
+ - **Read or establish intended architecture**: `get_architecture_contract`. A returned starter adapts
114
+ to Maven/Gradle source roots and monorepos and proposes product-code territories plus observed
115
+ dependency directions labelled `OBSERVED_NOT_ENFORCED`; oversized Java branches split only at real
116
+ child packages. Only runtime-cycle and 300-line file guards are active by default; generic
117
+ complexity/cohesion thresholds are `CANDIDATE_NOT_ENFORCED`. None becomes policy automatically.
118
+ - **Bootstrap local policy safely**: `get_architecture_contract action=preview` with an optional
119
+ reviewed `candidate_contract` and `baseline_mode=none|accept-current`; inspect the exact content,
120
+ verification and patch, then call `action=approve confirm_token=<exact-token>`. Approval creates
121
+ only a missing `.weavatrix/architecture.json`, rechecks graph identity, and never overwrites policy.
110
122
  - **Select rules before editing**: `prepare_change`; **enforce the ratchet after editing**:
111
123
  `verify_architecture`.
112
124
  - **Understand or request an exception**: `explain_architecture_violation` ->
@@ -117,11 +129,13 @@ projection; expand only when the answer requires it.
117
129
  - **Review exactly what Hosted sync would send**: `preview_sync`; only an approved
118
130
  `sync_graph dry_run=false confirm_token=...` may send that exact bounded payload.
119
131
 
120
- Across every scenario, treat `PARTIAL`, `UNAVAILABLE`, `OFF`, `NOT_CHECKED`, `ERROR`, or capped
121
- evidence as incomplete rather than success. Java and Rust exact language-server providers are not
122
- bundled, so their edges never become `EXACT_LSP` even when a mixed repository has a complete
123
- TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved and explicitly
124
- `INFERRED`; they improve cross-file flow without claiming compiler-exact overload or dynamic dispatch.
132
+ Across every scenario, treat `PARTIAL`, `UNAVAILABLE`, `OFF`, `NOT_SUPPORTED`, `NOT_CHECKED`,
133
+ `ERROR`, or capped evidence as incomplete rather than success. Java and Rust exact language-server
134
+ providers are not bundled, so their edges never become `EXACT_LSP` even when a mixed repository has
135
+ a complete TypeScript/JavaScript overlay. Java and Go receiver-type call edges are parser-resolved
136
+ and explicitly `INFERRED`; Go resolution uses parameter, local, constructor-return, imported and
137
+ struct-field types. These edges improve cross-file flow without claiming compiler-exact overload,
138
+ interface dispatch, reflection, or runtime behavior.
125
139
 
126
140
  ## Ground rules
127
141
 
@@ -171,10 +185,15 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
171
185
  and the score is not profiler data or an interprocedural Big-O proof. The default queue uses
172
186
  `min_score=85` plus a narrow strong-local fallback; use `min_score=0` only for full diagnostics.
173
187
  Inspect its line evidence and measure runtime before scheduling a performance rewrite.
174
- - **Audit completeness**: read `dependencyReport.status` plus its unused/missing counts, then
175
- each npm finding's `verification` (manifest, indexed source, scripts/config, unresolved dynamic
176
- usage), then `checks.osv.status` and `checks.malware.status`. A dependency result from a partial graph is not a
177
- repository-wide clean zero. For OSV, `OK` is
188
+ - **Audit completeness**: read the top-level Health capability matrix first: structure, dependencies,
189
+ runtime correctness, concurrency, advisories, malware and measured coverage each have independent
190
+ status/completeness. The bounded Go/Java correctness patterns can flag a fixed-index slice hazard,
191
+ discriminator mismatch, lost Java interrupt or unbounded retry candidate, but they are not a
192
+ compiler, race detector, runtime trace, CFG, or proof of race freedom. Then read
193
+ `dependencyReport.status`, ecosystem support, unused/missing counts, each npm finding's
194
+ `verification` (manifest, indexed source, scripts/config, unresolved dynamic usage), and
195
+ `checks.osv.status` / `checks.malware.status`. A dependency result from a partial or unsupported
196
+ ecosystem is not a repository-wide clean zero. For OSV, `OK` is
178
197
  complete for the recorded dependency fingerprint; `PARTIAL` is incomplete or stale,
179
198
  `NOT_CHECKED` has no repository-specific result, and `ERROR` means the local check failed. Treat
180
199
  the same non-`OK` states as incomplete for malware scanning. Refresh OSV only when the user has
@@ -248,12 +267,15 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
248
267
  safety semantics, not boilerplate. Use `.weavatrix-deps.json` entrypoints/nonRuntimeRoots only for
249
268
  verified conventions.
250
269
  - **API inventory**: `list_endpoints` (including mount provenance, Next.js App Router, Rust axum and
251
- actix-web). When one exact route is known, use `trace_endpoint` for its composed mount chain,
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.
270
+ actix-web). Spring endpoint rows also expose conditional activation and whether the controller is
271
+ inactive by default. When one exact route is known, use `trace_endpoint` for its composed mount
272
+ chain, handler and bounded production call graph instead of broad natural-language traversal.
273
+ - **CLI, worker, queue, cron or event flow**: identify the exact listener/handler/registration symbol,
274
+ then call `query_graph seed_symbols=[...] relation_filter=["calls","references"]
275
+ flow_direction="both"`; use `context_bundle` for production-first inbound/outbound containers and
276
+ diverse call-site excerpts, then `get_dependents` / `read_source` for decisive evidence. If the
277
+ symbol is unknown, use a narrow `search_code` registration check once and pin what it finds. Do not
278
+ force a non-HTTP flow through endpoint tools or begin with an unconstrained natural-language seed.
257
279
  - **Cross-repository API impact**: ensure both repositories are in `list_known_repos`, then call
258
280
  `trace_api_contract backend=<uuid-or-label> clients=[<uuid-or-label>]`; narrow with `method`, `path`,
259
281
  or backend `changed_files`. `path` may be a segment-aligned fragment (`/query` can select
@@ -273,19 +295,16 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
273
295
  `UNBASELINED` and `STALE` are explicit incomplete states, not green results.
274
296
  A green Java/Rust fixture proves only its declared representative signals, not compiler-exact
275
297
  coverage of arbitrary repositories.
276
- - **Target architecture before editing**: `get_architecture_contract` `prepare_change` with the
277
- intended files edit and rebuild `verify_architecture`. A missing contract returns a starter
278
- proposal from `get_architecture_contract output_format:"json"`, not an automatically approved
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.
298
+ - **Target architecture before editing**: if no contract exists, call
299
+ `get_architecture_contract action=preview baseline_mode=none` and inspect the adaptive product
300
+ territories, observed-but-not-enforced directions and verification. Pass a reviewed
301
+ `candidate_contract` when the desired target differs. Only after explicit owner approval call
302
+ `get_architecture_contract action=approve confirm_token=<exact-token>`. Use
303
+ `baseline_mode=accept-current` only when the owner intentionally accepts current deterministic
304
+ debt into the ratchet. Then run `prepare_change` with intended files → edit/rebuild →
305
+ `verify_architecture`. An approved exception is still applied by adding the exact returned proposal
306
+ to `exceptions` and verifying again. Existing contracts are never overwritten; Hosted contracts
307
+ are pulled only after explicit opt-in. No tool silently changes an active policy.
289
308
  - **Behavioral architecture**: `git_history` ranks churn × connectivity hotspots and hidden
290
309
  co-change coupling from bounded local numstat history. Always set `top_n`; it is enforced across
291
310
  every returned structured collection and JSON reports per-collection truncation. Use it as review
@@ -0,0 +1,119 @@
1
+ import {architectureHash} from './contract-schema.js'
2
+
3
+ export const isSymbolNode = (id) => String(id).includes('#')
4
+ const endpointId = (value) => value && typeof value === 'object' ? String(value.id) : String(value ?? '')
5
+
6
+ export function fileOfNode(id, byId) {
7
+ const node = byId.get(String(id))
8
+ if (node?.source_file) return String(node.source_file).replace(/\\/g, '/')
9
+ return String(id).split('#')[0].replace(/\\/g, '/')
10
+ }
11
+
12
+ export function componentForFile(file, components) {
13
+ const normalized = String(file || '').replace(/\\/g, '/')
14
+ let best = null
15
+ for (const component of components) for (const prefix of component.paths) {
16
+ if (normalized !== prefix && !normalized.startsWith(`${prefix}/`)) continue
17
+ if (!best || prefix.length > best.prefix.length) best = {id: component.id, prefix}
18
+ }
19
+ return best?.id || '(unmapped)'
20
+ }
21
+
22
+ export function relationKind(link) {
23
+ if (link.typeOnly === true) return 'type-only'
24
+ if (link.compileOnly === true) return 'compile-only'
25
+ return 'runtime'
26
+ }
27
+
28
+ export function runtimeFileGraph(graph) {
29
+ const byId = new Map((graph.nodes || []).map((node) => [String(node.id), node]))
30
+ const files = new Set((graph.nodes || []).filter((node) => !isSymbolNode(node.id)).map((node) => String(node.id)))
31
+ const adjacency = new Map([...files].map((file) => [file, new Set()]))
32
+ for (const link of graph.links || []) {
33
+ if (relationKind(link) !== 'runtime' || !['imports', 're_exports'].includes(link.relation) || link.barrelProxy === true) continue
34
+ const source = fileOfNode(endpointId(link.source), byId)
35
+ const target = fileOfNode(endpointId(link.target), byId)
36
+ if (source && target && source !== target && files.has(source) && files.has(target)) adjacency.get(source)?.add(target)
37
+ }
38
+ return adjacency
39
+ }
40
+
41
+ export function stronglyConnected(adjacency) {
42
+ let index = 0
43
+ const indexes = new Map(), low = new Map(), stack = [], onStack = new Set(), out = []
44
+ const visit = (node) => {
45
+ indexes.set(node, index); low.set(node, index); index++; stack.push(node); onStack.add(node)
46
+ for (const target of adjacency.get(node) || []) {
47
+ if (!indexes.has(target)) { visit(target); low.set(node, Math.min(low.get(node), low.get(target))) }
48
+ else if (onStack.has(target)) low.set(node, Math.min(low.get(node), indexes.get(target)))
49
+ }
50
+ if (low.get(node) !== indexes.get(node)) return
51
+ const component = []
52
+ while (stack.length) {
53
+ const value = stack.pop()
54
+ onStack.delete(value)
55
+ component.push(value)
56
+ if (value === node) break
57
+ }
58
+ if (component.length > 1 || adjacency.get(node)?.has(node)) out.push(component.sort())
59
+ }
60
+ for (const node of [...adjacency.keys()].sort()) if (!indexes.has(node)) visit(node)
61
+ return out.sort((a, b) => b.length - a.length || a[0].localeCompare(b[0]))
62
+ }
63
+
64
+ export function architectureViolation(ruleId, kind, evidence, current, target) {
65
+ const normalizedEvidence = String(evidence).replace(/:\d+(?=\b|$)/g, '')
66
+ const fingerprint = architectureHash({ruleId, kind, evidence: normalizedEvidence}).slice(0, 32)
67
+ return {fingerprint, ruleId, kind, evidence, ...(current != null ? {current} : {}), ...(target != null ? {target} : {})}
68
+ }
69
+
70
+ export const matchComponentSelector = (selector, value) => selector.includes('*') || selector.includes(value)
71
+
72
+ export function collectComponentEdges(graph, contract) {
73
+ const nodes = Array.isArray(graph?.nodes) ? graph.nodes : []
74
+ const links = Array.isArray(graph?.links) ? graph.links : []
75
+ const byId = new Map(nodes.map((node) => [String(node.id), node]))
76
+ const componentEdges = new Map()
77
+ for (const link of links) {
78
+ if (!['imports', 're_exports', 'calls', 'references'].includes(link.relation) || link.barrelProxy === true) continue
79
+ const fromFile = fileOfNode(endpointId(link.source), byId)
80
+ const toFile = fileOfNode(endpointId(link.target), byId)
81
+ if (!fromFile || !toFile || fromFile === toFile) continue
82
+ const from = componentForFile(fromFile, contract.components)
83
+ const to = componentForFile(toFile, contract.components)
84
+ if (from === to) continue
85
+ const kind = relationKind(link)
86
+ const key = `${from}\0${to}\0${kind}`
87
+ const record = componentEdges.get(key) || {from, to, kind, count: 0, samples: []}
88
+ record.count++
89
+ if (record.samples.length < 5) record.samples.push(`${fromFile} -> ${toFile}`)
90
+ componentEdges.set(key, record)
91
+ }
92
+ return {nodes, links, byId, componentEdges}
93
+ }
94
+
95
+ export function collectComponentFitness(nodes, links, byId, contract) {
96
+ const stats = new Map(contract.components.map((component) => [component.id, {
97
+ files: new Set(), internalPairs: new Set(), boundaryPairs: new Set(),
98
+ }]))
99
+ for (const node of nodes.filter((item) => !isSymbolNode(item.id))) {
100
+ const file = String(node.source_file || node.id).replace(/\\/g, '/')
101
+ stats.get(componentForFile(file, contract.components))?.files.add(file)
102
+ }
103
+ const runtimePairs = new Set()
104
+ for (const link of links) {
105
+ if (relationKind(link) !== 'runtime' || !['imports', 're_exports', 'calls', 'references'].includes(link.relation) || link.barrelProxy === true) continue
106
+ const source = fileOfNode(endpointId(link.source), byId), target = fileOfNode(endpointId(link.target), byId)
107
+ if (!source || !target || source === target) continue
108
+ const pair = `${source}\0${target}`
109
+ if (runtimePairs.has(pair)) continue
110
+ runtimePairs.add(pair)
111
+ const from = componentForFile(source, contract.components), to = componentForFile(target, contract.components)
112
+ if (from === to) stats.get(from)?.internalPairs.add(pair)
113
+ else {
114
+ stats.get(from)?.boundaryPairs.add(pair)
115
+ stats.get(to)?.boundaryPairs.add(pair)
116
+ }
117
+ }
118
+ return stats
119
+ }