Commit Graph

13 Commits

Author SHA1 Message Date
ruvnet bf8e766875 fix(witness): re-anchor #1862 marker + refresh manifests after #2721
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()).
2026-07-18 19:43:23 -04:00
ruvnet 1f7be650aa chore(witness): keep partial builds out of temporal history 2026-07-16 23:39:54 -04:00
ruvnet 0f6edf172c chore(witness): attest stable hook fallback 2026-07-16 23:25:35 -04:00
ruv 8161a088c8 fix(witness): regenerate + re-sign manifests to close out #2632
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>
2026-07-14 07:12:03 -04:00
rUv 1d5b06e4a2 fix(federation): unblock main — TS shim types + dispatcher import + witness re-sign (#2604)
* 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>
2026-07-09 10:16:55 -04:00
rUv 11f34ec947 chore(release): 3.25.3 — 10 fixes + CI guards (#2602)
* 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>
2026-07-07 22:19:06 -04:00
rUv 402b701a9d fix(security): ADR-165 Phase 1 — close 5 critical CVEs + refresh registry + audit CI gate (#2508)
* 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>
2026-06-29 22:41:24 -04:00
ruv 8c2f03e037 fix: 3 user-reported bugs — #2469 SKILL.md markdown, #2473 witness drift, #2474 ADR importer
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>
2026-06-26 14:40:18 -04:00
ruv f8ab5a3255 fix(witness): #2021 — refresh stale markers, regen signed manifest, add fast drift CI guard
#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>
2026-05-16 19:20:26 -04:00
rUv cffa557449 chore(release): 3.7.0-alpha.27 — ships managed_agent_* (ADR-115) + ruflo-wasm→ruflo-agent (#1934)
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>
2026-05-12 10:44:30 -04:00
rUv 965ec669d9 fix(#1927): ruflo-cost-tracker encodeProjectPath handles Windows backslash + drive colon (#1928)
* 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>
2026-05-12 08:41:58 -04:00
Reuven b4a60e0374 feat: performance verification + capability historical reference
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>
2026-05-09 11:14:47 -04:00
Reuven 9817695a60 feat: per-OS verification cognitive containers + tutorial README
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>
2026-05-09 10:47:43 -04:00