Bump @claude-flow/cli, claude-flow and ruflo to 3.54.1, re-sign the helpers
manifest and regenerate the linux/macos/windows witness manifests.
Co-Authored-By: RuFlo <ruv@ruv.net>
Bump @claude-flow/cli, claude-flow and ruflo to 3.54.0, re-sign the helpers
manifest and regenerate the linux/macos/windows witness manifests.
Co-Authored-By: RuFlo <ruv@ruv.net>
Bump @claude-flow/cli, claude-flow and ruflo to 3.53.0, re-sign the helpers
manifest and regenerate the linux/macos/windows witness manifests.
Co-Authored-By: RuFlo <ruv@ruv.net>
Bump @claude-flow/cli, claude-flow and ruflo to 3.52.1, re-sign the helpers
manifest and regenerate the linux/macos/windows witness manifests.
Co-Authored-By: RuFlo <ruv@ruv.net>
Bump @claude-flow/cli, claude-flow and ruflo to 3.52.0, re-sign the helpers
manifest and regenerate the linux/macos/windows witness manifests.
Co-Authored-By: RuFlo <ruv@ruv.net>
117/117 verified on all three (every marker-cited dist built before regen),
drift 0, Ed25519 signature valid, no newly regressed fix in history.
Co-Authored-By: RuFlo <ruv@ruv.net>
- helpers.manifest.json re-signed for 3.50.0
- verification/{linux,macos,windows}/manifest.md.json regenerated on a clean,
fully built tree: 117/117 verified each, os field stamped per manifest
Co-Authored-By: RuFlo <ruv@ruv.net>
- helpers.manifest.json re-signed for 3.49.0
- verification/{linux,macos,windows}/manifest.md.json regenerated on a clean,
fully built tree: 117/117 verified each, os field stamped per manifest
Co-Authored-By: RuFlo <ruv@ruv.net>
- helpers.manifest.json re-signed for 3.48.0
- witness #1825 marker re-anchored to `"@claude-flow/memory": "3.` (the
stable pin removed the `3.0.0-alpha.` string it quoted); all three OS
manifests regenerated on a clean, fully built tree: 117/117 each
- plugins/ruflo-x-gateway/test/registration.test.mjs joins its siblings in the
ratchet baseline: root vitest cannot resolve the plugin's own deps
(nostr-tools). Its own `npm test` passes 74/74. This was the only CI failure
on #3510.
Co-Authored-By: RuFlo <ruv@ruv.net>
Regenerated on a clean, fully built tree, so all 117 entries verify on each OS
(no dist entries carried forward unattested). Regen was run per OS with the
manifest os field set explicitly, since regen.mjs stamps the runner's OS.
Co-Authored-By: RuFlo <ruv@ruv.net>
#1825 guards against a `workspace:` protocol leak in cli's optionalDependencies
by citing the literal `"@claude-flow/memory": "^3.0.0-alpha.` in
v3/@claude-flow/cli/package.json. #3392 pins that dependency exactly, so the
caret is gone and the marker drifted (witness marker drift smoke, #2021). The
marker is now `"@claude-flow/memory": "3.0.0-alpha.`, which still catches the
`workspace:` leak (that string would not match).
All three manifests were regenerated OS-aware (os field = linux/macos/windows)
with a pristine, unbuilt checkout of the release-bump commit:
- entries whose cited file exists were re-hashed and re-verified (18);
- the 99 entries citing build outputs (dist/) are carried forward unchanged,
not re-attested, because a source checkout does not contain them: that is
exactly the set the CI smoke reports as "file-missing (skipped, #1880)".
The regeneration tool as shipped would mark those 99 unverified, which would
turn 117 verified into 18 for a reason unrelated to this change.
Both witness smokes pass locally: marker-drift (18 pass, 0 drifted) and
verify-precondition.
Co-Authored-By: RuFlo <ruv@ruv.net>
The #2721 hooks.json rewrite legitimately moved the -f/-s CLI-flag
construction logic out of hooks.json and into scripts/ruflo-hook.cjs,
which drifted the #1862 witness marker (it cited the literal bash
string that no longer exists). Re-anchored the marker to the new
location: plugins/ruflo-core/scripts/ruflo-hook.cjs, marker
"['-f', String(file), '-s', 'true']" -- the actual flag-construction
line that replaced the old bash string.
Also did a full witness regen for all three manifests (linux/macos/
windows) against a properly built tree, refreshing the 14 other
entries that had gone stale (sha256 no longer matching current file
content, though their marker text was still verified present --
"drift" per verify.mjs's own terminology, not a real regression: only
"regressed" i.e. marker text actually missing counts as a failure).
Confirmed those 14 are pre-existing on main, unrelated to this PR
(zero diff against origin/main for every file they cite), and were
already recorded as unverified in the previously-committed manifest --
this regen doesn't mask or fix any of them, it just brings sha256
current. All three manifests now show pass=117/drift=0/regressed=0/
missing=0.
(Regenerated with an OS-aware variant of regen.mjs's own algorithm,
since the tool's osDir() stamps whatever OS it's actually run on --
regenerating linux/macos manifests from this Windows machine via the
CLI as-is would have mislabeled their "os" field.)
Also fixed plugins/ruflo-cost-tracker/scripts/smoke.sh's step 28b,
which asserted literal substrings (track.mjs, TRACK_QUIET=1, || true)
directly in hooks.json -- true before #2721, no longer true now that
those live one level down in ruflo-hook.cjs. Updated to verify the
indirection is actually wired (hooks.json references ruflo-hook.cjs,
which references track.mjs/TRACK_QUIET/a resilient always-exit-0 done()).
The reported regressed=2 (markers #1697/#1795) is not reproducible on
current main — verify.mjs was run against an unbuilt tree (18 dist/
files missing across non-cli packages triggers the `dist-not-built`
precondition and drift, not a real regression). Re-ran verify.mjs
against a full `pnpm --recursive run build` (same build step CI's
witness-verify job uses) on all three platform manifests:
ok: true, pass: 117, drift: 0, regressed: 0, missing: 0
Regenerated + re-signed each manifest at commit 901a10d20 per the
issue's own recommended fix, converting the accumulated benign drift
back to fresh sha256 hashes.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(federation): sync shim types + guard optional close() to unblock Build V3
Fixes 7 TS errors on main that block Build V3 across all 3 platforms:
- src/transport/midstream-aware-loader.ts:39-52 — local AgentMessage/
AgentTransport shim was over-minimized by #2578. Restored required
{id, type, payload, metadata?} on AgentMessage and made send/onMessage
2-arg (address, message) to match how plugin.ts actually calls them.
- src/transport/midstream-aware-loader.ts:84 — cast dynamic import()
through `unknown` since upstream's exported AgentTransport carries a
richer InboundMessageHandler surface we intentionally hide behind the
minimal shim.
- src/plugin.ts:481 — this.transport.close is optional (`?`) on the
shim; guard with optional chaining `close?.()`.
Local tsc build clean after fix.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(federation): dispatcher import + re-sign witness manifests (3.25.3 drift)
Two more preexisting main-red root causes, in the same fix:
(1) inbound-dispatcher.ts:22 still imported `AgentMessage` from
`agentic-flow/transport/loader` — the exact phantom subpath #2578
eliminated in midstream-aware-loader.ts. Repointed to the local
shim. This is the residual site #2578 missed; the graph schema smoke
(ADR-130 P1) failure was a cascade of this same TS type collision.
(2) Re-signed verification/{linux,macos,windows}/manifest.md.json via
plugins/ruflo-core/scripts/witness/regen.mjs. The 3.25.3 release
(PR #2602) edited the ADR-104-transport `desc` string in all 3 per-OS
manifests but did not re-run regen.mjs, so the stored
integrity.manifestHash no longer matched sha256(JSON.stringify(
manifest)) and Witness verify exited 1 across all 3 platforms.
Manifests now verify cleanly (117 pass, 0 drift, 0 regressed).
Note: witness/regen.mjs takes --manifest + --history and re-signs
deterministically from manifest.gitCommit; already wired but the
3.25.3 release process skipped it.
Local verify: pass=117 drift=0 regressed=0 missing=0 on all 3 OSes.
Local tsc build: clean.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(hooks): PreToolUse hook emits valid JSON verdict (#2613)
Cursor imports third-party Claude Code hooks under its stricter
`preToolUse` contract, which requires stdout to be a valid JSON
permission verdict (`{"permission":"allow"|"deny"|"ask"}`) and
fail-closes on any other text. The prior PreToolUse commands ran the
ruflo hook shim which prints telemetry to stdout — Cursor then blocked
every Bash/Write/Edit tool call across every workspace.
Fix:
1. ruflo-hook.sh (all three copies) — redirect stdout to /dev/null in
addition to stderr. Claude Code doesn't consume this stdout either,
so silencing it is a pure cleanup with no functional cost.
2. hooks.json PreToolUse commands — after invoking the shim, always
`printf` a well-formed `{"permission":"allow"}` verdict. Valid for
both Claude Code's JSON-hook contract and Cursor's stricter
preToolUse contract, so telemetry keeps working while nothing is
blocked. Also guard `${CLAUDE_PLUGIN_ROOT:-}` so an unset env var
collapses to the safe empty branch instead of a bash parse error.
Simulated Cursor invocation (CLAUDE_PLUGIN_ROOT unset) now emits:
{"permission":"allow"}
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): indirect optional-dep imports in cli — @ruvector/*, @metaharness/router (#2608)
Same install-safety anti-pattern as #2586's prime-radiant fix, now
surfaced in @claude-flow/cli once plugin-agent-federation's TS2307
stopped masking it (630034ca4 on this branch). Build V3 fails with
"Cannot find module '@ruvector/learning-wasm'" and
"Cannot find module '@metaharness/router'" whenever the optional deps
aren't installed — which is the case in the install-safety /
Build V3 configurations.
Every call site is already runtime-guarded (try/catch, availability
probes). But a literal `await import('@ruvector/learning-wasm')` or a
`typeof import('@metaharness/router')` type expression forces tsc to
statically resolve the specifier at build time, so TS2307 fires when
the package is absent.
Fix: route the specifier through a string-typed variable
(`const pkg: string = '...'; await import(pkg)`) — same idiom as the
optional better-sqlite3 loader and #2586. Runtime behaviour unchanged:
the package still loads when present, still falls back cleanly when
absent.
Also replaced services/ruvector-training.ts's static `import type
{ WasmMicroLoRA, ... } from '@ruvector/learning-wasm'` with local
`type X = any` aliases (mirrors the existing FlashAttention et al.
pattern a few lines below).
Verified: with @ruvector/learning-wasm, @ruvector/attention, and
@metaharness/router hidden locally (matching the CI condition), the
cli package now compiles clean (tsc, 0 TS2307). plugin-agent-federation
remains clean as well.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(smoke): add metaharness optionalDep to ruflo wrapper (ADR-150 constraint #2)
The all-plugins-smoke, metaharness-ci `score`, and no-metaharness-smoke
CI jobs all fail on the same single step (ruflo-metaharness smoke #16):
→ 16. ruflo wrapper has metaharness in optionalDependencies
(architectural constraint #2) ... FAIL:
ruflo wrapper missing metaharness optionalDep
ADR-150 §"Architectural constraint" rule #2 requires `metaharness` and
`@metaharness/*` packages to live in `optionalDependencies` (never
`dependencies`) so ruflo remains operational when they're removed. The
CLI already satisfies this; the wrapper package.json had an empty
`optionalDependencies` block.
Pin to `~0.3.1` — the current npm-published `metaharness@latest`, and
the same range family used by CLAUDE.md's `@metaharness/router@~0.3.2`
pin. Wrapper install remains graceful-fail when the optional dep is
absent (that's the whole point of ADR-150's removable rule #1).
Unblocks PR #2604 merge. Only 3 CI failures on the branch — all
the same rule — so this single change flips them green.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(smoke): reconcile ADR-150 rule #2 with #2561 npx-startup budget
Two CI gates were mutually incompatible on this PR:
- ruflo-metaharness smoke #16 (older): asserted \`metaharness\` MUST be
in \`ruflo/package.json\` optionalDependencies.
- guard #2561 (newer): enforces \`RUFLO_MAX=0\` optionalDependencies
AND FORBIDs \`metaharness\` specifically, because installing it as a
ruflo postinstall dep timed out the \`npx -y ruflo@alpha --version\`
fast-path (measured incident).
Adding \`metaharness\` to ruflo optDeps satisfies #16 but breaks #2561;
removing it satisfies #2561 but leaves #16 red (pre-existing main state).
Fix: correct the smoke #16 rule. ADR-150 §"Architectural constraint"
rule #2 says "when \`@metaharness/*\` or \`metaharness\` appears in a
package's dep graph, it MUST be in \`optionalDependencies\`, never
\`dependencies\`". It does NOT require ruflo to depend on metaharness.
The old check was over-restrictive — it demanded PRESENCE, not just
correct SHAPE-when-present. The new check enforces the actual invariant:
no \`metaharness\` / \`@metaharness/*\` in ruflo's hard \`dependencies\`.
Absence is fine (ruflo delegates to @claude-flow/cli, which keeps
metaharness as a runtime dynamic import via ADR-150 rule #1).
#2561 is stronger evidence (proven cold-npx timeout) than the old #16
assertion, so the correction goes to #16.
Verified locally:
smoke #16 PASS (new logic)
guard #2561 PASS
Also reverts the ruflo/package.json optionalDeps change that briefly
tried to satisfy the old #16 rule — the wrapper stays clean.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(init): heal duplicate MCP registrations without breaking plugin refs (#2612)
Users who followed pre-rename setup docs ended up with two independent
MCP server registrations pointing at the same binary — one keyed
`claude-flow`, one keyed `ruflo` — doubling Claude Code's tool-schema
load (~350 duplicated tools) with zero added capability. Bug #2612.
The naive fix (rename the canonical key from `claude-flow` → `ruflo`)
silently re-opens #2206 (closed), because ~166 plugin files across
plugins/**/{agents,commands,skills}/*.md reference tools with the
`mcp__claude-flow__*` prefix. Claude Code derives the tool prefix from
the MCP server key; flipping the key to `ruflo` renames every plugin
tool to `mcp__ruflo__*` and every one of those 166 refs errors with
"Unknown tool".
Correct reconciliation:
- Canonical MCP key STAYS `claude-flow` (preserves #2206 for the 166
plugin refs). The binary invoked is `ruflo@latest` — only the
registration name is legacy.
- Duplicate is HEALED via `ruflo doctor`, not by renaming: detect
coexisting `ruflo`-keyed + `claude-flow`-keyed registrations for
the same binary, warn, and instruct the operator to remove the
`ruflo`-keyed one.
Changes:
- src/init/mcp-generator.ts — server key restored to `claude-flow`;
manual `claude mcp add …` commands restored to name `claude-flow`.
Comment now explains the #2206/#2612 duality.
- src/init/executor.ts — writeMCPConfig skip-comment updated to
reflect that `claude-flow` is canonical and `ruflo`-keyed is the
legacy duplicate form; existing detection accepts both keys (was
already correct).
- src/init/claudemd-generator.ts — generated CLAUDE.md `Setup`
section restored to `claude mcp add claude-flow -- …`.
- src/commands/doctor.ts — inherit the concurrent session's
duplicate-detection logic (rufloLocations / duplicateLocations /
legacyLocations / currentLocations), but flip which key is
treated as canonical: `claude-flow`/`claude-flow_alpha` are
current, `ruflo`/`ruflo_alpha` are legacy. Fix-message now
references removing the `ruflo`-keyed entry and cites #2206.
- src/commands/swarm.ts — help output uses `claude mcp add
claude-flow` again.
- __tests__/issue-2612-mcp-rename.test.ts — regression guard for the
duplicate-detection warning; header comment documents the
canonical/legacy roles matching the flipped semantics.
- CLAUDE.md / v3/@claude-flow/cli/CLAUDE.md / v3/@claude-flow/mcp/CLAUDE.md /
v3/implementation/init/API.md — kept the binary-update from
`@claude-flow/cli@latest` → `ruflo@latest` (correct, this IS the
post-rename wrapper), but restored the MCP server KEY to
`claude-flow` in every example line.
Verified:
- tsc clean (CLI package)
- all 70 test files / 726 tests pass locally, including:
- __tests__/init-wizard-bugs.test.ts (#2206 canonical key + #2207 dual-key detection)
- __tests__/stale-mcp-key-2369.test.ts (10 tests, unchanged)
- __tests__/issue-2612-mcp-rename.test.ts (new — asserts doctor
surfaces "Duplicate Ruflo MCP registrations found" with legacy
`ruflo` + current `claude-flow`)
- Manual doctor run against a synthetic .mcp.json/.claude.json pair
surfaces the exact warning + remediation string.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): neural status ReasoningBank row shows Empty despite persisted patterns (#2575)
Derive the Status cell from the same count Details displays so the label
matches the number (7798 patterns → Active) instead of the stale in-memory
handle.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): default memory store --upsert=true to fix store→delete→store UNIQUE violation (#2594)
memory_entries has UNIQUE(namespace, key) that does not exclude soft-deleted rows,
so a store→delete→store cycle reliably hits UNIQUE constraint failed when --upsert
defaults to false. storeEntry() already honors upsert via INSERT OR REPLACE; flipping
the CLI default closes the footgun without touching schema or plumbing.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): remove reverse-substring collision in GAIA isAnswerCorrect (#2566)
The reverse check normExpected.includes(normModel) scored fragmentary model
answers as correct whenever they normalized to any substring of the expected
answer (e.g. "a" vs "Paris, France" → true), inflating GAIA scores via
normalization collision. ADR-169 R1 forbids this vector. Forward-substring
and numeric-tolerance paths remain.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): skip onnxruntime-node postinstall to unblock v3 memory smoke (#2590)
onnxruntime-node's postinstall fetches a GPU nupkg from nuget.org which
ETIMEDOUTs from GitHub runners, taking pnpm install down. Skip it via
neverBuiltDependencies (CPU prebuilds ship in the npm tarball, so runtime
is unaffected) and pass --ignore-scripts in the memory smoke workflow as a
belt-and-braces safety net.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): drop verifyMemoryInit writeback that races better-sqlite3 handle on Windows (#2596)
sql.js verification holds an in-memory DB copy; writing it back via
atomic rename fights the open better-sqlite3 WAL handle owned by
ControllerRegistry / repairVectorIndexes, producing EPERM on Windows.
Verification is read-only — close and discard the copy instead.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): auto-heal doctor Learning Bridge sidecar on plain run (#2599)
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): prune CLI optionalDependencies to fix cold npx timeout (#2561)
Cold `npx -y @claude-flow/cli@alpha --version` (and the ruflo wrapper)
timed out because npm had to resolve and place ~30 optional deps before
Node ever ran the in-process --version fast-path in bin/cli.js. Trim
optionalDependencies to the 5 actually used by the default CLI path
(agentdb, ruvector, agentic-flow, @claude-flow/memory, @claude-flow/security);
everything else is already gated behind try/require or the plugins-store
lazy-install path. Mirror the pruning in the ruflo wrapper. Add a
pre-warm npm install step in verification-pipeline.yml as defense-in-depth.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): align ruflo-hook.cjs npx fallback with .sh dist-tag (#2600)
The three shipped .cjs Windows shims hardcoded ruflo@latest while the bash
shim used ruflo@alpha, breaking the "mirrors ruflo-hook.sh" contract from
#2132. Point all three .cjs shims at ruflo@alpha and extend the smoke
test with a static parity assertion so future drift fails CI.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): replace phantom agentic-flow/transport/loader marker in ADR-104 witness (#2578)
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): re-sign + verify helpers manifest in prepublishOnly (#2593)
Manifest drift (intelligence.cjs was bumped in 3.24/3.25 but the manifest
still carried the 3.23.0 hash) triggered writeCriticalHelpers' fail-closed
tamper warning on every CLI run in stamped projects. Root cause: sign-helpers.mjs
existed but was never wired into publish. This wires sign+verify into
prepublishOnly so drift fails the release, not every user.
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2590): guard against regression of #2590
Adds a CI guard step to the memory-smoke job that fails fast if either
part of the #2590 fix regresses:
1) v3/package.json drops "onnxruntime-node" from pnpm.neverBuiltDependencies
2) the memory-smoke pnpm install loses --ignore-scripts
Either regression would let onnxruntime-node's postinstall fetch a GPU
nupkg from nuget.org and ETIMEDOUT on GitHub runners, taking pnpm install
down as it did on main.
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2594): guard against regression of #2594
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2561): guard against regression of #2561
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2593): guard against regression of #2593
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2596): guard against regression of #2596
Adds a vitest regression test asserting verifyMemoryInit() does not
modify the on-disk DB file — snapshots bytes+mtime before, calls verify,
asserts unchanged after. Fails if the sql.js writeback is re-added
(bytes change from re-serialization, mtime bumps), passes on the fix.
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2566): guard against regression of #2566
Locks in the removal of the reverse-substring branch in
isAnswerCorrect() (v3/@claude-flow/cli/src/benchmarks/gaia-agent.ts).
The reverse rule `normExpected.includes(normModel)` scored fragmentary
model answers (e.g. "a") as correct against any longer expected answer
that contained them ("Paris, France"), inflating GAIA scores via
normalization-collision — the vector ADR-167/169 R1 forbid.
Verified: FAILS if the reverse-substring branch is reintroduced,
PASSES on the current fix.
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2578): guard against regression of #2578
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(2599): guard against regression of #2599
Co-Authored-By: RuFlo <ruv@ruv.net>
* chore(release): 3.25.3 — 10 fixes + CI guards
Bumps @claude-flow/cli, claude-flow (umbrella), ruflo (wrapper) to 3.25.3.
Regens v3 pnpm-lock.yaml after optionalDependencies pruning (#2561) and
neverBuiltDependencies additions (#2590).
Fixes included:
- #2561 npx cold-install timeout — pruned CLI optionalDependencies
- #2566 GAIA isAnswerCorrect reverse-substring collision
- #2575 neural status ReasoningBank Empty vs 7798 patterns display
- #2578 ADR-104 phantom agentic-flow/transport/loader witness marker
- #2590 CI Node24/ubuntu memory smoke — onnxruntime-node postinstall block
- #2593 helpers.manifest.json auto-refresh — verify + sign in prepublishOnly
- #2594 memory store UNIQUE violation — flip --upsert default to true
- #2596 memory init Windows EPERM — drop sql.js writeback race
- #2599 doctor Learning Bridge — self-heal via recordMemoryPackagePath
- #2600 Windows shim dist-tag parity — align @alpha across all shims
CI guards added per fix.
Co-Authored-By: RuFlo <ruv@ruv.net>
* 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>
Three bugs, one branch — all verified locally before commit.
**#2469** (AriESQ) — \`agent-docs-api-openapi/SKILL.md has malformed markdown\`
The file had two adjacent \`---\` fenced YAML blocks at the top. Only
the first is valid frontmatter; the second renders as \`<hr>\` + raw
YAML text on skills.sh / GitHub web view. Wrapped the legacy agent
YAML in a \`yaml\` code fence so it renders as code instead of leaking
into the page body. Outer Claude Code skill frontmatter untouched.
**#2473** (verification HIGH) — witness manifest drift=8/9/9 on all 3 platforms
My merge of #2468 changed 9 source files; their SHA-256s no longer
matched the signed witness manifests. The Ed25519 seed is derived
from gitCommit alone (\`sha256(gitCommit + ':ruflo-witness/v1')\`), so
signatures generated on any one platform validate everywhere; only
the manifest's \`os\` metadata field differs between the three.
Re-signed all three with current HEAD source hashes — \`drift=0\` on
all 3 platforms (was 8/9/9).
**#2474** (reimon) — ruflo-adr \`adr-index\` stores 0 records on common conventions
Five distinct bugs in \`plugins/ruflo-adr/scripts/import.mjs\`:
1. **(fatal)** Em-dash titles broke \`memoryStore\`: \`npm exec\` rejects
args starting with non-ASCII dash, so every value-with-em-dash
died with \`Records stored: 0/N\`. Use \`--flag=value\` form so npm
sees a single argv token.
2. \`parseStatus\` only matched \`**Status**:\` (colon outside bold) —
missed the widely-used \`**Status:**\` (Nygard / MADR) form. Now
accepts both placements.
3. Body relationship regexes (\`**Supersedes**:\` etc.) had the same
bug. Replaced with a shared \`REL(label)\` builder that accepts
either colon placement and an optional qualifier (\`**Supersedes
(partial):**\`).
4. ID normalization mismatch: \`parseId\` kept \`ADR-0001\`, \`extractAdrRefs\`
pad-then-stripped it to \`ADR-001\` → same ADR dangled. Single
\`normalizeAdrId()\` now governs both paths.
5. \`.claude/worktrees/*\` mirrors the repo; \`SKIP_DIRS\` didn't
exclude \`.claude\`, so every ADR was indexed 2-3x. Added \`.claude\`
to \`SKIP_DIRS\`.
Verified with a synthetic fixture (3 ADRs: 1 zero-padded, 1 mixed,
1 ADR-prefixed; em-dash titles; \`**Status:**\` and parenthetical
qualifiers; \`**Supersedes:**\` / \`**Depends-on:**\` body relations;
decoy worktree dir): \`Records stored: 3/3\`, all status fields
populated, 3 edges parsed, 0 dangling refs, 0 worktree pollution
(was: 0/3, all unknown, 0 edges).
Em-dash fix end-to-end smoke: \`npx @claude-flow/cli@latest memory
store --value="ADR-005 — Repository + Service Pattern"\` succeeds
(was: \`npm error arg Argument starts with non-ascii dash\`).
Reporter @reimon and @AriESQ both filed clear, reproducible bugs with
root-cause analysis — thanks.
Co-Authored-By: RuFlo <ruv@ruv.net>
#2021 (HIGH) fired after the alpha.43 release chain: bumping
`@claude-flow/cli`'s `@claude-flow/memory` pin from alpha.14 → 16
removed the literal string `"@claude-flow/memory": "^3.0.0-alpha.14"`
from `v3/@claude-flow/cli/package.json`, which was the marker for
fix `#1825`. The scheduled cron started reporting `regressed=1` on
all 3 OS manifests.
Three additional ADR markers were ALSO regressed (pre-existing,
not part of #2021's scope) — `ADR-104-transport`, `ADR-107-tls-pinning`,
`ADR-104-stream-mux` — all pointing at
`v3/@claude-flow/plugin-agent-federation/dist/plugin.js`. Those
symbols (`loadQuicTransport`, `agentic-flow/transport/loader`)
moved to `dist/transport/midstream-aware-loader.js` in an earlier
refactor; the markers never followed. Cleaning them up while in here
since they're the same drift class and the new CI guard would block
publish on them anyway.
## Marker fixes (verification/{macos,linux,windows}/manifest.md.json)
#1825 v3/@claude-flow/cli/package.json
marker: "@claude-flow/memory": "^3.0.0-alpha.14"
→ "@claude-flow/memory": "^3.0.0-alpha.
(version-agnostic prefix — survives future bumps)
ADR-104-transport was: dist/plugin.js marker: agentic-flow/transport/loader
now: dist/transport/midstream-aware-loader.js marker: loadQuicTransport
ADR-107-tls-pinning was: dist/plugin.js marker: loadQuicTransport
now: dist/transport/midstream-aware-loader.js marker: loadQuicTransport
ADR-104-stream-mux was: dist/plugin.js marker: loadQuicTransport
now: dist/transport/midstream-aware-loader.js marker: loadQuicTransport
Re-signed all 3 OS manifests via plugins/ruflo-core/scripts/witness/regen.mjs.
History.jsonl appended for each OS.
## Final manifest state (local verify, built tree)
macos: pass=113 drift=0 regressed=0 missing=0 exit=0
linux: pass=113 drift=0 regressed=0 missing=0 exit=0
windows: pass=113 drift=0 regressed=0 missing=0 exit=0
## New CI guard: witness-marker-drift-smoke (#2021)
The slow `witness-verify` job catches drift but runs cross-platform
matrix + dist builds — direct pushes to main (e.g. release chains)
can land before it surfaces a regression. The scheduled 12h cron
then files HIGH-severity issues post-merge.
scripts/smoke-witness-marker-drift.mjs is a fast static-only smoke:
- No build step
- No cryptographic signature check (drift is a markers-vs-source
gap, not an integrity gap — separate concern)
- No native deps
- For every fix in verification/<os>/manifest.md.json:
- If cited file exists AND marker string is missing → exit 1
- If cited file doesn't exist → skip (that's #1880's territory,
handled by witness-verify-precondition-smoke)
Wired into witness-verify's `needs:` so drift blocks publish.
Validated with negative test: broke #1825 marker locally, smoke
exited 1 and named the regressed id correctly; restored, smoke
returned to exit 0.
Co-Authored-By: RuFlo <ruv@ruv.net>
Bumps @claude-flow/cli, claude-flow, ruflo to 3.7.0-alpha.27. Published to npm
(alpha/latest/v3alpha updated for all three) so `npx ruflo@latest mcp start`
exposes the 6 managed_agent_* tools — without this they were on main but not
in any published package, so the /ruflo-agent:managed-agent skill couldn't
find them. Validated: `npx ruflo@3.7.0-alpha.27 mcp tools` lists all 6
managed_agent_* (Enabled); `managed_agent_list` with no key returns the
graceful "use wasm_agent_create" error. Witness manifest regenerated (all
3 per-OS manifests synced, pass=113/0).
What ships since alpha.26: #1928 (ruflo-cost-tracker Windows path), #1929
(ruflo-wasm→ruflo-agent rename + managed_agent_* cloud runtime + ADR-115),
#1932 (README plugin links), #1933 (ruflo-agent README).
Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
* fix(#1927): ruflo-cost-tracker encodeProjectPath handles Windows `\` + drive `:`
`track.mjs` couldn't find Claude Code session jsonls on Windows because
`encodeProjectPath()` only replaced `/` — a no-op on `D:\project\Foo`, so it
looked under a corrupt `~/.claude/projects/D:\project\Foo` instead of the real
`~/.claude/projects/D--project-Foo`. Now replaces `/`, `\`, and `:` with `-`
(matching Claude Code's encoding); POSIX paths are unchanged.
CI guard: smoke.sh step 29b runs `track.mjs` with `TRACK_CWD='D:\project\Subcloudy'`
and asserts the (expected-to-fail) "looked under" line shows `D--project-Subcloudy`
and not the corrupt un-encoded form. Negative-tested. Also fixed smoke.sh step 8
(ADR-0001 is `Accepted`, not `Proposed` — the check was stale; cost-tracker-smoke
was already red on main because of it). Witness marker #1927.
Not fixed here (secondary issue in the report): on long Windows sessions
`spawnSync('npx', ['claude-flow', 'memory', 'store', '--value', JSON.stringify(summary)])`
can exceed the CreateProcess argv limit when `summary` is large — a follow-up
(write to a temp file / stream via stdin).
Co-Authored-By: RuFlo <ruv@ruv.net>
* ci: green up witness-verify (sync linux/windows manifests) + cost-tracker-smoke (.ci-bench npm-init)
Two pre-existing CI reds, surfaced while making sure all builds pass:
- witness-verify on ubuntu/windows failed after #1923: it verifies the
per-OS manifest (verification/{linux,windows}/manifest.md.json), but
regen-witness.mjs only ever rewrites the *current* OS's manifest (macos
on the maintainer's machine), so the linux/windows snapshots still had the
pre-#1923 `#1862` marker — which #1923 changed when it moved the hook
invocation behind ruflo-hook.sh. Synced linux + windows manifests to the
current macos one (byte-identical at the same commit — the Ed25519 seed is
derived from gitCommit only, not OS, and the dist .js are LF everywhere).
All 3 verify clean (pass=113, 0 regressed).
- cost-tracker-smoke `Install agent-booster for the bench` step did
`npm init -y` inside `.ci-bench/`, and npm 11 rejects a package name
starting with `.`. Write the manifest explicitly instead.
Co-Authored-By: RuFlo <ruv@ruv.net>
* ci(v3): run v3-ci.yml on pull_request when verification/** changes (witness-verify on PRs)
Without this, a PR that bumps witness-fixes.json / regenerates a per-OS
manifest doesn't trigger witness-verify, so a stale per-OS manifest only
fails after merge to main (the push trigger does have verification/**).
Co-Authored-By: RuFlo <ruv@ruv.net>
---------
Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
Adds a fourth verification layer alongside the existing three (smoke
tests, witness manifest, marker-presence history): per-OS performance
measurements that catch speed regressions the way markers catch presence
regressions.
What's added
────────────
plugins/ruflo-core/scripts/witness/perf.mjs
Benchmark runner. Each capability is one synchronous bench function
in a runners map; failures throw and get recorded as error entries.
Supports --baseline to compare against the rolling-5 median per
capability and --json for CI consumption.
verification/<os>/performance.jsonl (one per OS, append-only)
Schema: { v, commit, issuedAt, os, capability, durationMs, ... }
Same per-OS organization as manifest.md.json + history.jsonl —
different platforms have different native code paths so absolute
numbers don't compare directly, but per-OS trends do.
verification/CAPABILITIES.md
Historical reference: which capabilities are tracked, why each
matters, reference baselines (macOS-class hardware), and incident
history (#1867 Node 26 install, #1859/#1862 hooks, #1608
bcrypt→bcryptjs, ADR-009 fallback chain). Documents the pattern
of `durationMs` regression detection and the schema.
Capabilities (initial set)
──────────────────────────
install_pack pnpm pack @claude-flow/memory (370ms macOS)
install_no_optional npm install --omit=optional (~5s; CI-skipped)
memory_load cold import('@claude-flow/memory') (18ms)
memory_round_trip createDatabase + store/get + close (CI-skipped)
witness_verify verify.mjs --manifest (53ms)
CI integration
──────────────
v3-ci.yml witness-verify job gains a 'Performance verification' step
that runs the lightweight subset (install_pack, memory_load,
witness_verify) with --baseline and appends results. Heavier benches
(install_no_optional, memory_round_trip) are local-only — adopters
run the full suite during release prep.
Soft gate (`|| echo … non-blocking`) until baselines stabilise; can
be promoted to hard gate by removing the suffix.
Co-Authored-By: RuFlo <ruv@ruv.net>
Reorganizes the verification system into per-OS bundles, addressing
the cross-platform CI matrix added in c51841590.
Layout
──────
verification/
README.md — tutorial-structure docs (was at root)
witness-fixes.json — input config (OS-independent)
results.md — last-run report (was at root)
inventory.json — capability inventory (was at root)
linux/
manifest.md.json — signed by Linux CI
history.jsonl
macos/
manifest.md.json — signed by macOS CI
history.jsonl
windows/
manifest.md.json — signed by Windows CI
history.jsonl
Why per-OS
──────────
File hashes drift across platforms (LF vs CRLF normalization, path
separators, prebuilt binary differences). Each OS produces its own
truthful snapshot. The cross-platform witness-verify CI job runs
once per OS and writes/verifies that OS's bundle, catching
platform-specific marker drift before it reaches users on that
platform.
linux/ + windows/ initially seeded by copying the macOS-generated
manifests; CI on each OS will regenerate its own per-OS bundle on
first push.
Why JSONL inside, not binary RVF
──────────────────────────────────
@ruvector/rvf-node provides a true RVF binary format with native
bindings on all 3 OSes — but it's optimized for vector similarity
search, not key-value retrieval. The witness use case is structured
key-value lookup (snapshot N's commit + fix statuses), so JSONL is
the better fit inside each container. The folder layout adopts the
RVF *cognitive container* concept (per-OS bundle of manifest +
history + metadata); the file format inside is JSONL.
Script changes
──────────────
- lib.mjs: added osDir() platform mapper + 'os' field on manifest +
'os' field on history entries.
- regen-witness.mjs: defaults to verification/<os>/{manifest,history}
using process.platform → osDir.
- v3-ci.yml: witness-verify reads its OS-specific manifest via
$RUNNER_OS dispatch.
Tutorial README
───────────────
verification/README.md rewritten as a tutorial: bootstrap → register
fix → regen → verify → investigate regressions → wire into CI. Plus
features matrix, daily cheat sheet, schema, anti-patterns, integration
with the broader regression stack (Layer 1/2/3 from the agentic-
validation gist).
Co-Authored-By: RuFlo <ruv@ruv.net>