mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-14 14:01:28 +08:00
docs/x-gateway-github-style-metadata
27 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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()). |
||
|
|
1f7be650aa | chore(witness): keep partial builds out of temporal history | ||
|
|
0f6edf172c | chore(witness): attest stable hook fallback | ||
|
|
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
|
||
|
|
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 (
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
3b0dc837af |
chore: project-wide quality sweep — no dead code, no slop, witness-validated (#2139)
* chore(quality-sweep): T1/T3/T5 — dep dedup, dead script removal, stale comment T1 (dead-code — cli): - Remove @claude-flow/memory, @claude-flow/embeddings, @claude-flow/security from `dependencies` section of v3/@claude-flow/cli/package.json. All three are dynamic imports only (await import(…)) and belong solely in `optionalDependencies`. Listing them in both sections triggers the npm 11.x arborist dedupe crash documented in issues #1147 / #2018. T3 (stale scripts): - Delete scripts/regenerate-witness.mjs — standalone implementation that writes to verification.md.json at repo root (file does not exist; the per-OS verification/{os}/manifest.md.json layout landed in a later ADR). No CI reference, no caller. scripts/regen-witness.mjs is the canonical delegating wrapper and is kept. T5 (placeholder claims): - Remove stale "Code subcommand (placeholder for future code analysis)" comment from src/commands/analyze.ts — the command is fully implemented (LOC/TODO/ complexity/security analysis). The comment was left over from an old stub. Tests: 1999 passing | 46 skipped (unchanged). Co-Authored-By: RuFlo <ruv@ruv.net> * chore(quality-sweep): T7/T10 — remove trivial assertion, tighten protobufjs override T7 (test honesty): - Remove expect(true).toBe(true) in coverage-router.test.ts catch block. The catch handled "format not supported is acceptable" — the no-op assertion was misleading (test passed trivially). Replaced with a comment-only path so the intent is visible without fabricating a passing assertion. T10 (dependency hygiene — protobufjs critical): - Add overrides.protobufjs = >=7.5.6 to v3/@claude-flow/cli/package.json. GHSA-xq3m-2v4x-88gg (critical, CVSS 9.8) affects <7.5.5. GHSA-66ff-xgx4-vchm (high) and GHSA-2pr8-phx7-x9h3 (moderate) affect <=7.5.5. The 7.5.4 transitive from @opentelemetry/otlp-transformer (via agentdb optional) and onnxruntime-node (via @xenova/transformers optional) is now forced to 7.5.6+. - Tighten ruflo/package.json overrides.protobufjs from >=7.5.5 to >=7.5.6 to cover the two additional advisories. Tests: 1999 passing | 46 skipped (unchanged). Co-Authored-By: RuFlo <ruv@ruv.net> * chore(quality-sweep): T9 — update STATUS.md to 3.10.x reality; T8 done T9 (docs vs reality): - STATUS.md was pointing at branch fix/issues-may-1-3 / ruflo@3.6.24 (stale). Updated snapshot reference to ruflo@3.10.2 / @claude-flow/cli@3.10.1 @ |
||
|
|
edde98f9eb |
feat(graph): ADR-130 — unified graph intelligence backend (P1-P6) (#2129)
* feat(graph): ADR-130 Phase 1 — graph_edges schema + PQ encoder + edge writer Acceptance criteria met (smoke-graph-schema-migration.mjs: 23/23 pass): - graph_edges table added to MEMORY_SCHEMA_V3 with temporal columns: confidence, decay_rate, last_reinforced, witness_id, embedding_ref - 4 indexes: source_id, target_id, relation, last_reinforced - embedding-quantization.ts: Int8 global-scalar PQ (400 bytes/384-dim) inline:<base64> format; 392.6 KB/1000 edges (<500 KB target) inlineCosine() for zero-decode similarity ranking - graph-edge-writer.ts: thin sql.js accessor with module-level db cache insertGraphEdge, queryEdgesBySource, countGraphEdges, _resetBridgeDb fire-and-forget pattern with flushDb after every write Tracking: #2128 — ADR-130 Phase 1 complete Co-Authored-By: RuFlo <ruv@ruv.net> * feat(graph): ADR-130 P2+P3+P5 — graph-query, trajectory hooks, pathfinder Phase 2 — agentdb_graph-query MCP tool (smoke: 21/21 pass): - k-hop: recursive CTE over graph_edges (sql-cte backend) - pagerank: simple personalized PageRank power iteration (PPR) - semantic: cosine ranking on inline PQ embeddings - complexityBudget enforcement: maxNodesVisited, maxDepth, maxMillis - Falls back gracefully when graph-node native is available Phase 3 — SONA trajectory-to-graph hooks (smoke: 10/10 pass): - hooks_intelligence_trajectory-step: fire-and-forget 'trajectory-caused' edge - hooks_post-task (success=true): fire-and-forget 'reinforced-by' edge - Neither write blocks tool response (<200ms tool latency preserved) Phase 5 — agentdb_graph-pathfinder MCP tool (smoke: 20/20 pass): - 6 algorithm variants: personalized-pagerank, dynamic-mincut, spectral-sparsify, temporal-centrality, connected-component-churn, witness-chain-divergence - depth > 5 clamped; non-existent seed returns empty paths not error - complexityBudget.maxNodesVisited limits traversal Tracking: #2128 — ADR-130 P2+P3+P5 complete Co-Authored-By: RuFlo <ruv@ruv.net> * feat(graph): ADR-130 Phase 4 — plugin adapter contract (GraphEdgesSource) Smoke: 24/24 pass (smoke-graph-plugin-adapter.mjs) - GraphEdgesSource class added to knowledge-graph-adapter.ts implements KnowledgeGraphSource; reads live edges from graph_edges via lazy import of @claude-flow/cli graph-edge-writer falls back to empty edge list when table unavailable (backward compat) - createAutoGraphAdapter(): autoRegister path, no SublinearAdapter impl needed - All 8 existing adapters retain exportAsSparseMatrix (no breaking changes) - ruflo-plugin-creator SKILL.md: documents graph_adapter optional plugin.json field with edgeRelations, nodeTypes, autoRegister fields Tracking: #2128 — ADR-130 Phase 4 complete Co-Authored-By: RuFlo <ruv@ruv.net> * feat(graph): ADR-130 Phase 6 — benchmark + CI integration + witness manifest Benchmark results (scripts/benchmark-graph.mjs): - Write throughput: 2345 ops/sec (>500 target ✓) - SQLite footprint: 578 bytes/edge (<1KB target ✓); PQ raw: 400 bytes/edge ✓ - k-hop depth=1: p99=4.9ms (<10ms target ✓) - k-hop depth=3: p99=0.1ms (<50ms target ✓) - PQ encode p99: 0.063ms (<1ms target ✓) - PQ decode p99: 0.031ms (<0.5ms target ✓) - PQ cosine self-similarity: 1.000000 ✓ 6/6 targets met CI (.github/workflows/v3-ci.yml): - graph-schema-smoke (ADR-130 P1) - graph-query-smoke (ADR-130 P2+P5) — depends on schema - graph-trajectory-smoke (ADR-130 P3) — depends on schema - graph-plugin-adapter-smoke (ADR-130 P4) — depends on schema - graph-benchmark (ADR-130 P6) — depends on all smoke jobs Witness manifest updated via regen-witness.mjs Tracking: #2128 — ADR-130 Phase 6 complete (all phases shipped) Co-Authored-By: RuFlo <ruv@ruv.net> * chore(release): v3.9.0 — ADR-130 graph intelligence P1-P3 Ships all 6 phases of ADR-130 unified graph intelligence backend: - @claude-flow/cli@3.9.0 (latest, alpha, v3alpha) - claude-flow@3.9.0 (latest, alpha, v3alpha) - ruflo@3.9.0 (latest, alpha, v3alpha) Key additions: graph_edges schema, PQ encoder, agentdb_graph-query, agentdb_graph-pathfinder, SONA trajectory hooks, plugin adapter contract. Benchmark: 2345 ops/sec write, 4.9ms k-hop p99, 6/6 targets met. Tracking: #2128 Co-Authored-By: RuFlo <ruv@ruv.net> * fix(graph): CI fixes — ADR-112 guidance, plugin TS types, pnpm install Fix 3 CI failures from PR #2129: 1. Tool description (ADR-112): agentdb_graph-pathfinder was missing 'Use when' guidance — added 'Use when agentdb_graph-query k-hop is not enough' + 'Prefer over prompt-level graph loops' text. audit-tool-descriptions: 325/325 pass (0 violations). 2. Plugin TypeScript build (ruflo-graph-intelligence): dynamic imports of '@claude-flow/cli/src/memory/graph-edge-writer.js' in knowledge-graph-adapter.ts caused TS2307 (module not found) in the plugin's isolated tsc context. Fixed with explicit @ts-ignore + local type alias for the module shape; fallback path unchanged. 3. CI install (graph smoke jobs): npm ci --workspace fails at root — the v3 workspace uses pnpm, not npm workspaces. Switched all 5 graph job install/build steps to pnpm install + pnpm run build inside working-directory: v3, matching the Build V3 job pattern. 4th failure (Smoke / Node 24 ETIMEDOUT onnxruntime-node) is a transient infra network timeout — pre-existing flake, not a regression. Tracking: #2128 Co-Authored-By: RuFlo <ruv@ruv.net> * fix(ci): graph smoke jobs — use pnpm -r build from v3 workspace root The previous fix switched from npm to pnpm but still called pnpm run build from within v3/@claude-flow/cli which fails because that package uses composite TypeScript references to @claude-flow/shared and @claude-flow/swarm — those must be built first. Fix: all 5 graph smoke/benchmark CI jobs now run: cd v3 && pnpm install --frozen-lockfile && pnpm -r build (exact same pattern as Build V3 and browser-rvf-create smoke jobs) Tracking: #2128 Co-Authored-By: RuFlo <ruv@ruv.net> * fix(smoke): resolve sql.js from CLI node_modules in schema + trajectory tests smoke-graph-schema-migration.mjs and smoke-trajectory-graph-edges.mjs called await import('sql.js') bare-specifier — which resolves relative to the smoke script's location (repo root), not the CLI package. In CI, sql.js is only installed under v3/@claude-flow/cli/node_modules. Fix: use createRequire scoped to the CLI dist path so Node resolves sql.js from the correct node_modules. Passes locally and in CI. Tracking: #2128 Co-Authored-By: RuFlo <ruv@ruv.net> * fix(smoke): resolve sql.js from v3 workspace root not cli dist path createRequire from v3/@claude-flow/cli/dist/src/... doesn't find sql.js because pnpm hoists it to v3/node_modules/ (workspace root), not the individual package node_modules. Fix: use createRequire(v3/package.json) as the base — this resolves from v3/node_modules/ which is where pnpm installs shared deps with default hoist settings. Tracking: #2128 Co-Authored-By: RuFlo <ruv@ruv.net> * fix(ci): #ADR-130 P1 — install root sql.js + symlink into v3/ graph-schema-smoke imports sql.js via createRequire on v3/package.json, but sql.js is a transitive dep at the repo root — not declared in any workspace package.json. `cd v3 && pnpm install` doesn't hoist it, so the smoke fails with "Cannot find module 'sql.js'". Same fix pattern as the #2120 memory smoke job: root `npm install` for sql.js, then symlink it into v3/node_modules so the v3-scoped require resolves correctly. No duplicate install. Co-Authored-By: RuFlo <ruflo-bot@users.noreply.github.com> * fix(ci): ADR-130 — switch graph smoke scripts to bare sql.js import The createRequire(v3/package.json) pattern failed in CI because pnpm install inside v3/ does not reliably expose sql.js to scripts run from the repo root. Switch both smoke scripts to `await import('sql.js')` (bare ESM specifier) which resolves from root node_modules — the same pattern used by smoke-memory-stats-legacy-db.mjs which passes CI. All 5 graph CI jobs now have an `npm install --legacy-peer-deps` root deps step before the pnpm build step. The stale symlink step in the graph-schema job is removed. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(ci): #ADR-130 P2+P5 — same sql.js install + symlink for query/pathfinder smoke Smoke passes locally (21/0) but fails CI (3/17) with "graph_edges DB unavailable" — same root cause as the P1 smoke: sql.js isn't hoisted into v3/node_modules where the v3-scoped createRequire expects it. Apply the same fix: root `npm install` for sql.js, then symlink into v3/node_modules. Co-Authored-By: RuFlo <ruflo-bot@users.noreply.github.com> --------- Co-authored-by: RuFlo <ruflo-bot@users.noreply.github.com> |
||
|
|
47a7825b0e |
feat(rvagent): #ADR-129 — full rvagent integration (4 phases) (#2123)
* docs(adr): ADR-129 — rvagent full integration (4 phases, post-3.7.0 baseline) Proposes a 4-phase integration of @ruvector/rvagent-wasm@0.1.0 to make WasmAgents first-class participants in the ruflo swarm. ## Gaps found in current code (verified by deep-researcher) - agent-wasm.ts:165-196 — echo-stub bypass (JsModelProvider never constructed; verified by `grep -rn 'new JsModelProvider'` returns 0 hits). WasmAgent.prompt() either echoes or hits a default — not routed through the v3 provider system from #2042. - agent-wasm.ts:420-429 — buildRvfFromTemplate silently drops template.mcp_tools, so wasm_gallery_create can't surface MCP tools to the agent. - 10 of 13 gallery methods unexposed (loadRvf, configure, getCategories, listByCategory, addCustom, removeCustom, importCustom, exportCustom, getActive, getConfig). - 6 agent introspection methods unexposed (get_state, get_todos, get_tools, turn_count, is_stopped, reset). - No bridge from any of the 35 ruflo plugins to the WASM agent runtime. ## 4 phases | Phase | What | Smoke | |---|---|---| | 1 | JsModelProvider → callAnthropicMessages bridge | smoke-wasm-provider-bridge.mjs | | 2 | wasm_agent_compose + addMcpTools bridge (314 tools) | smoke-wasm-rvf-compose.mjs | | 3 | 16 new MCP tools (gallery CRUD + introspection) | smoke-wasm-gallery-crud.mjs | | 4 | Plugin bridge contract | smoke-wasm-plugin-bridge.mjs | ## Top 3 risks 1. Billing expansion — Phase 1 turns wasm_agent_prompt into billable LLM calls (was echo). 2. addMcpTools over-permissioning — Phase 2 default must be explicit allowlist, not full dump (314 tools include destructive ones like memory_delete, federation_*). 3. importCustom prompt-injection — Phase 3 deserializes user JSON in the WASM runtime; AIDefence gate required. No phase needs a separate ADR. Anchored in #2042 (provider routing), ADR-115 (rvagent rename), ADR-127 (smoke pattern). Co-Authored-By: RuFlo <ruflo-bot@users.noreply.github.com> * feat(rvagent): #ADR-129 P1 — JsModelProvider routes WasmAgent through v3 provider system Wire set_model_provider() at agent-creation time so the WASM runtime's internal conversation loop dispatches through callAnthropicMessages (Anthropic / OpenRouter / Ollama, same routing as agent_execute #2042). Echo-stub fallback preserved for keyless environments. Smoke + CI job added: smoke-wasm-provider-bridge.mjs / wasm-provider-bridge-smoke. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(rvagent): #ADR-129 P2 — wasm_agent_compose + addMcpTools bridge (314-tool unlock with allowlist gate) Fix silent drop of template.mcp_tools in buildRvfFromTemplate; extend buildRvfContainer to accept mcpTools param → builder.addMcpTools(). Add wasm_agent_compose MCP tool with explicit allowlist, destructive-tool gate (mcpToolsAllowDestructive required for *_delete/*_shutdown/federation_*), and includePlugins P4 wire. Smoke + CI job: smoke-wasm-rvf-compose.mjs. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(rvagent): #ADR-129 P3 — 16 new MCP tools (10 gallery CRUD + 6 introspection) with AIDefence gate on import Add wasm_gallery_load_rvf, configure, categories, list_by_category, add_custom, remove_custom, import (HIGH_RISK + AIDefence gate), export, active, config. Add wasm_agent_state, todos, tools, turn_count, is_stopped, reset. Export 10 new functions from agent-wasm.ts. Smoke + CI job: smoke-wasm-gallery-crud.mjs. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(rvagent): #ADR-129 P4 — plugin manifest "rvagent" field + includePlugins in compose Add loadPluginManifest() + extractPluginSkills() to wasm-agent-tools.ts. wasm_agent_compose gains includePlugins?: string[] — reads each plugin's .claude-plugin/plugin.json, parses rvagent.exposeSkillsAsTools, and adds matching skills to the RVF container. Unknown plugin name → warning, not error. Smoke + CI job: smoke-wasm-plugin-bridge.mjs. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(ci): #2120 — memory smoke uses pnpm (workspace: protocol unsupported by npm) The memory-stats-legacy-db-smoke job hit `EUNSUPPORTEDPROTOCOL: Unsupported URL Type "workspace:"` in CI because `cd v3/@claude-flow/cli && npm install` ran against a package.json with workspace:* deps that only pnpm understands. Same pattern as the agent-execute smoke fix. Switch the job to pnpm/action-setup + `pnpm install` + `pnpm --filter @claude-flow/cli build`. The smoke logic is unchanged. Co-Authored-By: RuFlo <ruflo-bot@users.noreply.github.com> * fix(rvagent): #ADR-129 — pad 16 new wasm tool descriptions to ADR-112 spec (>=80 chars + Use-when guidance) Co-Authored-By: RuFlo <ruv@ruv.net> * feat(rvagent): #ADR-129 — benchmark suite (provider routing, compose, gallery CRUD, plugin enum) Co-Authored-By: RuFlo <ruv@ruv.net> * feat(witness): #ADR-103 — register ADR-129 P1-P4 fixes in witness manifest Co-Authored-By: RuFlo <ruv@ruv.net> * fix(ci): #2120 — pnpm install must run from v3/ (workspace root) My prior fix ( |
||
|
|
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> |
||
|
|
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> |
||
|
|
ef73a1616f |
feat(ruflo-agent): rename ruflo-wasm → ruflo-agent + Claude Managed Agents (cloud) runtime — ADR-115 (proposed→accepted, implemented) (#1929)
* docs(adr): ADR-115 — Claude Managed Agents as a cloud backend for rvagent (explored + validated)
Records the proposal to add `runtime: "managed"` to ruflo's rvagent
interface (ruflo-wasm / @ruvector/rvagent-wasm / wasm_agent_* MCP tools),
backed by Anthropic's Claude Managed Agents API (beta), as a second backend
alongside the local WASM sandbox — mirroring the ConsensusTransport
LocalTransport|FederationTransport pattern (ADR-095 G2 / ADR-104). The
agent/environment/session/events model maps ~1:1 to wasm_agent_create/
prompt/files/terminate + the gallery.
Validated live against api.anthropic.com/v1 with the org's Anthropic key
(GCP claude-flow/anthropic-api-key): created an agent + environment + session,
sent a bash task, observed the full event log (status_running → user.message
→ tool_use(bash) → tool_result → agent.message("Done.") → status_idle,
stop_reason end_turn), cleaned up. ~7s for a trivial Haiku task.
High-value combos noted: ruflo's own MCP server as a Managed Agent tool
source (cloud-hosted ruflo, zero local infra); Managed Agent session as a
third task_assign executor (closes #1916 items 3/4); long-running/async work;
skills + define-outcomes parity. Constraints: opt-in/off-by-default, needs
ANTHROPIC_API_KEY + beta access, plugin-level @anthropic-ai/sdk dep,
cost-tracking + orphaned-session GC, beta churn, branding.
Status: proposed. Registered in AgentDB (adr-ADR-115) + adr-patterns.
Co-Authored-By: RuFlo <ruv@ruv.net>
* refactor(plugins): rename ruflo-wasm → ruflo-agent (agent-runtimes home; ADR-115 prep)
`ruflo-wasm` only covered local WASM-sandboxed agents (rvagent —
@ruvector/rvagent-wasm, the wasm_agent_*/wasm_gallery_* MCP tools). It's
becoming the home for *all* ruflo agent runtimes: the existing local-WASM
backend plus Anthropic's Claude Managed Agents as a cloud backend (ADR-115),
behind one interface — same local-vs-cloud pattern as ConsensusTransport.
- git mv plugins/ruflo-wasm → plugins/ruflo-agent
- plugin.json: name ruflo-wasm → ruflo-agent; description/keywords now span
both runtimes (rvagent/wasm + managed-agents/anthropic/cloud)
- .claude-plugin/marketplace.json entry renamed
- README / plugins/README / docs/index / cli README / ruflo README /
discover-plugins SKILL / verification/inventory.json / ADR-115 — refs updated
- wasm_agent_* / wasm_gallery_* MCP tool names are unchanged (they stay; the
plugin is just renamed). managed_agent_* tools land next per ADR-115.
(Left `ruflo-wasm-mcp` in ruvocal/workerClient.ts alone — unrelated worker MCP name.)
Co-Authored-By: RuFlo <ruv@ruv.net>
* feat(cli): managed_agent_* MCP tools — Claude Managed Agents cloud runtime (ADR-115)
Six new MCP tools wrapping Anthropic's Claude Managed Agents REST API (beta,
`anthropic-beta: managed-agents-2026-04-01`) via plain fetch — no new SDK dep:
managed_agent_create agents.create + environments.create + sessions.create ↔ wasm_agent_create (CLOUD counterpart)
managed_agent_prompt events.send(user.message) + poll events until idle ↔ wasm_agent_prompt
managed_agent_status GET /v1/sessions/{id}
managed_agent_events GET /v1/sessions/{id}/events (full transcript) ↔ wasm_agent_files
managed_agent_list GET /v1/sessions
managed_agent_terminate DELETE /v1/sessions/{id} (+ optionally the env) ↔ wasm_agent_terminate
Needs ANTHROPIC_API_KEY (or CLAUDE_API_KEY); every tool degrades gracefully
with a structured "use wasm_agent_* for a local no-key runtime" error when the
key is absent — the CLI/MCP server stays up. ADR-112-compliant descriptions
(each says when wasm_agent_* / native is the right call instead). Registered
in mcp-client.ts. Lives conceptually in the `ruflo-agent` plugin (the
`ruflo-wasm`→`ruflo-agent` rename in the prior commit).
Validated live against api.anthropic.com with the org's Anthropic key (GCP
claude-flow/anthropic-api-key) via `ruflo mcp exec -t managed_agent_*`:
create (haiku) → prompt ("echo … > /tmp/r.txt && cat") → got finished:true,
status:idle, stopReason:end_turn, assistantText:"Done.", toolUses:[bash],
13 events → terminate (sessionDeleted+environmentDeleted). No-key path returns
the graceful error. audit-cli-mcp-tools 311 registered/0 dangling;
audit-tool-descriptions 0 no-guidance; cli build clean.
Co-Authored-By: RuFlo <ruv@ruv.net>
* feat(ruflo-agent): wire the managed-agent (cloud) runtime into the plugin + CI smoke
- skills/managed-agent/SKILL.md — drives the cloud runtime: managed_agent_create
/ prompt / status / events / list / terminate, with the WASM-vs-managed
decision table, the ANTHROPIC_API_KEY prereq + graceful fallback, the
mcpServers-reachability caveat, and the cost/cleanup discipline (a cloud
session bills until terminated). Explicit allowed-tools (no wildcard).
- commands/managed-agent.md — quick "list cloud sessions / status / transcript
/ clean up" command (the cloud sibling of /wasm).
- plugin.json — kept rvagent-wasm + ruvllm-wasm keywords (still built on those);
added managed-agents/anthropic/cloud.
- smoke.sh: step 1 now also asserts name=ruflo-agent + the managed-agents
keywords; step 10 expects ADR-0001 status `Accepted` (was stale `Proposed`,
pre-existing red); new step 12 — managed-agent skill+command exist + all 6
managed_agent_* tools referenced + the skill keeps an explicit allowed-tools
list + offers the wasm_agent_create fallback. 12 passed / 0 failed.
- .github/workflows/ruflo-agent-smoke.yml — new CI job running smoke.sh on any
plugins/ruflo-agent/** change (the plugin had no CI gate before).
Validated: `claude --plugin-dir plugins/ruflo-agent` loads the plugin and lists
its skills (managed-agent, wasm-agent, wasm-gallery); plugin.json + all skill
frontmatters parse; smoke.sh 12/0.
Co-Authored-By: RuFlo <ruv@ruv.net>
* docs(adr): ADR-115 → Accepted + Implementation section (managed_agent_* landed)
Status Proposed → Accepted. Added an Implementation (2026-05-12) section:
the ruflo-wasm→ruflo-agent rename, the 6 managed_agent_* MCP tools (plain
fetch, no new SDK dep, graceful no-key degradation, ADR-112 descriptions),
the managed-agent skill+command, the smoke.sh/ruflo-agent-smoke.yml CI guard,
the live e2e validation (create→prompt→terminate against api.anthropic.com
with the GCP anthropic-api-key) and `claude --plugin-dir` validation, and the
called-out follow-ups (runtime:"managed" unification, deployed HTTP ruflo MCP
server for the cloud-hosted-ruflo combo, task_assign/federation dispatch to a
Managed Agent session, cost-tracking + orphaned-session GC, multiagent/outcomes).
Tracking issue: #1931.
Co-Authored-By: RuFlo <ruv@ruv.net>
* test(cli): no-network guard for managed_agent_* tools (ADR-115)
__tests__/managed-agent-tools.test.ts (10 cases): the 6 managed_agent_*
tools are registered; each has an object inputSchema + a ≥80-char,
ADR-112-ish, unique description that names the wasm_agent_*/native fallback;
and — crucially — every handler degrades gracefully with no ANTHROPIC_API_KEY/
CLAUDE_API_KEY: no throw, structured error mentioning the key + the
wasm_agent_create fallback, no network call (so the CLI/MCP server stays up
offline). Plus managed_agent_prompt's missing-sessionId/message validation.
Co-Authored-By: RuFlo <ruv@ruv.net>
* docs(adr): ADR-115 — add the third runtime (Claude Agent SDK) to the picture
ADR-115 adds the *cloud* runtime (Managed Agents); add a section noting the
natural *third* runtime — the Claude Agent SDK (@anthropic-ai/claude-agent-sdk,
"Claude Code as a library": query()/ClaudeSDKClient, hooks, subagents, MCP,
permission modes, sessions, loads .claude/ config + plugins; runs in-process,
full host trust). ruflo-agent → three runtimes behind one model:
WASM (rvagent) local sandbox, no host fs/net untrusted/portable/offline
SDK (future) your process, your filesystem a real Claude agent loop on the local repo — the in-process `claude -p`
Managed Anthropic cloud container long-running/async, no local infra
The SDK runtime's killer combo: `mcpServers: { ruflo: { command: "npx", args: ["ruflo","mcp","start"] } }` — a *local* stdio MCP server, so the agent gets ruflo's 314 tools with zero deployment (vs Managed Agents needing a reachable URL). Anthropic positions SDK→Managed as prototype→production. Costs: heavy dep (bundles a Claude Code binary), full host trust (no sandbox — least isolated), needs an API key. Implementing it = a follow-up, likely ADR-116 (tracked in #1931).
Co-Authored-By: RuFlo <ruv@ruv.net>
---------
Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
|
||
|
|
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> |
||
|
|
f0ee0f9688 |
fix(#1921): plugin hooks use a resilient shim, not bare npx @alpha per fire (#1923)
* fix(#1921): plugin hooks invoke a resilient shim, not bare `npx @alpha` per fire Every PreToolUse/PostToolUse/Stop hook ran `npx <pkg>@alpha hooks …`, which (a) re-resolves the @alpha dist-tag from the registry on every fire and (b) re-installs from cold cache — and when that install crashes (an arborist `Invalid Version` on npm 10.8.x, deep in a transitive OTEL/grpc subtree) the user sees a hook error in Claude Code after every assistant turn, plus ~7s of wasted registry traffic per turn. Fix: each plugin (`.claude-plugin/`, `plugin/`, `plugins/ruflo-core/`) ships `scripts/ruflo-hook.sh` — prefers an already-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline --yes ruflo@alpha`, and ALWAYS exits 0. hooks.json invokes `"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh" … || true` (the `|| true` covers the unset-$CLAUDE_PLUGIN_ROOT case). stdin (the hook event JSON) passes through unchanged; the stdin-jq-xargs shell-injection-safety pattern in plugin/hooks/hooks.json is preserved. This does NOT fix the underlying arborist crash (which needs the offending empty-`version` package pinned via `overrides` once it's identified on npm 10.8.2 — see the issue thread) — it makes a CLI/install failure invisible and cheap instead of a visible error every turn. CI guard: scripts/audit-hook-commands.mjs — fails CI if any hook `command` uses `npx` without `--prefer-offline`, or invokes the CLI without a non-fatal guard. Wired into v3-ci.yml as `hook-command-audit` (also bash-lints each ruflo-hook.sh and asserts it exits 0 with no CLI on PATH) + added to witness-verify needs[]. Path triggers updated to fire on `**/hooks/hooks.json`, `**/scripts/ruflo-hook.sh`, and `scripts/**`. Witness markers for #1921 + Co-Authored-By: RuFlo <ruv@ruv.net> * fix(#1921): make test-hooks.mjs shim-aware; fix shim-lint CI step; regen witness Rebasing #1921 onto main surfaced 3 CI failures: - plugin-hooks-smoke (ubuntu + macos): test-hooks.mjs substituted only `npx ruflo@alpha` → the local CLI, but the hooks.json now invokes `${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh <args>`. It now also substitutes the shim path → `<cli> hooks <args>` (bypassing the shim, so the test exercises the real CLI flag wiring) and strips the shim's trailing `|| true` so exit codes are still asserted. 7/7 pass. - hook-command-audit shim-lint step: `PATH="/nonexistent" bash "$sh"` set PATH to a dir with no `bash`, so `bash: command not found`. Now invokes bash by full path with `PATH=` empty: `PATH= "$BASH" "$sh"` — the shim's `command -v` is a builtin (works with empty PATH) and the npx fallback fails cleanly under `|| true` → exit 0. (resolved in v3-ci.yml during the rebase.) Witness manifest regenerated; #1862's marker refreshed to match the shim-relocated `post-edit -f "$FILE" -s true` (the documented-flag form is preserved). `ruflo verify` 0 regressed. Co-Authored-By: RuFlo <ruv@ruv.net> --------- Co-authored-by: Reuven <cohen@ruv-mac-mini.local> |
||
|
|
95df0111e0 |
fix(plugins): #1902/#1903/#1904 install-safety + plugin-package CI guard (#1925)
* fix(plugins): #1902/#1903/#1904 install-safety + CI guard published tarballs declared @claude-flow/ruvector-upstream (a never- published package) as a hard dep / strict peer, so `npm install` E404'd. The repo source was already clean (the runtime does `await import(...). catch(() => null)`), so the fix is a republish + a guard. resolve any @claude-flow publish (they're all 3.x prereleases). Repo source already uses ">=3.0.0-0" + optional peers; fix is a republish. plus ./formula and ./convoy subpaths the build never emitted. tsup.config now builds the formula/convoy entries (were commented out) and package.json exports/main/module point at the actually-emitted .js/.cjs filenames. CI guard: scripts/audit-plugin-packages.mjs — fails on (A) unpublished @claude-flow/* hard dep / non-optional peer, (B) bare-stable peer range that can't resolve a prerelease, (C) main/module/exports path not in `files`, (D) post-build, an exports path that doesn't exist on disk. Wired into v3-ci.yml as `plugin-package-audit` (builds plugins first so check D is live) + added to witness-verify needs[]. Witness markers for Version bumps for republish: legal-contracts/healthcare-clinical/ perf-optimizer 3.0.0-alpha.1→2, agentic-qe 3.0.0-alpha.4→5 (repo was stale at 3.5.59), gastown-bridge 0.1.3→0.1.4. Co-Authored-By: RuFlo <ruv@ruv.net> * chore(plugins): bump IPFS registry CID for #1902/#1903/#1904 republish LIVE_REGISTRY_CID → QmeXmAdbWVvT84GfDXPD2Vg1HWhiTW2VdZfRLhkS96KkX2 (re-pinned to Pinata). Reflects the republished plugin versions: @claude-flow/plugin-agentic-qe 3.0.0-alpha.4 → 3.0.0-alpha.5 @claude-flow/plugin-gastown-bridge 0.1.3 → 0.1.4 @claude-flow/plugin-legal-contracts 3.0.0-alpha.1 → 3.0.0-alpha.2 @claude-flow/plugin-healthcare-clinical 3.0.0-alpha.1 → 3.0.0-alpha.2 @claude-flow/plugin-perf-optimizer 3.0.0-alpha.1 → 3.0.0-alpha.2 Also updated the matching `version` fields in the demoPluginRegistry offline fallback. Ships with the next @claude-flow/cli release. Co-Authored-By: RuFlo <ruv@ruv.net> --------- Co-authored-by: Reuven <cohen@ruv-mac-mini.local> |
||
|
|
31f22ff9a9 |
fix(#1916): register agent_logs + hive worker resolution + all 20 dangling CLI↔MCP tools — published 3.7.0-alpha.26 (#1924)
* fix(#1916): register agent_logs MCP tool + resolve hive-spawned workers `ruflo agent logs <id>` called `callMCPTool('agent_logs', …)` against a tool that was never registered → `MCP tool not found: agent_logs`. Registered it in agent-tools.ts. Today it returns the agent's createdAt + lastResult as synthetic entries (per-agent activity logging lands with hive worker execution wiring — #1916 items 3/4, a tracked follow-up) with the documented shape `{ agentId, entries: [{timestamp,level,message,context?}], total }`. Also: `hive-mind_spawn` writes workers to `.claude-flow/agents.json`, a different file from the canonical `.claude-flow/agents/store.json` that agent_status/agent_list/agent_logs read — so `agent status <hive-worker-id>` returned `not_found`. Added `loadAllAgents()` (canonical store ∪ hive store, canonical wins on collision) and routed those three tools through it. NOT in this PR: the task-execution dispatch (#1916 items 3/4 — `task_assign` transitions state but doesn't run a worker; hive metrics stay 0). That needs a design decision (which executor) and is a separate change. CI guard: scripts/audit-cli-mcp-tools.mjs — scans every `callMCPTool('<name>')` in src/commands/*.ts and fails if `<name>` isn't registered in src/mcp-tools/*.ts (the `MCP tool not found` class). Monotone-decreasing baseline at verification/cli-mcp-tool-baseline.json — surfaces 20 *other* CLI subcommands with the same dangling-tool bug (`memory export`, `task retry`, `workflow validate`, `session export`, …; agent_logs is now fixed and not in the list). Wired into v3-ci.yml `tool-descriptions-audit` job (already in witness-verify needs[]). Behavioral guard: __tests__/agent-logs-hive-resolution.test.ts. Witness markers for #1916 + #1916-guard. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(#1916): register the 16 missing CLI↔MCP tools — cli-mcp-tool-baseline → 0 The #1916-guard (scripts/audit-cli-mcp-tools.mjs) surfaced 20 `ruflo <cmd>` subcommands that callMCPTool() a tool that was never registered (would die with `MCP tool not found`). Cleared all of them: - Renamed the coverage tools `hooks/coverage-{route,suggest,gaps}` → `hooks_coverage-{route,suggest,gaps}` (the handlers already existed; the slash names just didn't match the CLI's underscore calls). - Pointed `ruflo swarm stop` / `ruflo stop` at the existing `swarm_shutdown` tool instead of a non-existent `swarm_stop`. - Registered 16 new MCP tools (each with ADR-112 "use when … is wrong" guidance): task_retry, workflow_stop, workflow_validate, session_current, session_export, session_import, memory_detailed-stats, memory_cleanup, memory_compress, memory_export, memory_import, hive-mind_optimize-memory, hooks_teammate-idle, hooks_task-completed, mcp_start, mcp_stop Real where the operation maps cleanly to an existing store/backend (task_retry clones into a fresh pending task; memory_export/import dump & re-store entries; memory_cleanup prunes expired TTLs dry-run-by-default; workflow_validate structurally checks a JSON workflow; session_export/import round-trip the session record; memory_detailed-stats reshapes memory_stats). Honest no-ops with the correct return shape + a `note` where the underlying capability genuinely isn't wired yet (memory_compress — sql.js has no on-disk compression; hive-mind_optimize-memory — structural compaction only, pattern-quality consolidation is the intelligence pipeline's job; hooks_* team hooks — auto-assignment/pattern-learning delegated; mcp_start/stop — the MCP toolset runs in-process, there's no separate server to start/stop). cli-mcp-tool-baseline.json is now 0. tool-descriptions-audit still passes (all 16 new tools carry guidance, ≥80 chars, unique). Full cli test suite green (48 files / 1977 tests). Witness #1916-cli-tools marker added → ruflo verify 107 verified, 0 regressed. mcp-tools-deep.test.ts exception list updated for mcp_start/mcp_stop. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(#1916): register coverageRouterTools + harden the CLI↔MCP audit; bump 3.7.0-alpha.26 Validating the alpha.25 publish caught a gap: `ruflo hooks coverage-route` (and -suggest / -gaps) still failed with `Tool not found: hooks_coverage-route`. Root cause: the coverage tools were defined in ruvector/coverage-tools.ts but their array was never imported into mcp-client.ts's TOOL_REGISTRY — renaming the slash→underscore name didn't help because the file wasn't registered at all. - mcp-client.ts: import + `...coverageRouterTools` in registerTools([…]). - coverage-tools.ts: category 'coverage' → 'hooks' (matches the hooks_* names). - scripts/audit-cli-mcp-tools.mjs: now derives the "registered" set from what mcp-client.ts ACTUALLY spreads into registerTools([…]) (resolving each `...xTools` to its `import { xTools } from '<path>'` and scanning that file), instead of "any src file with a name: definition". So an unregistered tool-source file now correctly produces a dangling-reference flag — this is exactly the gap that let hooks_coverage-* slip through. Version bumped to 3.7.0-alpha.26 (alpha.25 shipped the still-broken coverage tools). Witness manifest regenerated. cli-mcp-tool-baseline.json still 0; audit + mcp-tools-deep + mcp-client tests green. Co-Authored-By: RuFlo <ruv@ruv.net> --------- Co-authored-by: Reuven <cohen@ruv-mac-mini.local> |
||
|
|
ad169de89b |
fix(#1914): daemon start only reaps daemons in the current workspace (#1917)
`killStaleDaemons` SIGTERM'd every process whose command line contained
`daemon start --foreground`, so starting the daemon in workspace B killed
workspace A's daemon — a violation of ADR-014's per-workspace daemon scope.
The forked daemon's argv is now stamped with `--workspace <root>` (kept
last), and `killStaleDaemons{Posix,Windows}` filter on it via
`daemonCommandLineBelongsToWorkspace` — an exact trailing match, never a
bare path-prefix match, so `/a/proj` can't reap `/a/proj-other`'s daemon.
Pre-#1914 daemons (no stamp) are left for `daemon stop` to handle via the
PID file. `resolveWorkspaceFlag` rejects shell metacharacters / null bytes
since the value lands in a forked child's argv.
CI guard: __tests__/daemon-workspace-scope.test.ts (12 cases — cross-
workspace isolation, prefix-sibling, legacy-no-stamp, Windows tasklist
row, space-containing paths) + witness marker for #1914.
Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
|
||
|
|
16e59c2613 |
fix(#1906): agent_execute model aliases → current Claude 4.x ids (not deprecated claude-3.x) (#1908)
`MODEL_MAP` in agent-execute-core.ts mapped haiku/sonnet/opus/inherit to `claude-3-5-haiku-latest` / `claude-3-5-sonnet-latest` / `claude-3-opus-latest` — ids the Anthropic API now 404s. Every `agent_execute` call (and the WASM agent's LLM fallback, which routes through `resolveAnthropicModel`) failed with HTTP 404 even with a valid key. Fixed mappings (Claude 4.x family): haiku → claude-haiku-4-5-20251001 sonnet → claude-sonnet-4-6 opus → claude-opus-4-7 inherit → claude-sonnet-4-6 (= new DEFAULT_ANTHROPIC_MODEL) Also replaced the 4 other hardcoded `claude-3-5-sonnet-latest` defaults (`callAnthropicMessages` fallback, `resolveAnthropicModel` no-input case, `executeAgentTask` fallback, the doc-comment example) with `DEFAULT_ANTHROPIC_MODEL`. ## CI coverage (the user's ask: "make sure the ci guard doesn't miss these") Two layers: 1. Unit test `__tests__/agent-execute-models.test.ts` — picked up by the cli package's vitest run in CI. Asserts each alias resolves to the right Claude-4.x id, the prefix-strip works, the pass-through works, and — critically — `no alias resolves to a claude-3.x id` (the #1906 regression-class assertion). 8/8 pass. 2. Witness marker `#1906` in the manifest — `claude-sonnet-4-6` must be present in `agent-execute-core.js` dist; `witness-verify` fails on regression. 104/104 fixes verified. Closes #1906 · related to #1863 (agent_execute was the path #1863's comment pointed users at — now it actually works) Co-authored-by: Reuven <cohen@ruv-mac-mini.local> |
||
|
|
8aac1b2ccc |
feat(mcp): ADR-112 — 285/285 tool descriptions have 'Use when …' guidance + CI guard + #1892 statusline (#1897)
* docs(adr-095): status update — G1/G3/G4/G6/benchmark remediated (verification receipts)
External re-audit (AlphaSignal AI, May 7) surfaced ADR-095 gaps publicly.
Verification pass on current main shows 4 of 7 named gaps already
quietly fixed by the v3.7.0-alpha work:
G1 — agent_spawn intentionally registry-only; real execution wire is
agent_execute → agent-execute-core.ts:117 → Anthropic Messages API
G3 — workflow_execute has a real step executor (workflow-tools.ts:308+);
the 'Workflow not found' error is correct missing-ID handling
G4 — promptWasmAgent (agent-wasm.ts:154) detects echo stub + routes
through callAnthropicMessages when ANTHROPIC_API_KEY set
G6 — refuted via direct measurement: hook is a single routing call,
no trigram/Jaccard symbols, 8 backend entries observed
Bench — simulate_benchmarks.py removed; '84.8% SWE' claim cleaned
from tracked docs
Preserves original ADR text. Adds 'Status update — 2026-05-11' section
at the bottom with file-path receipts. Still open: G2, G5 (→ADR-094),
G7 (per-controller), #1748 (tool descriptions).
Related: #1896 (external audit response)
Co-Authored-By: RuFlo <ruv@ruv.net>
* feat(mcp): ADR-112 — every tool description now has "Use when … is wrong because …" guidance + CI guard + #1892 statusline fix
External audit (AlphaSignal AI, May 7) measured 237/300 MCP tool
descriptions lacked guidance for when Claude should pick Ruflo's tool
over native (Bash/Read/Grep/Glob/Task/TodoWrite). Re-measurement on
current main was actually 279/285 — worse. Now: 0/285.
## ADR-112 + bulk fix
- New ADR documenting the rule: every description must answer
"use this over native when?" with concrete value-add (cost
attribution / learning persistence / coordination / witness chain /
sandbox isolation), and honestly state when native is fine.
- 7 agent-tools.ts descriptions hand-edited (the P1 native-Task overlap).
- 272 remaining descriptions bulk-updated via category-aware suffixes
in scripts/bulk-fix-tool-descriptions.mjs — each tool category
(memory/agentdb/embeddings/swarm/hive-mind/hooks/workflow/browser/
cost/intelligence/aidefence/security/federation/iot/wasm/ruvllm/
config/system/mcp/status/doctor/performance/analyze/progress/transfer/
guidance/claims/terminal/daemon/causal/graph/reasoningbank/search)
gets its own honest "Use when … is wrong because …" suffix.
## CI guard (every tool's description checked)
- scripts/audit-tool-descriptions.mjs scans every MCPTool definition and
enforces three gates per tool:
1. "Use when ..." guidance present (the original ADR-112 check)
2. Description length ≥ 80 chars (catches near-empty descriptions)
3. Description unique across all tools (catches lazy copy-paste)
All three baselines stored in verification/mcp-tool-baseline.json
and are monotone-decreasing — CI fails on any regression.
- .github/workflows/v3-ci.yml gains a `tool-descriptions-audit` job
wired into witness-verify needs[] so the release pipeline gates on it.
## #1892 — UI version mismatch
- v3/@claude-flow/cli/.claude/helpers/statusline.js was hardcoded
to "RuFlo V3.5"; now reads from installed @claude-flow/cli's
package.json at runtime via resolveBannerVersion() so the UI matches
`ruflo doctor` output. Resolves across local-checkout / npm-installed /
globally-installed layouts.
## Witness manifest
- verification/witness-fixes.json: ADR-111, ADR-112, #1892 markers added.
- verification/macos/manifest.md.json regen'd — 102/102 fixes verified,
Ed25519 signature valid.
## Tests
- 1963 federation+cli tests pass on this branch.
- Build clean.
- Audit: 285/285 tools with guidance, 0 too-short, 0 duplicates.
Resolves #1748 (tool discoverability)
Resolves #1892 (UI version mismatch)
Tracks #1896 (external audit response)
Co-Authored-By: RuFlo <ruv@ruv.net>
* docs(verification): README — current 102/102 fix count + ADR-112 baseline + Layer 1 smoke jobs
- Folder layout adds mcp-tool-baseline.json (ADR-112)
- Example manifest summary updated 82→102 fixes, alpha.18→alpha.21
- Manifest schema example: added missing 'signature' field
- Integration table expanded with the 5 Layer 1 smoke jobs that exist
today: install, hook, mcp-protocol, memory-import, tool-descriptions
Co-Authored-By: RuFlo <ruv@ruv.net>
* chore(verification): lock ADR-112 baseline at all-zeros for noGuidance, tooShort, duplicates
The enhanced audit-tool-descriptions.mjs now tracks three gates instead
of one. Baseline file was carrying only the original noGuidance count;
running --update-baseline writes all three so future regressions in
any gate fail CI.
Co-Authored-By: RuFlo <ruv@ruv.net>
* ci: fix Performance Verification — download phantom artifact
Long-standing latent bug masked by download-artifact@v3's warning
behavior, surfaced as a hard error by @v4. The job tried to download
build-artifacts-<verification-id> but no job in the workflow has
ever uploaded an artifact under that name; build-verification only
runs npm pack and uploads nothing.
Fix: build the CLI locally inside the perf job (same pattern the
other jobs use) instead of relying on a phantom artifact. Memory-leak
smoke now probes the v3 cli dist binary with a graceful fallback if
the build skipped — keeps the job informational, not blocking.
Affected run: https://github.com/ruvnet/ruflo/actions/runs/25648092044
Triggered by main push of
|
||
|
|
d0c507e643 |
fix(memory): #1883 + #1884 — WSL path resolution + import-key sanitization + CI guard (#1886)
* fix(memory): #1883 + #1884 — WSL path resolution + import-key sanitization #1883 — memory_import_claude(allProjects=false) returned imported=0 on WSL because project-hash derivation only POSIX-slash-replaced cwd. A WSL bridge running Ruflo with cwd `/mnt/c/Users/x/Project Name` could never match the Windows-host Claude Code project dir `C--Users-x-Project-Name`. Fix: resolveProjectMemoryDir() tries multiple candidate hashes (legacy POSIX, WSL `/mnt/<drive>/`-translated, leading-dash-stripped, space-replaced) and returns the first that exists. Also adds optional `projectPath` input parameter as an explicit override for callers in cross-environment setups. #1884 — memory_import_claude wrote keys built from raw frontmatter `name` and section titles directly to storeEntry, bypassing validateMemoryInput. memory_delete enforces it. Any markdown file with shell-metacharacters in section headings (`(`, `)`, `{`, `}`, `[`, `]`, `<`, `>`, `!`, `#`, etc.) produced keys that imported successfully but could not be deleted through MCP — stranded in the database, requiring direct SQLite intervention. Fix: sanitizeMemoryKey() replaces every char in DANGEROUS_KEY_CHARS with `_` before storeEntry. The set is shared with DANGEROUS_KEY_PATTERN used by validateMemoryInput so write-side and read-side can never drift apart. CI guard (catches the bug class going forward): - plugins/ruflo-core/scripts/test-memory-import.mjs: 12 regression checks covering static dist scan (helpers defined + called from import handler), legacy-code negative-attestation, sanitizer property test against 27 adversarial inputs, WSL-fixture and POSIX-compat candidate-set checks. - .github/workflows/v3-ci.yml: new `memory-import-smoke` job (ubuntu+macos), wired into witness-verify needs[]. - verification/witness-fixes.json: #1883 + #1884 markers (resolve…, sanitize…) — witness-verify cryptographically attests both helpers are present in dist on every PR. Why our verification missed these (and is now closed): - Witness manifest catches drift from a known-good baseline. Both bugs were always there; no drift to detect. Closed via new markers + the static dist scan that asserts call-sites, not just helper presence. - CI matrix has Linux/macOS/Windows runners but no WSL-bridge fixture. Closed via deriveCandidates() unit assertion on synthetic WSL cwd. - No round-trip test for write-path/read-path key invariant. Closed via sanitizer property test on 27 adversarial inputs. Local verification: 12/12 regression guards pass; witness-verify clean (99 fixes pass, signature valid). Closes #1883 Closes #1884 Co-Authored-By: RuFlo <ruv@ruv.net> * ci: memory-import-smoke uses recursive --no-bail build The targeted `--filter @claude-flow/cli... run build` doesn't pull in @claude-flow/swarm, which @claude-flow/cli imports from at TS-compile time (TS6305 — referenced .d.ts not built from source). Switching to the same `pnpm --recursive --no-bail run build || true` pattern that witness-verify uses. The smoke script already fails loudly if the cli dist didn't get produced, so we don't lose signal. Co-Authored-By: RuFlo <ruv@ruv.net> --------- Co-authored-by: Reuven <cohen@ruv-mac-mini.local> |
||
|
|
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> |
||
|
|
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> |
||
|
|
d065b2d654 |
fix #1874 + add MCP protocol-compliance smoke layer
The bug
───────
@claude-flow/mcp and @claude-flow/shared returned protocolVersion as
{ major, minor, patch } in the initialize response. The MCP spec
requires a YYYY-MM-DD string. Claude Code's Zod validator rejects
the object form with 'Invalid input: expected string, received
object', so HTTP MCP transport users couldn't connect at all.
Fix
───
- MCPProtocolVersion type: interface with major/minor/patch →
type alias for string (both packages).
- Server constants: '2025-11-25' (mcp) and '2024-11-05' (shared).
- Existing unit test in mcp.test.ts also corrected — it was
asserting the wrong shape, so test + prod agreed on a non-spec
format. This is the most important finding from the
'why did validation miss this' investigation.
- README example updated to spec-compliant string.
Why validation missed it (the gap)
──────────────────────────────────
- Layer 1 (smoke): no smoke test boots the actual HTTP MCP
server, sends a real initialize request, and validates the
wire format. The existing tests only exercise tool execution.
- Layer 2 (witness): tracks fix presence, can't catch
'always-wrong-from-the-start' bugs that have no good baseline.
- Layer 3 (history): same — no marker, no signal.
- The unit test was self-consistent with the buggy production
code. Both used { major, minor, patch }. Nothing measured
against the upstream MCP spec or a real client validator.
Closing the gap
───────────────
plugins/ruflo-core/scripts/test-mcp-protocol.mjs
Boots the HTTP MCP server, sends initialize, asserts response
shape against the spec:
- protocolVersion is a string matching YYYY-MM-DD
- capabilities is an object
- serverInfo has { name, version } strings
Final assertion mirrors what Claude Code's Zod would accept.
v3-ci.yml: new mcp-protocol-smoke job (Linux + macOS), gated
before witness-verify. Three layers of regression guard now
cover this class.
verification/witness-fixes.json: registers #1874-mcp and
#1874-shared. Witness now attests the spec strings are present in
both dist files; future regressions to the object form are caught
by witness-verify, not just user reports.
Impact
──────
84/84 fixes verified in the regenerated manifest (was 82).
Anyone running ruflo mcp start -t http with the new build can now
connect Claude Code without the Zod rejection.
Closes #1874
Co-Authored-By: RuFlo <ruv@ruv.net>
|
||
|
|
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>
|
||
|
|
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
|