* fix(security): ADR-165 Phase 1 — close all critical CVEs, refresh registry, add CI gate
Closes ADR-165 Phase 1. Both workspaces pass `npm audit --audit-level=critical`.
## Before (2026-06-29)
| Workspace | Critical | High | Moderate | Total |
|-----------|----------|------|----------|-------|
| Root | **1** | 6 | 31 | 38 |
| v3 | **4** | 33 | 57 | 97 |
## After
| Workspace | Critical | High | Moderate | Total |
|-----------|----------|------|----------|-------|
| Root | **0** | 0 | 31 | 31 |
| v3 | **0** | 27 | 58 | 88 |
All 5 critical advisories closed (vitest GHSA-5xrq, handlebars prototype-pollution,
protobufjs constructor-pollution, plus 2 more in v3). 12 of 39 high advisories
closed via overrides; the remaining 27 v3 highs are deeper transitive chains
that would require breaking-change major bumps — flagged for ADR-165 Phase 2.
## Changes
### Root workspace overrides (package.json)
- `vitest`: `^1.0.0` → `^3.2.6` (closes critical GHSA-5xrq CVSS 9.8)
- `hono`: `>=4.11.4` → `>=4.12.25` (closes 6 hono advisories)
- `undici`: `>=7.18.0` → `>=8.5.0` (closes 7 undici advisories — bumps the
stale pin that ADR-165 flagged as still-in-vulnerable-range)
- `vite`: `>=6.4.6` → `>=8.0.16` (closes 2 vite advisories)
- NEW `@grpc/grpc-js`: `>=1.14.4`
- NEW `form-data`: `>=4.0.6`
- NEW `http-proxy-middleware`: `>=3.0.7`
- `@hono/node-server`: `>=1.19.10` → `>=1.19.14`
### v3 workspace overrides (v3/package.json + pnpm.overrides)
- `vitest`: `^4.0.16` → `^4.1.0` (and `@vitest/coverage-v8` matched)
- Top-level + pnpm overrides: `handlebars: >=4.7.9`, `protobufjs: >=8.6.0`
- 27 sub-package `package.json` updated to `vitest ^4.1.0`
### CVE registry refresh (v3/@claude-flow/security/src/CVE-REMEDIATION.ts)
Rewritten from 5 stale Jan-2026 entries to 16 total: 15 fixed, 1 open
(ADR165-OPEN-01 — PII pipeline wiring per ADR-164 §6.1 not yet on
dispatch-layer). `SECURITY_SUMMARY` is now computed dynamically from the
registry; `validateRemediation()` correctly returns `allFixed: false`
with 1 issue. ADR-165 §5 flagged this as THE Phase 2 priority — now closed.
### New CI gate
`.github/workflows/cve-audit.yml`:
- `audit-root` — `npm audit --audit-level=critical` in root, blocking
- `audit-v3` — same in v3, blocking
- `audit-high-report` — warn-only summary on high-severity drift
- Triggers: PR, push to main, daily cron
### ADR-165 §9 evidence ledger addendum
Captures AFTER-remediation `npm audit --json` metadata for both workspaces.
The diff between BEFORE (already in §9) and AFTER makes Phase 1 verifiable.
Also CORRECTED one prior surprise in §9: the `validate-input.ts` in
`mcp-tools/` is NOT a 9-line shim. It's 269 lines of real implementation.
(That was an inaccurate findings note from the initial audit.)
### §7.3 research items resolved
- `protobufjs` v3 chain confirmed gone after override pins
- `handlebars` v3 chain confirmed not user-reachable on the workflow path
(toolchain-only; override sufficient)
- `validate-input.ts` confirmed real implementation, not a shim (registry
entry corrected)
- CORS surface check: no `cors()` / `app.use(cors` call sites — the hono
CORS-wildcard advisory is not exploitable on the current server
- ADR-164 §6.1 PII pipeline NOT wired in current agentbbs dispatch —
recorded as ADR165-OPEN-01 (Phase 3 work)
## Gates (all PASS)
- `npm audit --audit-level=critical` root: exit 0 (was non-zero)
- `npm audit --audit-level=critical` v3: exit 0 (was non-zero)
- vitest suites: 105/109 pass (4 skip-conditional — same as before)
- ADR-112 audit: 352/352 tools with guidance
- business-pods smoke: 11/11 PASS
- agentbbs smoke: 8/8 PASS
- agenticow smoke: 8/8 PASS
- cli build: clean (tsc)
## Phase 2+ deferred
The 27 v3 high-severity advisories that remain are transitive chains with
no patched-in-range version. ADR-165 §6 Phase 2 picks these up after the
`cve-watch.yml` automation in §6 lands (NEW PR — not in scope here).
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* chore(lock): regen v3/pnpm-lock.yaml after override updates (PR #2508 CI fix)
PR #2508 added handlebars + protobufjs to v3 overrides + bumped vitest pin,
but v3/pnpm-lock.yaml wasn't regenerated. CI surfaced
ERR_PNPM_LOCKFILE_CONFIG_MISMATCH on every install step.
Same pattern as the previous lockfile-drift fixes on PR #2500 and #2503.
* fix(ci): cve-audit.yml jq-only + regen witness manifests for #1609 marker drift
Two PR #2508 CI failures fixed:
1. Static-regression-guard tripped on cve-audit.yml line 52: the static
YAML strict-parser sees `if high > 0:` inside the `run: |` block as
a YAML block-mapping key indicator. Refactored all 3 inline-python
blocks to use jq (preinstalled on ubuntu-latest) — no embedded
`if x > 0:` lines, so the YAML guard passes.
2. Witness marker drift smoke flagged fix-marker #1609 — the Phase 1
vitest bump (4.0.16 → 4.1.0) drifted the cited marker string in
v3/@claude-flow/aidefence/package.json. Updated `marker` field in
all 3 platform manifests + `desc` to reference ADR-165 Phase 1, then
re-signed via plugins/ruflo-core/scripts/witness/regen.mjs.
Co-Authored-By: RuFlo <ruv@ruv.net>
The bug
───────
@claude-flow/mcp and @claude-flow/shared returned protocolVersion as
{ major, minor, patch } in the initialize response. The MCP spec
requires a YYYY-MM-DD string. Claude Code's Zod validator rejects
the object form with 'Invalid input: expected string, received
object', so HTTP MCP transport users couldn't connect at all.
Fix
───
- MCPProtocolVersion type: interface with major/minor/patch →
type alias for string (both packages).
- Server constants: '2025-11-25' (mcp) and '2024-11-05' (shared).
- Existing unit test in mcp.test.ts also corrected — it was
asserting the wrong shape, so test + prod agreed on a non-spec
format. This is the most important finding from the
'why did validation miss this' investigation.
- README example updated to spec-compliant string.
Why validation missed it (the gap)
──────────────────────────────────
- Layer 1 (smoke): no smoke test boots the actual HTTP MCP
server, sends a real initialize request, and validates the
wire format. The existing tests only exercise tool execution.
- Layer 2 (witness): tracks fix presence, can't catch
'always-wrong-from-the-start' bugs that have no good baseline.
- Layer 3 (history): same — no marker, no signal.
- The unit test was self-consistent with the buggy production
code. Both used { major, minor, patch }. Nothing measured
against the upstream MCP spec or a real client validator.
Closing the gap
───────────────
plugins/ruflo-core/scripts/test-mcp-protocol.mjs
Boots the HTTP MCP server, sends initialize, asserts response
shape against the spec:
- protocolVersion is a string matching YYYY-MM-DD
- capabilities is an object
- serverInfo has { name, version } strings
Final assertion mirrors what Claude Code's Zod would accept.
v3-ci.yml: new mcp-protocol-smoke job (Linux + macOS), gated
before witness-verify. Three layers of regression guard now
cover this class.
verification/witness-fixes.json: registers #1874-mcp and
#1874-shared. Witness now attests the spec strings are present in
both dist files; future regressions to the object form are caught
by witness-verify, not just user reports.
Impact
──────
84/84 fixes verified in the regenerated manifest (was 82).
Anyone running ruflo mcp start -t http with the new build can now
connect Claude Code without the Zod rejection.
Closes#1874
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix: intelligence layer loads flat array from auto-memory store
The auto-memory-hook.mjs writes a flat JSON array to auto-memory-store.json,
but intelligence.cjs loadEntries() only checked for store.entries (object
wrapper format). This caused the vector store to load only 1 fallback
pattern from MEMORY.md instead of the full 1,300+ entries.
Now supports both formats: flat array and { entries: [...] } wrapper.
Also fixes deprecated Dirent.path usage (use parentPath first).
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix: apply same loadEntries fix to helpers-generator.ts
The published CLI package generates intelligence.cjs during `init` via
helpers-generator.ts — it had the same flat-array bug. Users running
`npx claude-flow init` would get the broken version.
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix: statusline uses real data instead of hardcoded/estimated values
- Hooks: count actual hook entries instead of hardcoding total=17
- Vectors: count real entries from auto-memory-store.json, not file-size/2
- Tests: scan v3/ directory (depth 6), was missing ~2000 test files
- Swarm: only show active if state updated within 5 min (stale check)
- Security: flag as STALE if audit older than 7 days
- ADRs: count actual files (76), don't use stale compliance JSON (7)
- Intelligence: scale to 2000 entries = 100% instead of 100 entries
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix: apply statusline accuracy fixes to generator (end-user path)
The statusline-generator.ts always overwrites the bundled statusline.cjs
during init, so all 6 accuracy fixes must be in both files:
- Hooks: count actual entries, not hardcode 17
- Vectors: read real entry count from store JSON
- Tests: scan depth 6, include v3/ directory
- Swarm: 5-min staleness check on metrics
- Security: PENDING when no audit run, STALE after 7 days
- ADRs: count files directly, skip stale compliance JSON
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix: prevent MCP server self-kill on startup (#1380)
Three compounding bugs caused `mcp start` to crash with "Killed":
1. Self-kill: getStatus() reported current process as "running" for stdio
transport, then start command sent SIGKILL to its own PID
2. Config crash: Zod schema rejected partial configs with non-object values
3. Hook exit: process.exitCode=0 was overridden by async errors
Fixes:
- Add isSelfDetected guard to skip kill when PID matches process.pid
- Add .passthrough() to SystemConfigSchema, merge partial configs with defaults
- Use process.exit(0) in .finally() for reliable hook exits
- Remove invalid hook events (TeammateIdle, TaskCompleted, PostCompact)
- Wrap hook commands in sh -c for cross-platform CLAUDE_PROJECT_DIR expansion
Published as v3.5.39. Tested in Docker — clean startup, no warnings.
Closes#1380
Co-Authored-By: claude-flow <ruv@ruv.net>
* docs: add ADR-057 — RVF native storage backend to replace sql.js
Proposes replacing the 18MB sql.js WASM SQLite dependency with
RuVector Format (RVF) across @claude-flow/shared, memory, and
embeddings packages. Includes automatic and manual migration paths
for existing .db and .json files with full backward compatibility.
Key benefits: -18MB install size, 150x-12,500x faster vector search
via native HNSW, quantization support, crash-safe append-only format.
Co-Authored-By: claude-flow <ruv@ruv.net>
* docs: extend ADR-057 with RVF embedding provider, ruvLLM persistence, and progressive download
Add three major sections to ADR-057:
- Section 3A: RVF as 5th EmbeddingProvider (52KB WASM replaces 540MB
agentic-flow for basic use cases). Updated auto-select hierarchy:
rvf > agentic-flow > transformers > mock.
- Section 3B: ruvLLM learning persistence via RVF segments. SONA
patterns (ReasoningBank), LoRA adapters, and EWC++ weights now
survive process restarts. RuVectorProvider.searchMemory works
offline via RVF without HTTP server.
- Section 10: Progressive download architecture. Replaces npm
optionalDependencies (all-or-nothing 1.3GB) with on-demand
capability downloads stored as .rvf files. 5 phases from 22MB
core CLI to full LLM/CNN/GNN/kernel capabilities.
Implementation plan expanded from 5 to 8 phases. Testing strategy
updated with 11 new test cases covering the additions.
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat: add optimized Docker images for Ruflo lite/full/workers
- Dockerfile: Multi-stage Alpine build with aggressive dependency pruning.
Result: 324MB image, 0.6s startup (vs 1.3GB/35s baseline).
Uses --omit=optional + explicit rm -rf of heavy transitive deps.
- Dockerfile.full: Full image variant with all optional dependencies
including native compilation (onnxruntime-node, better-sqlite3).
- Dockerfile.headless: Updated from node:20 to node:22, claude-flow
branding to ruflo, same prune strategy as lite.
- docker-compose.yml: Three profiles (lite, full, workers) with
appropriate resource limits and health checks.
- .dockerignore: Excludes node_modules, tests, source maps, IDE
configs, and secrets from build context.
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat(ADR-057): implement RVF native storage backend across all packages
Replace sql.js (18MB WASM) with zero-dependency RVF format across
memory, events, embeddings, and learning subsystems. Pure TypeScript
fallback with optional native @ruvector/rvf acceleration.
New files:
- memory/rvf-backend.ts: IMemoryBackend impl with HNSW + binary persistence
- memory/hnsw-lite.ts: Lightweight HNSW graph for vector search
- memory/rvf-learning-store.ts: SONA pattern/LoRA/EWC/trajectory persistence
- memory/persistent-sona.ts: PersistentSonaCoordinator wrapping learning store
- shared/events/rvf-event-log.ts: Append-only event log (replaces EventStore)
- embeddings/rvf-embedding-cache.ts: Binary file embedding cache (FNV-1a keys)
- embeddings/rvf-embedding-service.ts: Hash-based embedding provider (<0.1ms)
Integrations:
- DatabaseProvider: 'rvf' added, auto-selected first (always available)
- EmbeddingProvider: 'rvf' added, auto-selected first in async factory
- All packages export new RVF types and classes
Tests: 163 passing (5 suites), validated in Docker (node:22-alpine)
- rvf-backend: 50 tests (CRUD, query, search, persistence, HNSW)
- rvf-event-log: 33 tests (append, replay, snapshots, crash recovery)
- rvf-embeddings: 30 tests (cache, service, determinism, normalization)
- rvf-learning-store: 31 tests (patterns, LoRA, EWC, trajectories)
- rvf-integration: 19 tests (provider selection, migration, concurrency)
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(ADR-057): harden RVF storage with security, performance, and migration
Security: atomic writes (tmp+rename) across all backends, path validation,
input validation at boundaries. Performance: persist lock prevents concurrent
flushes, stack overflow fix for large datasets, timer.unref() prevents hangs,
O(1) eviction lookup in embedding cache. New: bidirectional RVF migration
utility (JSON/SQLite/RVF), format v2 with backward compat, auto-persist
patterns and trajectories before eviction. Added HnswLite and RvfMigrator
exports. 193 tests passing, 0 TS errors.
Refs #1242
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix: doctor version detection and init settings warnings (#1235, #1230)
doctor: Replace unreliable path-walking heuristic with import.meta.url
traversal to find the correct package.json. Removes stale npx cache
scanning that could report wrong versions. Fixes#1235.
init: Remove invalid TeammateIdle and TaskCompleted keys from generated
.claude/settings.json hooks section. These are not recognized by Claude
Code and caused warnings. Config remains available under the claudeFlow
namespace. Fixes#1230.
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(doctor): remove Windows-incompatible shell redirects, simplify root detection
- Remove fragile Windows root calculation (split on backslash); use
dirname(dir) === dir instead which works on all platforms
- Remove 2>/dev/null from npm view command (fails on Windows cmd.exe);
the catch block handles errors gracefully already
Co-Authored-By: claude-flow <ruv@ruv.net>
* security: harden RVF against crafted files and race conditions
- rvf-backend: validate dimensions (1-10000), validate RVF header
structure and size before JSON.parse, guard persist interval
against concurrent flushes
- rvf-embedding-cache: use random suffix for tmp files to prevent
predictable-path attacks on multi-user systems
- rvf-event-log: add 100MB max payload size limit to prevent DoS
from crafted event log files
- rvf-migration: add null byte and type validation on all paths
Co-Authored-By: claude-flow <ruv@ruv.net>
Automatic checkpoint created by Claude Code
- Branch: feature/codex-integration
- Timestamp: 2026-02-07T21:31:00Z
- Changes: 2 file(s)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T19:04:42Z
- Changes: 19 file(s)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T16:02:16Z
- Changes: 1 file(s)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T16:02:05Z
- Changes: 1 file(s)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T16:01:53Z
- Changes: 1 file(s)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Updated standard-checkpoint-hooks.sh to accept both JSON and plain paths
- Fixed pre-edit and post-edit functions to detect input format
- Fixed v3 CLI hook flags (-f -> --file, -c -> --command, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>