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>
The no-metaharness-smoke gate asserts every metaharness skill emits a
\`"degraded"\` field when metaharness is unreachable (ADR-150 #3 —
graceful degradation). All other skills did this already; mint did not
because its dry-run path printed the plan without touching the registry.
Result: smoke-without-metaharness reported \`FAIL: mint did not emit
degraded:true payload\`.
Added a fast \`runMetaharness(['--version'])\` probe at the top of main()
so the dry-run also reports degraded:true when the registry is
unreachable. The probe is the same call the --confirm path uses
internally, so we don't add a new failure mode; we just surface the
existing one earlier.
This was the final red check on PR #2468 — all other 112 checks are
green on commit c73c8d96e.
Co-Authored-By: RuFlo <ruv@ruv.net>
Final ruflo-metaharness smoke contract failure after the count bumps:
test 17o anchors the contract test by enumerating every MCP tool name
and asserting \`tools.length === 9\`. Both lists are deliberately spelled
out so a refactor that drops a tool fails this gate. Added bench/evolve/
security_bench and bumped the count assertion to 12.
Co-Authored-By: RuFlo <ruv@ruv.net>
3 more plugin-contract failures from no-metaharness-smoke, all the same
root cause: ADR-153 added bench/evolve/security_bench MCP tools but the
smoke contract had hardcoded counts pinned to the pre-ADR-153 tool set.
- 17z53: \`runScript('foo.mjs', ...)\` reference count 9 → 12
- 17z9: MCP_SUCCESS_SEMANTIC occurrence count 10 → 13 (1 decl + 12 uses)
- 17z7: \`success: r.success\` handler count 9 → 12
- 17z6: test-mcp-tools.mjs phase-1 \`tools.length === 9\` → 12, plus
the 3 new tool names added to the expectedNames set
These are anchor counts that exist deliberately so a future iter adding
a tool also touches the smoke and CLAUDE.md catalog. Bumping in lockstep
with the 3 new tools.
Co-Authored-By: RuFlo <ruv@ruv.net>
Two plugin-contract failures in the no-metaharness-smoke job for
ruflo-metaharness:
- **17z61** (drift-from-history dispatcher round-trip) used
\`grep -B100\` to walk back from the step to its enclosing job header.
metaharness-ci.yml grew past 100 lines between that step (now line 604)
and its \`metaharness-real-data:\` job header (line 493). Replaced the
fixed-window grep with an awk one-pass that finds the most-recent
top-level job header above the step.
- **17z56** (every MCP tool documented in CLAUDE.md, iter 93) asserted
exactly 9 MCP tools. ADR-153 added 3 more (\`metaharness_bench\`,
\`metaharness_evolve\`, \`metaharness_security_bench\`) without updating
the lock count or the CLAUDE.md catalog. Documented the 3 tools in
CLAUDE.md and bumped the count to 12.
Co-Authored-By: RuFlo <ruv@ruv.net>
Stacked fixes to clear the remaining red CI checks on \`main\` that pre-dated
the #2412 lockfile-cascade fix. Each one verified locally before commit.
1. **Build V3 (ubuntu/macos/windows)** — \`graph-edge-writer.ts\` did a static
\`await import('better-sqlite3')\` which forces tsc to resolve the package's
types at build time. \`better-sqlite3\` is in \`optionalDependencies\` (so
CI doesn't install it) — type resolution failed with TS2307 on every
platform. Routed the module name through a variable so the static analyzer
stops trying to resolve it; runtime presence is still gated by the
existing try/catch.
2. **Static regression guards (#2267)** — \`scripts/smoke-workflows-yaml.mjs\`
crashed with \`SyntaxError: The requested module 'js-yaml' does not provide
an export named 'default'\` after js-yaml dropped the synthetic default
from its package exports. Switched to \`import * as yaml from 'js-yaml'\`.
3. **Tool description discoverability (ADR-112)** — two MCP tools regressed
the no-guidance baseline (count went from 0 → 2):
- \`metaharness_bench\` had no Use-when / Prefer / Pair-with hint
- \`testgen_tdd_repair\` had \"Use when …\" in a *later* string
fragment of a concatenated description, which the audit regex
(single-quoted-literal-only) misses
Added explicit \"Use when …\" guidance to the first fragment of each.
Audit now reports 340/340 tools with guidance.
4. **witness verify precondition smoke (#1880)** — Root \`package-lock.json\`
drifted: \`agentdb@3.0.0-alpha.16\` in lock vs \`^3.0.0-alpha.17\` in
package.json (same root cause as #2412 but for the npm lockfile, not the
pnpm one fixed last release). Every job that runs \`npm ci\` was failing
at install. Regenerated via \`npm install --package-lock-only\`. Verified:
\`npm ci --dry-run --legacy-peer-deps\` now exits 0.
5. **Supply-chain audit (#2046)** — \`plugins/ruflo-graph-intelligence\` had
1 HIGH/CRITICAL unaccepted direct-dep finding:
- \`ws@8.20.1\` pulled by \`sublinear-time-solver\` (GHSA-96hv-2xvq-fx4p,
memory exhaustion DoS) — bumped root override \`ws >=8.18.4\` →
\`>=8.21.0\` and added the same override to the plugin's own
package.json so it propagates through the plugin's own npm install
- \`@claude-flow/cli\` peerDep surfaces every HIGH transitive in cli's
own tree inside the plugin's audit report — added a tracked,
expiring accepted-finding (cli ships its own audit pipeline on
every publish; the plugin doesn't redistribute cli's tree).
Audit now reports \`OK: no hard-fail findings\`.
Verified locally:
- \`npm run build\` in v3/@claude-flow/cli: clean
- \`node scripts/smoke-workflows-yaml.mjs\`: exit 0, 53 workflows parsed
- \`node scripts/audit-tool-descriptions.mjs\`: 340/340 with guidance, OK
- \`npm ci --dry-run --legacy-peer-deps\` at repo root: exit 0
- \`node scripts/audit-supply-chain.mjs\`: OK, no hard-fail findings
Co-Authored-By: RuFlo <ruv@ruv.net>
Adds a new ruflo-testgen surface that closes the loop the existing TDD
plugins didn't — we generate tests, this fixes the code to satisfy them.
Inspired by agent-harness-generator/packages/darwin-mode ADR-175 Test-
Driven Repair mode, but implemented via headless `claude -p` instead of
wrapping `metaharness-darwin evolve`. Rationale:
1. `claude -p` already in our stack (no new optional dep)
2. Bounded cost via --max-budget-usd (first-class flag)
3. Capability-restricted via --allowedTools Read,Edit,Bash
4. Test exit code IS the fitness function (no LLM-as-judge)
5. Resumable via --session-id
Surface:
- plugins/ruflo-testgen/scripts/tdd-repair/tdd-repair.mjs (script)
- plugins/ruflo-testgen/skills/tdd-repair/SKILL.md (skill)
- v3/@claude-flow/cli/src/mcp-tools/testgen-tools.ts (MCP tool:
testgen_tdd_repair)
Pipeline (Test-Driven mode):
1. Pre-flight: run the test command. Refuse if already passing.
2. Spawn `claude -p` with focused prompt (read failing test, fix
source, don't touch test, verify by running it).
3. Re-run test to verify the fix; emit per-attempt receipts incl.
usage.cost_usd from claude's --output-format json.
4. If green: success. If red after --max-attempts: emit failure
receipts; workspace left as-modified for review.
Safety (mirrors ADR-153 conventions):
- --confirm REQUIRED (dry-run otherwise)
- --max-budget-usd hard cap (default $5, divided across attempts)
- --allowedTools restricts spawned claude to Read/Edit/Bash
- --permission-mode acceptEdits (auto-accept within the allowed set)
- 15 min hard timeout
- Pre-flight catches --test-command typos before any spend
Conformant mode (--no-test-oracle, agent writes own repro via MCTS)
is scoped for a follow-up ADR — current --no-test-oracle returns
config error with a clear hint.
Smoke verification (docs/benchmarks/tdd-repair/SMOKE-2026-06-22.md):
Built minimal failing-test fixture: add(a,b) returns a-b instead of
a+b. Pre-repair: 2/2 tests fail. After `tdd-repair --confirm`:
source patched to a+b, 2/2 tests pass. Verified by re-running.
Version bump 3.13.3 → 3.14.0 (MINOR per semver — backward-compatible
new MCP tool + new skill). Published with all three dist-tags (latest,
alpha, v3alpha) for @claude-flow/cli, claude-flow, ruflo.
Co-Authored-By: RuFlo <ruv@ruv.net>
router-compat CI step pipes the bench's --format json output to
JSON.parse, but the script always emitted a markdown header
`# bench-recordpair-overhead` + iterations line BEFORE the JSON body.
Result:
SyntaxError: Unexpected token '#', "# bench-re"... is not valid JSON
Same fix-class as iter 87 for bench-similarity. Guard the header
output behind `ARGS.format !== 'json'` so --format json emits pure JSON.
Local: pipes cleanly into JSON.parse — OK.
Co-Authored-By: RuFlo <ruv@ruv.net>
Two CI cold-cache problems hit the 180s ceiling — bump to 300s.
(1) Windows hook execution smoke / macos-latest
Observed running EXACTLY 180s before exit code null. macos runner's
cold start of `ruflo init` triggers: ONNX model download, agentic-flow
workspace init, MCP server spawn. CI's job timeout-minutes is 10, so
300s leaves room for assertion phase. Applied to both
smoke-windows-hook-execution.mjs and smoke-windows-init-hooks.mjs.
(2) test-mcp-tools chain-tool budget 90s → 180s
metaharness_audit_list still timed out at 90s. Locally audit-list
runs in ~4s; in CI, `npx @claude-flow/cli@latest memory list` pays
the npx tarball fetch (warm) + full CLI startup (loads agentic-flow
and ONNX). 180s gives 30x headroom over local cost.
Co-Authored-By: RuFlo <ruv@ruv.net>
In CI cold-cache, after oia_audit warms up the npx cache,
metaharness_audit_list STILL timed out at 60s. The audit_list handler
invokes `npx claude-flow memory list --namespace metaharness-audit`
which has its own cold-cache cost on first invocation (memory backend
init + ONNX embedder load if needed).
Add audit_list to the chain-tool bracket alongside drift_from_history
and oia_audit so it gets the 90s budget.
Co-Authored-By: RuFlo <ruv@ruv.net>
iter 128 refactored test-mcp-tools.mjs from:
const timeoutMs = tool.name === 'metaharness_drift_from_history'
? 90_000 : 60_000;
to:
const isChainTool = tool.name === 'metaharness_drift_from_history'
|| tool.name === 'metaharness_oia_audit';
const timeoutMs = isChainTool ? 90_000 : 60_000;
The smoke step 17z17 ("drift_from_history MCP tool + CLAUDE.md
surfacing") still grep'd for the literal ternary form, so it failed
with "no-extended-timeout" after the refactor. Extended the OR-set
to include the isChainTool form.
Net: 528/528 plugin smoke steps now pass in no-metaharness-smoke CI.
Co-Authored-By: RuFlo <ruv@ruv.net>