Commit Graph

17 Commits

Author SHA1 Message Date
rUv ddd27576cb fix(release): ship Capability Brain as a self-contained 3.32.30 train (#2829)
* fix(release): bundle policy and Codex runtimes

* fix(release): verify self-contained three-package archives
2026-07-29 01:30:53 -04:00
rUv 1d305b133e chore(release): correct stable train to v3.32.29 (#2826)
Preserve the immutable v3.32.28 source release while moving the npm train to collision-free v3.32.29 and federation alpha.18 coordinates.
2026-07-29 00:24:25 -04:00
rUv dbb1f1e1dd feat: capability brain and governed federation plane (#2825)
Adds the live Ruflo capability brain, governed federation and Cognitum product planes, source-bound concurrent harness contracts, ADRs 325-329, and the v3.32.28 guarded release train.
2026-07-29 00:13:16 -04:00
ruv a02b46e4fb fix(verification): unblock ADR-104 and witness source checks 2026-07-09 10:40:08 -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
ruvnet d687753cc2 fix(federation): cap agentic-flow peer to <2.0.13 (#2364)
agentic-flow@2.0.13 dropped the ./transport/loader subpath from its
exports map. The federation plugin imports
'agentic-flow/transport/loader' for loadQuicTransport, AgentMessage,
QuicTransportConfig, and WebSocketFallbackTransport. With 2.0.13
resolved, that subpath throws ERR_PACKAGE_PATH_NOT_EXPORTED.

Runtime impact is bounded — midstream-aware-loader.ts wraps the dynamic
import in try/catch and returns null on failure, so the plugin falls
back to the midstream-native path rather than crashing. But the peer
range previously said ">=2.0.12-fix.8" which silently accepted 2.0.13;
tighten to ">=2.0.12-fix.8 <2.0.13" so npm install warns about the
incompatibility instead of letting it surface as a runtime fallback.

Type imports continue to work because the devDependency is still pinned
to 2.0.12-fix.8 for typecheck.

This is the in-repo half of the fix. Upstream agentic-flow needs to
either restore ./transport/loader to its exports map (Option A in the
issue body) or publish migration notes for callers (Option B). The
peer cap will widen again once upstream resolves either way.

Closes #2364.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-06-12 08:54:25 -04:00
rUv 455f0b17be fix(plugin-agent-federation): #1949 — agentic-flow → optional peer dep (drops cookies@0.9.1 blocker) (#2013)
Hardened npm registries reject `@claude-flow/plugin-agent-federation@alpha`
with `403 Forbidden` on `cookies@0.9.1` because of a deep transitive
chain (agentic-flow → fastmcp → mcp-proxy → pipenet → koa → cookies).
The plugin only uses agentic-flow for one function (`loadQuicTransport`
as fallback), so it doesn't need to be a hard runtime dep.

**package.json**
- Moved `agentic-flow` from `dependencies` → `peerDependencies` with
  `peerDependenciesMeta.agentic-flow.optional = true`
- Added `midstreamer` as a second optional peer (so an operator can
  pick either or both backends — per ADR-120's Step 2 loader)
- Kept `agentic-flow` in `devDependencies` so vitest + tsc still
  resolve it in this workspace
- Bumped version 1.0.0-alpha.15 → 1.0.0-alpha.16

**midstream-aware-loader.ts**
- Replaced the static value import of `loadQuicTransport` with a
  lazy `loadAgenticFlowQuicTransport()` that uses direct dynamic
  `import()` (vitest-mockable) and falls back to `null` when the
  package isn't installed
- Type imports remain static — they're erased at compile time, so
  TypeScript users still get full IntelliSense without forcing the
  install
- `loadFederationTransport()` now throws a clear, actionable error
  when neither midstreamer nor agentic-flow is present, instead of
  silently crashing on a missing module

**Impact**
- Install size: 529 packages → 2 packages (verified via `npm pack` +
  fresh install in an empty workspace)
- No more `cookies@0.9.1`, no more `koa-router@14.0.0` deprecation
  warning, no more 403 in hardened registries
- 555/555 vitest tests pass (up from 549 — 6 loader tests now
  exercise the new lazy-import path)

**audit-fix-invariants.mjs**
- Added 4 new invariants checking the peer-dep wiring stays in
  place (package.json `peerDependencies` + `peerDependenciesMeta`,
  and the loader's type-only import + lazy loader symbol)
- 38/38 invariants pass

Closes #1949.

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-05-15 07:47:29 -04:00
Reuven 31c6f97891 chore(federation): 1.0.0-alpha.15 — ships ADR-111 Phases 4-6 + Phase 7 staging
Published with both dist-tags atomically:
  @claude-flow/plugin-agent-federation@1.0.0-alpha.15
    alpha:  1.0.0-alpha.15
    latest: 1.0.0-alpha.15

Includes (delta from alpha.14):
  - Phase 4 WgFirewallService — nftables + pf projection
  - Phase 5 WgWitnessService — Ed25519-signed append-only chain
  - Phase 6 federation_wg_status / _attest / _keyrotate MCP tools
  - Security: readSafePeerWgFields validator closes peer-content
    injection vector in buildInterfaceConfig + summarize
  - Phase 7 staging helper (scripts/phase7-stage.mjs)
  - Federation user guide (docs/federation/)

Cross-OS validated: 550/550 tests pass on darwin/arm64 (mac mini)
and linux/x64 (ruvultra). claude -p verified working on both hosts.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-10 23:04:16 -04:00
Reuven f2f1fec3e1 chore(federation): 1.0.0-alpha.14 — ships ADR-111 Phases 1-3
Published with both dist-tags updated atomically per the CLAUDE.md
publishing protocol (closing the gap that produced #1881):

  @claude-flow/plugin-agent-federation@1.0.0-alpha.14
    alpha:  1.0.0-alpha.14
    latest: 1.0.0-alpha.14

Includes:
  - Manifest.wg? section (Phase 1) — Ed25519 sig covers it
  - WgMeshService with no-shell pure projection (Phase 2)
  - Coordinator/breaker WG propagation hooks (Phase 3)
  - 33 new unit tests; 513/513 pre-existing pass

Cross-OS validated: 513/513 tests pass on both darwin/arm64
(mac mini) and linux/x64 (ruvultra) over tailscale. deriveMeshIP
produces byte-identical outputs across hosts for the same nodeId.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-10 22:33:41 -04:00
rUv 056ed8e489 feat(federation): optimizations + ADRs 105-110 (alpha.13 + agentic-flow@fix.8) (#1878)
* feat(federation): ADRs 105-110 — state snapshot + 5 deferred-item ADRs, ship 109+110

ADRs (6 new):
- ADR-105: federation v1 state snapshot (meta-doc, navigation only)
- ADR-106: peer discovery — staticPeers v1, mDNS v2 plan (Proposed)
- ADR-107: TLS — tailnet trust v1, wss/cert pinning v2 (Proposed)
- ADR-108: native QUIC binding plan (Proposed — gated on agentic-flow#15-21)
- ADR-109: receive-side inbound dispatch (Implemented this commit)
- ADR-110: production SpendReporter (Implemented this commit)

ADR-109 implementation (alpha.10):
- Upstream: agentic-flow@2.0.12-fix.3 adds onMessage hook to AgentTransport
  interface + WebSocketFallbackTransport. Backward-compat (optional method,
  callers use ?.()).
- Downstream: new src/application/inbound-dispatcher.ts. Subscribes via
  transport.onMessage in plugin.ts; dispatches each received message through
  security gates (PEER_UNKNOWN, PEER_SUSPENDED, PEER_EVICTED, MISSING_METADATA),
  audits outcome, emits typed eventBus events (federation:inbound:<type>).
- 9 new tests in inbound-dispatcher.test.ts pin the gates.
- Validated mac→ruvultra over tailscale: 3 envelopes sent, all 3 dispatched,
  all 3 audited as message_rejected: PEER_UNKNOWN (correct — peer not in
  discovery, dispatcher fired the gate as designed). Without the dispatcher
  these would have queued silently.

ADR-110 implementation:
- New MemorySpendReporter in src/application/spend-reporter.ts. Storage-agnostic
  via injected MemoryStore interface. Writes to namespace=federation-spend,
  key=fed-spend-<peerId>-<ts> per cost-tracker consumer contract.
  Default TTL 7 days (matches cost-tracker's longest rolling window).
- 13 new tests pin: namespace, key shape, TTL, value round-trip, throw-bubble,
  audit honesty (negative tokens persisted as-is — clamping is breaker's job).

Plugin wiring:
- 472/472 tests pass (was 450 + 9 dispatcher + 13 reporter = 472)
- agentic-flow dep bumped 2.0.12-fix.2 → 2.0.12-fix.3
- 9 services in container (added federation:transport in alpha.9, this commit
  doesn't change count)

Witness manifest: 93 fixes (was 91), ADR-109 + ADR-110 markers added.

Published: @claude-flow/plugin-agent-federation@1.0.0-alpha.10 to npm alpha
tag. Tarball validated: dist/application/inbound-dispatcher.js +
dist/application/spend-reporter.js (with MemorySpendReporter export) both
present, plugin subscribes to onMessage, agentic-flow dep at fix.3.

Remaining ADRs (Proposed status, deferred for stated reasons):
- ADR-106 (mDNS): bonjour-service binding choice + tailnet-vs-LAN security review
- ADR-107 (TLS pinning): cert lifecycle is operator policy; not blocking intra-tailnet
- ADR-108 (native QUIC): gated on upstream agentic-flow Phase-1 (#15-21)

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): wire ADR-104 transport — real mac↔ruvultra peering

ADR-104 documented the design (agentic-flow loader pattern, WebSocket
fallback today, native QUIC roadmap). This commit wires it into the
plugin so federation_send actually moves bytes on the wire.

Changes to src/plugin.ts:
- New dep: agentic-flow@2.0.12-fix.2 (PR ruvnet/agentic-flow#153 patched
  build that fixes the published QUIC stub)
- initialize() loads transport via loadQuicTransport(), registers it as
  federation:transport service
- If config.port is set, transport.listen(port, host='0.0.0.0') binds an
  inbound listener (peers that only initiate outbound leave port unset)
- sendToNode callback now resolves peer.endpoint via discovery.getPeer,
  strips the protocol prefix (ws://, tailscale://), and calls
  transport.send(address, AgentMessage{id, type, payload, metadata})
- shutdown() closes the transport (terminates outbound + inbound clients,
  awaits server close cb)
- Graceful degrade: if transport load fails, plugin logs a warn and
  continues with the legacy in-process noop (preserves backward compat
  for tests/sandboxes without ws available)

Validated end-to-end on real hardware:
  ruvultra (linux/x64): plugin booted, listening on 0.0.0.0:9101
  mac (darwin/arm64):   plugin booted, sent envelope in 150ms over tailscale

Witness manifest: 91 fixes (was 90), ADR-104-transport marker added.

Service-count assertion bumped 7 → 8 (added federation:transport).
All 450 federation tests still pass (transport load is async + safe in
the mocked test PluginContext).

Published: @claude-flow/plugin-agent-federation@1.0.0-alpha.9 to npm
alpha tag. Tarball validated: dist/plugin.js contains 'loadQuicTransport'
+ 'agentic-flow/transport/loader' import + 'federation:transport'
service registration + dep agentic-flow@2.0.12-fix.2.

Co-Authored-By: RuFlo <ruv@ruv.net>

* perf+sec(federation): inbound sig verify + WS deflate compression (alpha.11)

Two optimizations:

1. SIGNATURE VERIFICATION on inbound (security correctness, not perf):
   - Closed the trust gap where dispatcher trusted sourceNodeId in metadata
     as a self-claim. Now requires Ed25519 signature against discovery's
     published peer.publicKey.
   - Outbound: plugin.ts sendToNode canonicalizes the AgentMessage (sorted
     keys, signature stripped) and signs with the local private key,
     attaches signature to metadata.
   - Inbound: inbound-dispatcher.ts canonicalizes received message,
     verifies against peer.publicKey from discovery. Reject INVALID_SIGNATURE
     if missing OR verifier returns false.
   - Peer-state checks (PEER_SUSPENDED/EVICTED) fire BEFORE sig check —
     cheap rejections short-circuit the expensive crypto.
   - 8 new tests + canonicalization spec.

2. WS COMPRESSION on transport (perf):
   - permessage-deflate enabled both server (.listen) and client
     (.getOrCreateConnection)
   - threshold=256B (skip pings), zlib level=3 (balanced), bothNoContextTakeover
   - Verified mac↔ruvultra over tailscale: 10KB highly-compressible
     payload p50=0ms, p95=1ms, p99=1ms, max=1ms over 30 sends —
     SAME as 2KB baseline despite 5x payload size. Compression is
     net-neutral on latency at typical federation message sizes.

Live audit confirms dispatcher fires sig-verify path:
   ruvultra received 31 envelopes from mac, all dispatched +
   audited. Reject path: PEER_UNKNOWN (correct — mac not in discovery,
   pre-sig gate).

Companion: agentic-flow@2.0.12-fix.4 published with the deflate
config (PR #153 fix.3 → fix.4).

Federation: 480/480 tests pass (was 472, +8 sig verify).

Co-Authored-By: RuFlo <ruv@ruv.net>

* perf+sec(federation): wss+pinning (ADR-107 done) + throughput bench (alpha.12)

Pushed past the "deferred" framing for two of the three remaining gaps:

1. **wss + sha256 cert pinning** (ADR-107 → Implemented):
   - agentic-flow@2.0.12-fix.6 adds tls.{certPath,keyPath,pinnedFingerprints,caPath}
     to WebSocketFallbackTransport
   - Server side: when cert+key set, binds via https.Server then attaches WSS
   - Client side: pinning installs fail-closed checkServerIdentity using
     sha256/<base64>(cert.raw); CA-only mode does standard rejectUnauthorized
   - Federation plugin passes config.tls through (no plugin code change —
     loadQuicTransport accepts it)
   - 4 new TLS tests pin: backward compat, pinning config, CA config,
     ws+pinning misconfig graceful ignore (14 tests total in loader spec)
   - Doctor surface for TLS mode deferred until first pinned deployment

2. **Throughput benchmark** (replaces speculative "stream mux needed"):
   - Real measurement mac→ruvultra@9105: 3,826 msgs/sec sustained
     end-to-end receive, 4.1 MB/sec wire bandwidth, 1KB payloads
   - Mac client side hits 200-250k msgs/sec (just JSON-serialize +
     queue), so the bottleneck is tailnet+server CPU, not client
   - 38× headroom over the design point (≤100 RPS per peer per ADR-097)
   - This invalidates the "stream mux needed" framing — head-of-line
     blocking is theoretical at 38× headroom; building app-layer mux
     would be premature complexity

Skipped (after measuring): app-layer stream multiplexing. The data
doesn't justify the cost — premature optimization. If a deployment
ever measures actual HoL blocking we revisit.

Still gated externally: native QUIC binding (agentic-flow#15-21).

Witness manifest: 96 fixes (was 95), ADR-107-tls-pinning marker.

Published @claude-flow/plugin-agent-federation@1.0.0-alpha.12 with
agentic-flow@fix.6 dep.

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): app-layer stream multiplexing (alpha.13)

After my "skipped per data" framing got pushed back: shipped it
anyway because the architectural value is real even if the perf
need isn't pressing.

Upstream agentic-flow@2.0.12-fix.8 adds:
- AgentMessage.streamId?: string | number (default 'default')
- WebSocketFallbackTransport.messageQueue keyed by ${address}#${streamId}
- receive(addr, streamId?) polls the right queue
- onMessage(handler, { streamId? }) — scoped OR catch-all (omit)
- Composes: stream-scoped + catch-all both fire on matching streams

Federation @claude-flow/plugin-agent-federation@1.0.0-alpha.13:
- Pulls agentic-flow@fix.8 transitively
- No plugin code change — backward-compat default streamId='default'

Cross-OS validated mac→ruvultra over tailscale:
- Sent 8 messages interleaved (5 rpc + 3 event)
- ruvultra rpc handler: 5/5 in order
- ruvultra event handler: 3/3 in order
- ruvultra catch-all: 8/8

Why now after I said skipped: the architectural value (clean
per-stream ordering, future QUIC stream mapping, request/response
pattern primitive) is real even when perf headroom is 38×. Premature
optimization framing was wrong — this is feature work, not perf
work, and ~100 lines of impl + 5 tests is cheap.

19/19 loader tests pass.

Co-Authored-By: RuFlo <ruv@ruv.net>

---------

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-05-09 22:05:08 -04:00
rUv 19a569b1a7 feat(federation): ADR-097 phases 2.a/2.b/3-up/4 + ADR-104 transport (#1876)
* feat(federation): ADR-097 Phase 2.a — peer state machine entity layer

FederationNode entity gains a state field (ACTIVE/SUSPENDED/EVICTED) plus
suspend()/evict()/reactivate() methods. All transitions flow through a
canTransition() table in the new federation-node-state.ts value object —
self-loops are rejected (so a duplicate suspend can't reset the
auto-eviction grace timer), EVICTED is terminal under breaker flow,
operator reactivate is the only escape.

Also ships pure helpers isCooldownElapsed + shouldAutoEvict so the Phase
2.b breaker service (separate file, deferred) can drive transitions
deterministically without owning the clock.

27 new tests pin: legal/illegal edges, no-op invariant on duplicate
suspend, EVICTED terminality, props round-trip preservation, cooldown
boundaries, auto-evict grace > cooldown.

Phase 2.b (breaker service wiring cost-tracker → suspend; outbound
short-circuit on !isActive) and Phase 4 (federation_breaker_status MCP +
doctor surface) remain deferred per ADR-097 status table.

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): ADR-097 Phase 2.b — breaker service + outbound short-circuit

Two-layer breaker shipping the active-defense half of the circuit breaker:

1. **evaluatePolicy** (pure) — given rolling samples + node + policy + now,
   returns SUSPEND/EVICT/REACTIVATE_ELIGIBLE/NONE. Cost-takes-priority
   over failure-ratio when both trip (cost is the harder-to-fake signal).
   Auto-evict supersedes reactivate-eligible from SUSPENDED.

2. **FederationBreakerService** — owns per-peer rolling buffer (bounded,
   default 100k samples), wraps evaluatePolicy with entity mutation,
   exposes recordOutcome/evaluate/tick/snapshot/forget. Crucially does
   NOT auto-reactivate — the breaker only signals eligibility; the
   integrator's health probe owns the reactivate() call. This avoids the
   "false-positive recovery" failure mode where a peer flaps SUSPENDED↔
   ACTIVE on transient telemetry.

Coordinator wiring: sendMessage now short-circuits on !peer.isActive
BEFORE session lookup, with PEER_SUSPENDED / PEER_EVICTED constant-string
errors (no remaining-budget echo per the Phase 1 anti-oracle posture).

Security invariants pinned by 25 new tests:
- Negative tokens/usd clamped to 0 (no credit-inflation attack)
- Failure ratio gated on minSamples=10 (anti-noise)
- Strict > on threshold comparisons (boundary correctness)
- EVICTED peers always return NONE (terminal under breaker flow)
- apply=false dry-run preserves entity state

Phase 4 (federation_breaker_status MCP + ruflo doctor surface) is now
unblocked: snapshot() + node.stateRecord give it everything it needs.
Phase 3 upstream (federation_spend bus emission) remains separate work
— when it lands, the bus subscriber calls recordOutcome() and the
in-memory buffer becomes a transparent cache. No breaker code changes.

Witness manifest: 87 fixes (was 85), Phase2b + Phase2b-coordinator
markers signed.

Co-Authored-By: RuFlo <ruv@ruv.net>

* chore(release): @claude-flow/plugin-agent-federation@1.0.0-alpha.6

Ships ADR-097 Phase 2.a (peer state machine) + Phase 2.b (breaker service
+ outbound short-circuit). Published to npm dist-tag alpha; latest is
held at alpha.5 until the breaker bakes for one /loop cycle.

Verified: tarball contains dist/application/federation-breaker-service.js,
dist/domain/value-objects/federation-node-state.js, and PEER_EVICTED
short-circuit in dist/application/federation-coordinator.js. All three
witness markers present in the published artifact.

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): ADR-097 Phase 4 — operator surface (3 MCP tools + doctor)

Closes the loop on the breaker so operators can see and operate it:

**3 new MCP tools** (mcp-tools.ts):
- federation_breaker_status — per-peer state snapshot + bucket counts;
  optional nodeId filter
- federation_evict — operator-initiated MANUAL_EVICT with audit log +
  session-termination side effect; idempotent (already-evicted returns
  false but still emits audit for operator visibility)
- federation_reactivate — escape hatch from SUSPENDED (after probe) or
  EVICTED (operator override)

**Coordinator additions** (federation-coordinator.ts):
- getPeerStates() — projects stateRecord over discovery.listPeers()
- getPeerStateCounts() — O(peers) bucket count for status lines
- evictPeer() / reactivatePeer() — async wrappers that audit-log every
  outcome (applied:true/false in metadata)

**Doctor health-check** (cli/doctor.ts):
- checkFederationBreaker — probes plugin loadability + asserts
  FederationNodeState export presence (catches version-skew where users
  have a pre-Phase-2 plugin installed). Optional plugin → "not
  installed" is a pass, not a fail. Selectable as `--component federation`.

**Plugin index exports** — FederationNodeState + breaker primitives so
external integrators (and the doctor probe) can detect Phase 2/4
support.

11 new coordinator tests pin: bucket-count math, audit emission on
both success/no-op evict paths, EVICTED → ACTIVE operator override,
unknown-peer no-op (no audit silence). 60 plugin-level tests updated
to assert the 12-tool count.

Witness markers added: ADR-097-Phase4-mcp + ADR-097-Phase4-doctor.
89 signed fixes in the manifest (was 87).

Published @claude-flow/plugin-agent-federation@1.0.0-alpha.7 to npm
alpha tag. Tarball validated: all 7 markers (Phase 2.a + 2.b + 4)
present in dist/.

ADR-097 status: Phases 1, 2.a, 2.b, 3-consumer, and 4 all Implemented.
Only Phase 3 upstream (federation_spend bus emission) remains
deferred — when it lands, the breaker's in-memory rolling buffer
becomes a transparent cache with zero breaker code changes.

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): ADR-097 Phase 3 upstream — closes ADR-097 100%

The last remaining "Deferred" entry from ADR-097's status table. With
this, the breaker has end-to-end telemetry: integrators call
coordinator.reportSpend() after each downstream agent completes, and
the event fans out to TWO subscribers in parallel:

1. SpendReporter — pushes to whatever durable backend the integrator
   wires (cost-tracker memory namespace, Datadog, accounting DB). The
   event shape matches the cost-tracker consumer in
   plugins/ruflo-cost-tracker/scripts/federation.mjs verbatim:
     { peerId, taskId, tokensUsed, usdSpent, ts, success }

2. FederationBreakerService.recordOutcome — feeds the breaker's
   in-memory rolling buffer so cost/failure-ratio thresholds fire
   correctly. Without this fan-out, integrators would have to wire two
   parallel pipelines for the same telemetry.

Both integrations are constructor-optional. A coordinator with neither
still accepts reportSpend() calls (silent no-op) so callers don't
branch on configuration.

**New files:**
- application/spend-reporter.ts — SpendReporter interface,
  FederationSpendEvent type, InMemorySpendReporter reference impl
- __tests__/unit/coordinator-spend-reporting.test.ts — 10 tests
  pinning fan-out, contract shape, ts auto-fill, throw-bubble

**New MCP tool:** federation_report_spend (13 tools total)

**Coordinator constructor:** added optional 9th arg
`integrations: { spendReporter?, breakerService? }` — backward-compat
since omission preserves the existing 8-arg shape.

**Anti-coupling design:** federation doesn't own model pricing; the
caller owns it. reportSpend() is an explicit POST-completion call,
not auto-emitted from federation_send. Future enhancement could
auto-emit a "predicted cost" placeholder, but deferred until a
concrete request justifies the additional state.

**Witness:** 90 signed fixes (was 89). Phase 3 upstream marker added.

**Published:** @claude-flow/plugin-agent-federation@1.0.0-alpha.8 to
npm alpha tag. Tarball validated — all 8 markers (Phase 2.a + 2.b +
3-upstream + 4) present.

ADR-097 status: ALL FIVE PHASES IMPLEMENTED (1, 2.a, 2.b, 3-consumer
+ 3-upstream, 4). Future work is integrator-side (production
SpendReporter adapter that persists to ruflo memory; auto-emit
predicted-cost placeholder).

Co-Authored-By: RuFlo <ruv@ruv.net>

* chore(release): umbrella alpha.20 — ships ADR-097 Phase 4 doctor surface

Bumps + publishes the 3-package umbrella chain:
- @claude-flow/cli@3.7.0-alpha.20
- claude-flow@3.7.0-alpha.20
- ruflo@3.7.0-alpha.20

All three on alpha + latest + v3alpha tags per CLAUDE.md publishing
rules. Static check confirms `checkFederationBreaker` ships in the
published @claude-flow/cli@alpha dist (3 occurrences in
package/dist/src/commands/doctor.js).

Now visible to users:
- `npx ruflo@latest doctor --component federation` reports plugin
  loadability + version-skew detection (catches users running an
  older pre-Phase-2 federation plugin against the new MCP tools)

Federation plugin already at @claude-flow/plugin-agent-federation
@1.0.0-alpha.8 (published earlier this session) — installs via
`npm install @claude-flow/plugin-agent-federation@alpha`.

Witness manifest re-signed with new release versions; 90 fixes still
verified. No new fix entries since this is a release-only bump (the
underlying code already shipped in the prior 3 commits today).

Co-Authored-By: RuFlo <ruv@ruv.net>

* docs(adr): ADR-104 — federation wire transport (agentic-flow loader, WS today, QUIC roadmap)

Documents the transport selection for ADR-097 federation. Smoke test
mac↔ruvultra over tailscale revealed agentic-flow's published QUIC is
API-only — loadWasmModule returns {}, encode/decode are placeholders,
crates/agentic-flow-quic/src/wasm.rs explicitly notes the WASM build is
a stub since browsers can't do raw UDP.

Decision: adopt the loadQuicTransport() loader pattern with WebSocket
fallback. Same AgentTransport interface today (WS) and tomorrow (native
QUIC when it lands — set AGENTIC_FLOW_QUIC_NATIVE=1). Federation code
stays transport-agnostic.

Validated: real mac→ruvultra:9101 over tailscale, 125ms send latency
(real I/O, not the prior 0ms stub).

Upstream contribution:
- ruvnet/agentic-flow#153 — adds quic-loader.ts to the published inner
  package, with WebSocketServer-backed real fallback
- Patched build published as agentic-flow@2.0.12-fix.1 (`fix` dist-tag)
  so federation can consume the working transport without waiting for
  upstream merge

12h verification routine updated with Check 8 (ADR-104 transport smoke):
- Pulls agentic-flow@fix
- Stands up real WebSocketServer + client send round-trip on localhost
- Asserts real send latency (>0, <5000ms) — catches if a future regression
  re-introduces the no-op stub behavior
- SEVERITY:HIGH if stub regression detected

Re-open this ADR when:
- ruvnet/agentic-flow ships native QUIC binding
- Federation traffic exceeds ~100 RPS to any single peer
- Federation peers cross outside tailnet boundary
- We have measured WS-vs-QUIC switch data

Co-Authored-By: RuFlo <ruv@ruv.net>

* feat(federation): wire ADR-104 transport — real mac↔ruvultra peering

ADR-104 documented the design (agentic-flow loader pattern, WebSocket
fallback today, native QUIC roadmap). This commit wires it into the
plugin so federation_send actually moves bytes on the wire.

Changes to src/plugin.ts:
- New dep: agentic-flow@2.0.12-fix.2 (PR ruvnet/agentic-flow#153 patched
  build that fixes the published QUIC stub)
- initialize() loads transport via loadQuicTransport(), registers it as
  federation:transport service
- If config.port is set, transport.listen(port, host='0.0.0.0') binds an
  inbound listener (peers that only initiate outbound leave port unset)
- sendToNode callback now resolves peer.endpoint via discovery.getPeer,
  strips the protocol prefix (ws://, tailscale://), and calls
  transport.send(address, AgentMessage{id, type, payload, metadata})
- shutdown() closes the transport (terminates outbound + inbound clients,
  awaits server close cb)
- Graceful degrade: if transport load fails, plugin logs a warn and
  continues with the legacy in-process noop (preserves backward compat
  for tests/sandboxes without ws available)

Validated end-to-end on real hardware:
  ruvultra (linux/x64): plugin booted, listening on 0.0.0.0:9101
  mac (darwin/arm64):   plugin booted, sent envelope in 150ms over tailscale

Witness manifest: 91 fixes (was 90), ADR-104-transport marker added.

Service-count assertion bumped 7 → 8 (added federation:transport).
All 450 federation tests still pass (transport load is async + safe in
the mocked test PluginContext).

Published: @claude-flow/plugin-agent-federation@1.0.0-alpha.9 to npm
alpha tag. Tarball validated: dist/plugin.js contains 'loadQuicTransport'
+ 'agentic-flow/transport/loader' import + 'federation:transport'
service registration + dep agentic-flow@2.0.12-fix.2.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(deps): regenerate pnpm-lock — was out of sync since alpha.9 (agentic-flow dep adds)

* chore: bump agentic-flow dep to 2.0.12-fix.8 to match lockfile (CI fix)

---------

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-05-09 21:55:49 -04:00
rUv b9e2eb37e0 fix(deps): bump vulnerable vitest pins to ^4.0.16 (#1609) (#1819)
Several @claude-flow/* packages still pinned vitest to ^1.x or ^2.x.
That range pulls vite <=6.4.1 → esbuild <=0.24.2, which carries
GHSA-67mh-4wv8-2f99 (esbuild dev server exposes arbitrary file reads
via network) — npm audit reports 4 moderate-severity vulnerabilities.

Fix is to bump every workspace package to vitest ^4.0.16 (which pulls
vite >=6.4.2, esbuild >=0.25.0, all clear). Most packages were already
on 4.x; this PR bumps the holdouts:

  - @claude-flow/aidefence              ^1.1.0 → ^4.0.16
  - @claude-flow/browser                ^2.0.0 → ^4.0.16
  - @claude-flow/codex                  ^1.4.0 → ^4.0.16
  - @claude-flow/plugin-agent-federation ^1.6.0 → ^4.0.16
  - @claude-flow/plugin-iot-cognitum    ^1.6.0 → ^4.0.16
  - @claude-flow/testing peerDep        >=1.0.0 → >=4.0.16

The lockfile regenerated cleanly — net 590 lines smaller as the dual
vitest 1.x / 2.x transitive trees collapse into a single 4.x tree.

Republish required for the affected packages to land the fix on npm
(this only updates source + workspace lockfile).

Closes #1609.
2026-05-06 16:53:24 -04:00
Reuven f8cd1c9fe2 chore(release): bump to 3.6.25 + regen witness manifest
Versions bumped:
  @claude-flow/cli                  3.6.24 → 3.6.25
  ruflo (umbrella)                  3.6.24 → 3.6.25
  claude-flow (umbrella)            3.6.24 → 3.6.25
  @claude-flow/plugin-agent-fed.    1.0.0-alpha.4 → 1.0.0-alpha.5

Captures 22 commits since 3.6.24:
  - audit_1776853149979 hardening (8 commits): execFileSync sweep,
    fetch timeouts, env validator, file-mode 0600, MCP stdin DoS cap,
    shell injection in github-tools + update/executor
  - test suite cleanup: 25 pre-existing failures cleared → 1933/1933 green
  - perf: dynamic-import sweep across memory-tools / hooks-tools / commands
  - ADR-096 encryption-at-rest Phases 1–4 (vault + session/terminal/memory.db)
  - ADR-097 federation budget circuit breaker Phase 1 (alpha.5 bump)
  - verification.md capability inventory expansion (300 MCP / 49 CLI /
    32 plugins / 43 agents)
  - ruflo-federation Claude Code plugin v0.2.0 docs

scripts/regenerate-witness.mjs (new):
  Reproducible regen — re-hashes every cited dist file, refreshes
  gitCommit / releases / issuedAt, recomputes manifest hash, re-derives
  the deterministic Ed25519 keypair from sha256(gitCommit +
  ":ruflo-witness/v1") via Node's native createPrivateKey/Public from
  PKCS#8 (no @noble dep), re-signs.
  All 27 existing fixes re-verified after CLI dist rebuild.

verification.md "Coverage so far" updated to reflect:
  - the new 3.6.25 release pointer
  - explicit pointers to the inventory section + tasks #25/#26 for
    the unenumerated ADR-096/097 work
  - regen instructions
2026-05-03 21:40:25 -04:00
Reuven db210a93a6 chore: bump to 3.6.22 + plugin-agent-federation@1.0.0-alpha.4
Batched publish: G1 agent_execute, G3 workflow runtime, G7 controller
activation (gnnService + rvfOptimizer), G4 WASM Anthropic fallback,
G2 federation Ed25519 signing/verification.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-03 19:01:40 -04:00
Reuven 6f495369fa feat(G2): real Ed25519 signing + verification in agent-federation plugin
ADR-095 G2 (federation slice). The April audit (@roman-rr) flagged the
"verifySignature returns true unconditionally" stub as a critical
authentication-bypass smoking gun. Independent security audit log
(audit_1776483149979) reached the same conclusion. This commit
replaces the stubs with real Ed25519 cryptography end-to-end:

- Added @noble/ed25519 to plugin dependencies (already in tree).
- Generate or load a persistent Ed25519 keypair on plugin init.
  Persisted to .claude-flow/federation/key-<nodeId>.json with mode 0600
  so the same node identity survives restarts. Falls back to an
  ephemeral key if the file system is read-only — still real crypto.
- Real signChallenge / signManifest using ed.sign() with the local
  private key.
- Real verifySignature / verifyManifest using ed.verify() with the
  peer's public key carried in the message envelope.
- getLocalPublicKey now returns the actual hex-encoded public key
  rather than an empty string.
- coordConfig.publicKey wired to the real key (was '' — the federation
  trust path was effectively keyless before this).

Manifest signing uses a canonical JSON serializer (keys sorted, the
signature field itself excluded) so sign and verify produce
deterministic results across nodes.

Functional check passed: ed.verify() rejects tampered messages and
mismatched public keys, accepts correctly-signed ones. Build clean.

Closes the federation-side of ADR-095 G2. Hive-mind multi-process
transport is a separate effort — the in-process EventEmitter
consensus handler still needs a real transport layer (separate ADR).

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-03 18:26:34 -04:00
rUv 1976c57ccd fix(federation): publish @claude-flow/plugin-agent-federation@1.0.0-alpha.3 with ruflo-federation bin (#1685)
Same class of bug as iot-cognitum: source existed (325 tests passing) but
unpublished, and ruflo-federation marketplace plugin's skills called
`npx @claude-flow/cli@latest federation <subcmd>` — federation isn't a
CLI subcommand. End result: every federation skill failed.

Plugin source (v3/@claude-flow/plugin-agent-federation):
- New src/bin.ts: standalone CLI shim that bootstraps AgentFederationPlugin
  in-memory, parses argv, resolves multi-word commands (federation peers
  add, federation peers remove, etc.), aliases short flags, dispatches to
  CLICommandDefinition handlers. Loads .env for FEDERATION_NODE_NAME,
  FEDERATION_BIND_HOST, FEDERATION_BIND_PORT, FEDERATION_TRUST_LEVEL.
- package.json: add bin {ruflo-federation: dist/bin.js}, files whitelist,
  homepage. Move workspace deps to devDependencies (all imports are
  `import type`, erased at compile — zero runtime workspace dep).
- New README.md with subcommand reference and .env config.

Marketplace plugin (plugins/ruflo-federation):
- Bulk-rewrote 5 files (3 skills + commands/federation.md +
  agents/federation-coordinator.md): now call
  `npx -y -p @claude-flow/plugin-agent-federation@latest ruflo-federation <subcmd>`

Other minor fix:
- plugins/ruflo-swarm/README.md: pin `npx @claude-flow/cli swarm` →
  `npx @claude-flow/cli@latest swarm` for consistency with the other 31 plugins.

Audit result post-fix: 32/32 plugins use working invocation patterns.
- 12 verbs against @claude-flow/cli@latest (all exist: memory, hooks,
  security, neural, swarm, doctor, init, embeddings, status, daemon,
  config, plus session)
- @claude-flow/plugin-iot-cognitum (alpha.5 published)
- @claude-flow/plugin-agent-federation (alpha.3 published — this PR)
- neural-trader (2.7.1 on npm)
- ruvector (0.2.25 on npm)

Smoke test: `npx -y -p @claude-flow/plugin-agent-federation@latest
ruflo-federation status` returns Node ID + session count + healthy flag.

Caveat: the 11 plugins that depend on mcp__claude-flow__* MCP tools
(adr, aidefence, autopilot, browser, daa, goals, plugin-creator, ruvllm,
sparc, wasm, workflows) require the MCP server to be connected — not
audited here.

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-04-30 16:26:23 -04:00
Reuven ecdbe801df feat: @claude-flow/plugin-agent-federation — scaffold, tests, README
Add the Agent LLM Federation Plugin implementing ADR-078:

Plugin scaffold (17 source files, 3,021 lines):
- Domain entities: FederationNode, FederationSession, FederationEnvelope, TrustLevel
- Domain services: PIIPipelineService (14 PII types, confidence scoring, adaptive
  calibration), DiscoveryService, HandshakeService, RoutingService, AuditService
- Application layer: TrustEvaluator (scoring formula with hysteresis),
  FederationCoordinator, PolicyEngine
- Plugin class: 9 MCP tools, 10 CLI commands, 1 agent type
- Clean DDD architecture: domain/application/infrastructure/api layering

Test suite (8 files, 202 tests, all passing):
- Trust scoring formula verification
- PII detection across 14 types with confidence thresholds
- Federation envelope HMAC signing/verification
- Capability gates per trust level
- Audit service with HIPAA/SOC2/GDPR compliance modes
- Routing mode selection (direct default, BFT for state mutations)
- Plugin interface compliance

README updated with federation plugin entry linking to issue #1669.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-29 18:25:20 -04:00