chore(release): metaharness 0.4.17 + 12 package patch releases by ruvnet · Pull Request #356 · ruvnet/metaharness · GitHub
Skip to content

chore(release): metaharness 0.4.17 + 12 package patch releases - #356

Merged
ruvnet merged 1 commit into
mainfrom
release/metaharness-0.4.17
Sep 26, 2026
Merged

ruvnet merged 1 commit into
mainfrom
release/metaharness-0.4.17

Conversation

@ruvnet

@ruvnet ruvnet commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Patch bumps for every published package with changes since its last npm release: metaharness 0.4.17, @metaharness/darwin 0.10.3, weight-eft 0.1.2, flywheel 0.1.12, and host-{claude-code,codex,pi-dev,copilot,opencode} 0.1.3, host-{hermes,openclaw,rvm,github-actions} 0.1.4.

Verified on this branch: build, full test suite (2,951 passing), lint, path-guard, smoke and runner-coverage.

🤖 Generated with claude-flow

Ships the merged dream-cycle fixes: writeAtomic path traversal and host
adapter injection (#300), .env guard (#327), MCP detection (#298),
grade masking (#337), toolSafety (#304), reward-hack tool content (#293),
reviewer isolation (#352) and the flywheel/darwin correctness fixes.

Co-Authored-By: claude-flow <ruv@ruv.net>
@ruvnet
ruvnet merged commit 7bffe2f into main Sep 26, 2026
15 checks passed
@ruvnet
ruvnet deleted the release/metaharness-0.4.17 branch September 26, 2026 15:47
enuno pushed a commit to enuno/agent-harness-generator that referenced this pull request Oct 15, 2026
…lm's gate (ADR-271) (ruvnet#221)

Implements the harness side of ADR-271: `@metaharness/avo` now serializes an AVO run's
aggregate outcome into the five Ed25519 SignedReceipts that meta-llm's POST /v1/flywheel/gate
(src/evolve/gate.ts) verifies, so an AVO benchmark result can earn a governed promotion verdict
WITHOUT porting AVO's GovernedVariationOperator runtime into the gateway (the non-goal).

- src/flywheelGate.ts: receiptsToGateInput(summary, signer) builds the 5 scoped receipts +
  manifests; submitToFlywheelGate() POSTs to the gate; gateTrustedKey(signer) yields the SPKI-DER
  key to register in the gateway allowlist. `canon` + `meetsPromotionRule` are byte-exact mirrors
  of the gateway so signatures verify and the replay decision reproduces.
- Corrected for meta-llm ruvnet#118: the gate anchors trust in FLYWHEEL_TRUSTED_PUBLIC_KEYS_JSON, not the
  embedded key — the contract requires registering gateTrustedKey and signing with a stable run key.
- __tests__/flywheelGate.test.ts: 10 tests (receipt validity, scope, replay reproduction, allowlist
  key). The gateway-side proof (real evaluateGate accepts the shape) ships in meta-llm PR ruvnet#356.

ADR-271 updated to Implemented (harness-side); gateway src/ unchanged.


Claude-Session: https://claude.ai/code/session_01BENsRDh3LVeZWMMeY1JncW
enuno pushed a commit to enuno/agent-harness-generator that referenced this pull request Oct 15, 2026
* feat: add governed field memory package

* feat(generator): add opt in governed field memory scaffolding (#203)

* feat(generator): scaffold governed field memory

* feat: @metaharness/avo — governed autonomous variation runtime (ADR-251) + live provider validation (#213)

* feat: add governed autonomous variation runtime

* test(avo): live governed-loop validation on OpenRouter + Cloud Run; ADR-252 LatentMesh

- openrouter-live.test.ts: skipIf-gated e2e driving GovernedVariationOperator
  with a real model (OpenRouter qwen/qwen3-8b via GCP-secret key, and the
  Cognitum meta-llm Cloud Run endpoint cognitum-low) — full
  inspect->edit->execute->evaluate->commit repair, every receipt Ed25519-signed
  and verified, auditable usage evidence persisted to bench/results/
- ADR-251: record live validation + user-ordered publication; 100-task
  preregistered gate remains open
- ADR-252: LatentMesh causally-verified latent-state communication (Proposed)

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* fix(healthcheck): horizon + avo publish on their own semver — exempt from umbrella version lockstep

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* fix(avo): dangling symlinks bypass the traversal guard; gate win32-incidental assertion

existsSync follows symlinks, so a symlink whose target is missing skipped the
symbolic-link policy check and surfaced ENOENT instead. lstat directly.
darwin avo-variation: the parent npm-test trace fails on Windows via the .cmd
shim; the seam contract assertions stay unconditional.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* test(horizon): 30s budget for the process-group-timeout test — Windows runners exceed vitest's 5s default

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* fix(avo)!: isolate agent context — untrusted agent could mutate live state and buy promotion (#214)

The VariationContext handed to agent.chooseAction carried the LIVE authoritative
state object and the live archive candidate (the promotion baseline). Readonly<>
is compile-time only, so a malicious agent could push a forged perfect evaluation
into state.evaluations, gut candidate.evaluation, inflate its budget, and be
committed with signed receipts. The context is now structuredClone'd before
crossing the trust boundary.

Adversarial acceptance test proves both directions: on the vulnerable code the
forged commit promotes (test fails); with the fix the promotion gate refuses it
(exit 126), the seed stays the winner, and receipts + checkpoint still verify.

@metaharness/avo 0.1.1.


Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* feat: add ChatGPT ARC AGI 3 metaharness (#218)

* feat: add ChatGPT ARC AGI 3 metaharness

* fix: update vulnerable MCP transitive dependencies

* fix: make ARC evidence tests portable on Windows

* fix(arc-agi-3): sort availableActions before hashing (order-independent observationHash)

Review finding M2: observationHash hashed availableActions in array order, so a
benign reorder from the environment adapter would fault the run
(UNLEDGERED_ENVIRONMENT_CHANGE / STALE_OBSERVATION). Sort the validated, unique
action names at the single canonicalization point. All 73 arc-agi-3 + 56
arc-agi-3-chatgpt tests pass (incl. checkpoint-trust / receipt-validation).

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): ADR-251 preregistered 100-task SWE-bench gate — executed, ship=false on cost (#217)

* bench(avo): preregister ADR-251 100-task unseen SWE-bench gate run

Task-set hash committed BEFORE any solving: sha256:1da0fdf1...c2a7ab.
100 seeded-random (seed 251) from the 407 Verified-500 instances never used
in any optimization/selection/training artifact. Fixed model deepseek/deepseek-chat,
3 arms, $100 budget ceiling, official docker evaluator, evaluateShipGate verdict
to be recorded pass OR null.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): retry OpenRouter on transient fetch/5xx/429 in solve-avo

14 darwin-fixed instances hit un-retried 'fetch failed' → empty predictions,
which would unfairly depress the baseline and inflate AVO relative lift. The
errored-instance cleanup pass re-solves them with backoff retry.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): three-arm SWE_BENCH_RESULTS assembler (dedup + resolved backfill + identical-task-set)

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): fixed-Darwin baseline reads candidate files before its one-shot patch

Blind generation (filenames only) hallucinated hunk context → 68/85 patches
failed git apply → false 1/100 resolve. A broken baseline would fake a huge AVO
lift. Fixed Darwin localizes THEN reads file content THEN emits one patch; this
strengthens the baseline (harder gate — honest direction). Blind run archived as
arm-darwin-fixed.BLIND-INVALID.jsonl.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): darwin-fixed baseline = one-shot full-file rewrite + git-diff extraction, density-ranked localization

Model-authored diffs hallucinate @@ line numbers → git apply rejects. Switch to the
SAME mechanism the AVO arms use: model emits full corrected file, harness writes it and
extracts via git diff (always applyable). Localization ranks candidates by keyword-match
density, preferring rare CamelCase identifiers, skipping __init__/setup/pyinstaller noise.
Difference from AVO is now purely one-call vs governed multi-action.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo)!: search/replace edits — full-file rewrite truncated large files in ALL arms

Root cause: model asked for FULL file content hits the output-token limit and returns
a truncated file → git diff shows the remainder DELETED (+2/-4137). ~half of every
arm's patches were truncations, so the run measured file-reproduction, not bug-fixing.
Fix: model emits small SEARCH/REPLACE blocks (aider format); harness applies them
against the real file (exact then whitespace-fuzzy). darwin-fixed applies directly;
AVO reads the current branch file, applies, hands the adapter correct full content —
no reproduction, no truncation. Smoke: AVO +11/-4 clean targeted fix (was +2/-4137).
ALL prior arm results invalidated; re-running from scratch.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): ADR-251 100-task preregistered SWE-bench gate — EXECUTED, ship=false on cost

Result (official swebench-3.0.17 docker, SWE-bench_Verified, unseen preregistered
task-set sha256:1da0fdf1...c2a7ab, model deepseek/deepseek-chat):
  darwin-fixed            5/100
  avo-no-supervisor      14/100  (+180% rel lift)
  avo-supervisor-memory  13/100  (+160% rel lift)

Ship gate: resolution +160% PASS, zero-violation PASS (0/300), replay 100% PASS,
COST +97.7% FAIL (<50% required) -> ship=false. AVO nearly triples one-shot
resolution with perfect governance but is not cost-competitive per accepted fix
under the strict preregistered bound. AVO-class claim blocked on COST, not efficacy.

Mechanism corrections applied identically across arms during the run: full-file
edit (truncated large files) -> search/replace; model-diff baseline (git apply
failures) -> git-diff extraction. Invalid intermediate runs archived.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* feat(avo): opt-in stopOnVerifiedWinner early-stop — cut cost once a fix is verified

The governed loop ran to the action budget on every instance even after a
committed candidate passed every promotion gate. Since bestVerified is captured
and cannot change, the extra actions were pure cost. New opt-in
stopOnVerifiedWinner (default false — package semantics unchanged) breaks the
loop at the first gate-passing commit. Benchmark solver opts in. Test proves it
halts at action 6 of a 12-action budget with the same winner. avo 0.1.2.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* bench(avo): auto-cadence (test-after-edit, commit-on-green) + finding: cost floor is intrinsic

Added forced evaluate-after-edit and commit-on-green (no LLM call) so an instance
stops the moment its in-loop tests pass. Empirical finding from a 2-instance smoke:
the in-loop conformant test rarely passes green even for patches the OFFICIAL eval
later resolves, and winning edits are scattered late (e.g. action 18-20). So
early-stop/cadence rarely fires and cannot meaningfully cut cost, and lowering the
action budget would forfeit the resolution gain. AVO's +160% resolution and +97.7%
cost are two sides of the same exploration — not cheaply separable with this oracle.
The ship=false-on-cost verdict stands and is now understood mechanistically.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_012qBqabgnYuymwgX1f9HC3G

* docs(adr-251): record cost-optimization finding — cost floor is intrinsic to AVO exploration

* bench(avo): mark cost-optimization phase complete (negative result recorded)

* docs(adr-251): cost-optimized re-run — optimizations no-ops (0 early-stops), cost limitation FINAL

Empirical: cost-optimized config re-run on the same preregistered 100 shows 0
early-stops and per-instance cost $0.011 = identical to v1 $0.0119. Leak-free
in-loop oracle never signals green, so optimizations never fire. v1 gate (13/100,
+97.7%, ship=false) IS the cost-optimized result. Cost limitation fundamental to
leak-free autonomous repair; ship=false-on-cost final.

* bench(avo): cost-optimized re-run artifacts + final state (loop complete)

* fix(bench): fully escape regex metachars in conformantEval glob→regex (CodeQL js/incomplete-sanitization)

The extension alternation escaped only '.', not backslash/other metachars — the
sole new CodeQL alert on this PR. Escape all regex metacharacters via a
replacement function (also avoids $-sequence misinterpretation).

* feat(avo): flywheel-gate receipt contract — submit AVO runs to meta-llm's gate (ADR-271) (#221)

Implements the harness side of ADR-271: `@metaharness/avo` now serializes an AVO run's
aggregate outcome into the five Ed25519 SignedReceipts that meta-llm's POST /v1/flywheel/gate
(src/evolve/gate.ts) verifies, so an AVO benchmark result can earn a governed promotion verdict
WITHOUT porting AVO's GovernedVariationOperator runtime into the gateway (the non-goal).

- src/flywheelGate.ts: receiptsToGateInput(summary, signer) builds the 5 scoped receipts +
  manifests; submitToFlywheelGate() POSTs to the gate; gateTrustedKey(signer) yields the SPKI-DER
  key to register in the gateway allowlist. `canon` + `meetsPromotionRule` are byte-exact mirrors
  of the gateway so signatures verify and the replay decision reproduces.
- Corrected for meta-llm #118: the gate anchors trust in FLYWHEEL_TRUSTED_PUBLIC_KEYS_JSON, not the
  embedded key — the contract requires registering gateTrustedKey and signing with a stable run key.
- __tests__/flywheelGate.test.ts: 10 tests (receipt validity, scope, replay reproduction, allowlist
  key). The gateway-side proof (real evaluateGate accepts the shape) ships in meta-llm PR #356.

ADR-271 updated to Implemented (harness-side); gateway src/ unchanged.


Claude-Session: https://claude.ai/code/session_01BENsRDh3LVeZWMMeY1JncW

* chore(avo): v0.1.3 — publish flywheel-gate receipt contract (ADR-271)

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01BENsRDh3LVeZWMMeY1JncW

* noop

* chore: remove accidental noop file

* noop

* chore: remove accidental noop file

* fix(proxy): replace stale daemon transactionally

* feat(darwin-mode): add numeric genome kind (ADR-272) (#260)

* feat(darwin-mode): add numeric genome kind (ADR-272)

A second, parallel evolution domain alongside the seven-surface prompt
genome (ADR-071): a bounded vector of named numeric parameters (e.g. ML
training hyperparameters), mutated by deterministic Gaussian
perturbation/crossover instead of code generation, and scored by a
caller-supplied external evaluator (subprocess, genome in on stdin,
NumericScoreCard JSON out on stdout) instead of the built-in SWE-bench
sandbox.

New modules only (numeric-types/-mutator/-archive/-evaluator/-evolve.ts
+ `evolve-numeric` CLI verb); zero changes to evolve.ts/mutator.ts/
types.ts/archive.ts/scorer.ts/sandbox.ts or the existing prompt-kind
tests (586 passed unchanged). +17 new tests, plus an end-to-end CLI
convergence proof against a synthetic optimum through the real built
dist/cli.js binary.

Motivated by ruvnet/wifi-densepose wanting to evolve
ruview-forecast-train's hyperparameters against a WQL metric — no
existing extension point fit (CodeGenerator still regenerates one of
seven fixed files; benchSuite still runs coding tasks), and widening
the ADR-071 safety allowlist to a non-code domain was rejected as
blurring a boundary that allowlist exists to hold.

* fix(darwin-mode): ShellEvaluator inherits full parent env, not a hand-picked scrub

* release: @metaharness/darwin 0.10.0 — numeric genome kind (ADR-272)

Ships #260: a second, parallel genome representation for evolving bounded
numeric parameter vectors (e.g. ML hyperparameters) against a caller-supplied
external evaluator. The seven-surface prompt kind is untouched.

Also corrects three comments that drifted from the code they describe:
- ShellEvaluatorOptions.env still claimed a scrubbed PATH/HOME/SystemRoot base
  after 34c9b8ff switched to inheriting the full parent env;
- mutateGenome's forced-mutation comment said "most-perturbed parameter" where
  the code picks one by hash;
- a ShellEvaluator test title said "takes the last {" where the parser
  deliberately takes the first.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(host-adapters): fix host-rvm install-rvm.sh shell+comment injection RCE (evaluated) (#224)

* dream(host-adapters): fix host-rvm install-rvm.sh shell injection (RCE)

installScript() interpolated spec.name unescaped inside two
double-quoted bash strings (--partition "..." and the following echo
line). Double-quoting alone does not stop $(...)/backtick command
substitution, so a harness name reaching this adapter directly could
run arbitrary commands the moment the generated install-rvm.sh runs.
Verified with a real bash -c execution repro (marker file created
pre-fix, not created post-fix).

Adds shellDq() (escapes \, ", $, backtick) and applies it at both
sites. Byte-identical output for any name without those characters.
39/39 host-rvm tests green (37 pre-existing + 2 new), 0 regressions;
dependent packages/bench 5/5; tsc clean; full monorepo build clean.

Pending: independent adversarial critique still running.

* dream(host-adapters): close comment-header newline injection (critic round 1)

Independent adversarial critic found installScript()'s and
partitionToml()'s '#'-comment header lines still interpolated
spec.name raw. A comment has no quoting to escape into: a literal
newline alone breaks out into a live bash statement (installScript)
or a bogus new TOML section (partitionToml) -- no $()/backtick
needed, so the prior shellDq()-only fix did not close this sibling.

Verified with a real bash -c execution repro (marker file created by
the injected command pre-fix, not created post-fix) and a TOML-section
injection repro for partitionToml. Adds commentSafe() (collapses
CR/LF runs to a space) and applies it at both comment sites. 41/41
host-rvm tests green, tsc clean, full monorepo build clean.

* dream(host-adapters): #223 host-rvm shell+comment injection RCE, ledger backfill

Research gist, adversarial-critique record, and Dream Cycle ledger for
2026-08-24. Backfills LEDGER.md rows for 2026-08-15 through 08-19 (5
prior nights ran and produced real PRs but their ledger rows never
reached main, since none of those PRs are merged yet) and notes the
2026-08-20 through 08-23 gap (a separate workstream, not a Dream Cycle
failure) with direct evidence (git ls-remote, PR/issue listing).

---------

Co-authored-by: Claude <noreply@anthropic.com>

* release: @metaharness/host-rvm 0.1.3 — shell+comment injection fix (#224)

Ships the #224 fix: shellDq()/commentSafe() applied at all 4 sites in
installScript()/partitionToml() where spec.name was interpolated raw into
a bash double-quoted string or a # comment header.

Independently verified with real bash execution: 4 payload shapes
($(...), backtick, quote-break, LF-comment) created a marker file against
the pre-fix code and are inert post-fix; 2 more corrupted TOML structure
pre-fix and no longer do.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* fix(darwin-mode): ShellEvaluator EPIPE crashed the run instead of demoting

The genome is written to child.stdin after spawn, so an evaluator that exits
without reading stdin (bad argv, immediate process.exit, startup crash) leaves
the pipe closed and the write raises EPIPE. With no 'error' listener on the
stdin socket that is an unhandled error event, killing the whole evolveNumeric
run rather than demoting the one candidate.

Platform-dependent race — Linux usually completes the write first, macOS often
does not — so it passed on main and failed on the next PR's macOS job. Caught
by CI on #246, not by review of #260.

close/error already resolve with a demoting errorCard carrying the child's real
exit code, so the EPIPE is swallowed. Regression test reproduces it
deterministically with a large genome (unhandled EPIPE without the fix).

Ships as @metaharness/darwin 0.10.1. 648 passed / 14 skipped.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* fix(release): resync package-lock + widen darwin range broken by the 0.10 bump

npm ci has been failing on main since the darwin 0.10.0 release:

  npm error `npm ci` can only install packages when your package.json and
  package-lock.json are in sync.
  npm error Missing: @metaharness/darwin@0.9.3 from lock file

Two things were missed when bumping darwin 0.9.3 -> 0.10.0 -> 0.10.1 and
host-rvm 0.1.2 -> 0.1.3:

1. The root package-lock.json still carried the old workspace versions, so
   `npm ci` refused. This is what took the Meta-Proxy native macOS/Windows
   lifecycle jobs red — they run `npm ci`, not `npm install`.
2. create-agent-harness pinned "@metaharness/darwin": "^0.9.1", which does not
   match 0.10.x (a minor bump is breaking in 0.x), so the workspace link broke.
   The numeric genome kind is purely additive over 0.9.3, so the range is
   widened to ^0.10.0 rather than darwin being held back; metaharness bumps
   0.4.7 -> 0.4.8 for the changed dependency range.

Verified by running a real `npm ci` against both lockfiles in a clean tree:
old -> the exact EUSAGE error above; new -> installs clean (222 entries).

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* fix(release): metaharness 0.4.9, not 0.4.8 — 0.4.8 is already published from an unmerged branch

Correcting my own bump in fe3d5b43. I moved create-agent-harness 0.4.7 -> 0.4.8
for the widened darwin range, without checking the registry: metaharness@0.4.8
was already published on 2026-08-24 and is a DIFFERENT artifact.

The registry is ahead of main for this package. Published 0.4.8 depends on
@metaharness/avo ^0.1.4; main has no avo dependency, because that integration
lives in PR #226, which is still open. So:

- main cannot reproduce metaharness@0.4.8;
- publishing from main would strip the avo integration off `latest` — a real
  regression for anyone installing metaharness.

Version moves to 0.4.9 so it no longer collides. DO NOT publish metaharness
from main until #226 lands and main actually contains the avo integration.
Tracked in an issue.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(host-adapters): fix host-openclaw YAML/shell injection via spec.name (evaluated) (#246)

* dream(host-adapters): #245 fix host-openclaw YAML/shell injection via spec.name (evaluated)

4th confirmed sibling of #188 (hermes)/#212 (github-actions)/#224
(host-rvm): spec.name reached skillMarkdown()'s YAML frontmatter and
installScript()'s shell double-quoted strings/comment line unescaped.
Fixed with the same shellDq/commentSafe/YAML-bare-vs-quoted conventions
already established in the prior two fixes. 6 new tests, all verified to
fail against pre-patch code; 0 regressions (host-openclaw 19->25/25,
bench 148/148). Independently critiqued (ACCEPT-WITH-CAVEATS) by a
separate adversarial-review subagent.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pnj4gAQQuaZCszdWuj2k23

* dream(host-adapters): #245 ledger rows for 2026-08-15..08-29

Backfills the 0/10-merged fact onto main (the #240 branch that first
backfilled per-night detail is itself unmerged) and adds tonight's own
row with the real PR number (#246).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pnj4gAQQuaZCszdWuj2k23

* fix(host-openclaw): close path traversal left open by the shell/YAML escaping

shellDq() stops command execution but not path traversal: a spec.name of
'../../../../tmp/evil' is an ordinary double-quoted bash string, so the
generated mkdir -p / cp lines wrote outside the skills directory. Verified
by real execution — a marker file outside $HOME/.openclaw was created both
before AND after the #246 escaping fix.

Adds pathSegmentSafe(), applied BEFORE shellDq() (applying it after would
rewrite the backslashes shellDq just added). Byte-identical for any name
without a path separator. 3 regression tests; 28/28 host-openclaw, 148/148
dependent bench.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* release: @metaharness/host-openclaw 0.1.3 — YAML/shell injection + path traversal (#246)

Ships #246 plus the path-traversal sibling closed during review:
- yamlValueSafe/yamlDq  frontmatter value position (bare-when-safe, quoted+escaped otherwise)
- shellDq               the two double-quoted bash sites
- commentSafe           the # comment header
- pathSegmentSafe       mkdir/cp path segment (traversal), applied BEFORE shellDq

Lockfile resynced in the same commit this time.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* feat(core): integrate @metaharness/avo as a metaharness dependency + `metaharness avo` subcommand (#226)

Wires the governed autonomous variation runtime (ADR-251) and its flywheel-gate receipt contract
(ADR-271) into the core CLI, matching the existing subcommand-delegation pattern (flywheel/redblue/
turn-credit → `<pkg>/cli` dispatch).

- @metaharness/avo@0.1.4: adds `src/cli.ts` (dispatch(cmd,args)->{lines,code}) + a `./cli` export.
  Subcommands: `trusted-key` (print the SPKI-DER key to register in FLYWHEEL_TRUSTED_PUBLIC_KEYS_JSON),
  `gate-build` (build+sign the 5 gate receipts from an AvoRunSummary, offline), `gate-submit`
  (POST them to /v1/flywheel/gate for a governed verdict). Uses avo's real flywheelGate API.
- metaharness@0.4.8: adds `@metaharness/avo@^0.1.4` to dependencies + a `case 'avo'` router entry +
  a help line. The GovernedVariationOperator stays a library import — the gateway is never a runtime dep.

Verified end-to-end through the built core bin: `metaharness avo gate-build <summary>` produces the
5 signed receipts + a promote decision; avo tests 10/10; core tsc clean. Both published to npm.


Claude-Session: https://claude.ai/code/session_01BENsRDh3LVeZWMMeY1JncW

Co-authored-by: ruv <ruvnet@gmail.com>

* dream(host-adapters): #211 close github-actions shell/YAML injection sibling of #188 (#212)

cfg.name/spec.name land unescaped in the generated composite Action's
run: line (bash-injection-shaped) and in #-comment/step-name lines
(YAML top-level key injection via newline), identically across all 3
byte-parity codegen paths. Same root cause as the 2026-08-14 hermes
fix (#188), recurring in the github-actions host. Closed with
shellDq()/yamlCommentSafe() helpers mirroring the existing yamlKey()
playbook, plus switching the run: line to a `|` block literal so
YAML-layer truncation can't bypass the bash-level escaping.

3 independent adversarial critic rounds; the first two each found a
real gap the prior round missed (a sibling comment site, a YAML-layer
truncation vector bash-escaping alone didn't close, an inaccurate
reachability comment) before the third returned ACCEPT.


Claude-Session: https://claude.ai/code/session_01EByF7M7c7gUrJYu8FUaWTk

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* release: host-github-actions 0.1.3 + metaharness 0.4.10 — GHA injection fix (#212)

Ships #212's shellDq()/yamlCommentSafe() + the move from a plain `run: echo`
scalar to a `|` block literal, across both published copies.

metaharness needs its own bump because 0.4.9 was published BEFORE #212 merged:
its dist/host-config.js has no block literal, so the fix was absent from the
shipped CLI. Verified by unpacking the published 0.4.9 tarball.

Note: the third byte-parity copy, apps/web-ui/src/generator/scaffold.ts, is
private:true and unpublished — but it is also outside CI (root workspaces is
["packages/*"] and ci.yml never references web-ui), so its 71 tests guarding
this fix run on no runner. See #195/#194.

Lockfile resynced in the same commit.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* ci(published-smoke): gate on tarball fetchability, not registry metadata (#263)

published-smoke resolves @latest over the network on every push to main, so a
publish concurrent with a push made it fail on some matrix legs and not others,
with a red that says nothing about the artifact.

Observed twice today, both reproducible only by timestamp correlation:
- run 33556294700: 0.4.9 published 20:38:02.122Z, the two failing steps ran at
  20:38:12Z and 20:38:17Z; 4 of 6 legs passed; a re-run with NO change to the
  commit or the artifact went 6/6 green.
- run 33560715843: run created 21:22:32Z, 0.4.10 published 21:23:37Z — the
  publish landed 65s INTO the run, so @latest changed underneath it; 1 of 6
  legs failed.

Root cause: "npm view" reads registry METADATA, which is updated before the
tarball is fetchable from every CDN edge. The existing resolve step therefore
proves a version exists, not that it can be installed.

Adds a bounded gate (10 x 15s) polling "npm pack" -- the tarball itself --
before any npx step, in each of the three jobs that resolve @latest.
Propagation resolves in seconds, so a genuinely broken publish still fails:
after 150s the gate exits 1 saying to treat it as a real breakage, not a race.

Does not weaken the check. The failure mode it was written for (iter 124's
broken bin name) still fails exactly as before -- that tarball was fetchable
and broken, which is different from not being fetchable yet.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(security-adversarial): disclose devDependency exclusion in harness audit/sbom (evaluated) (#243)

* dream(security-adversarial): #242 disclose devDependency exclusion in harness audit/sbom (evaluated)

harness audit (npm audit --omit=dev) and harness sbom (SPDX, filters
pkg.dev===true) both default to excluding devDependencies -- a defensible
two-tier posture, but neither said so. A reviewer trusting the default
output saw a clean bill of health even when this repo's own dev tree
carries a critical + 4 high advisories (Vitest UI arbitrary file
read/execute, js-yaml/nanoid/postcss/vite). devDependencies execute
during npm ci/test/build, a real CI/build-time attack surface (2025-2026
Shai-Hulud + node-ipc incidents).

- audit-cmd.ts: best-effort second npm audit (no --omit=dev) discloses
  the suppressed count without changing default PASS/FAIL gating; also
  fixes a double-counting bug in `total` (npm's own `total` key was being
  summed a second time via Object.values()).
- sbom-cmd.ts: counts excluded dev-scope packages, adds an SPDX
  creationInfo.comment + matching CLI line.
- New tests (sbom-cmd.test.ts, audit-cmd.test.ts) verified red against
  pre-patch code. Full create-agent-harness suite: 468/468 passed (2
  skipped), 0 regressions. tsc --noEmit clean.

Never merged automatically -- draft PR for human review.

Co-Authored-By: claude-flow <ruv@ruv.net>

* dream(security-adversarial): #242 ledger row for 2026-08-28

Co-Authored-By: claude-flow <ruv@ruv.net>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* release: metaharness 0.4.11 — audit advisory double-count fix (#243)

Ships #243. The headline is a shipped correctness bug, not the disclosure:
"harness audit" reported exactly DOUBLE every advisory count, because npm's
metadata.vulnerabilities carries a "total" key alongside the per-severity
keys and the old code summed Object.values().

Verified against the pre-fix baseline on main, running the real command:

  PRE-FIX   total advisories: 16
            per severity: info=0, low=0, moderate=3, high=4, critical=1
  POST-FIX  total advisories: 8

The pre-fix output contradicted itself -- header 16, breakdown summing to 8,
one line apart.

Also ships the devDependency disclosure. On this repo the default run now
prints "devDependencies not counted: 8 advisories (5 at high+)" where it
previously printed a bare "PASS: 0 advisories at high+", hiding them.
Default pass/fail semantics unchanged; the second audit call is best-effort
and can never fail the command.

Lockfile resynced in the same commit.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* ci: fail when a test or crate is reached by no runner (#194) (#195)

npm test is `npm run -ws --if-present test` and cargo test is `--workspace`, so
two things are currently indistinguishable from a pass: a workspace with no test
script, and a crate outside the members list. Both runners then report green and
complete. draco.yml already carries a note from the last time this bit --
"An explicit list silently drifts: arm tests existed but CI never ran them" --
and this generalises that fix instead of repeating it per-workflow.

scripts/check-runner-coverage.mjs walks every test file, package.json and
Cargo.toml and asserts each is either reached by a runner or recorded as a
deliberate exclusion with a reason. Zero dependencies, static, <1s, no network.

It counts three invocation forms as "reached", all of which are in use here:
  - a workspace matched by the root `workspaces` globs that has a test script
  - a file named explicitly in a workflow, as `vitest run <path>` OR `node <path>`
  - a workflow job with `working-directory: <dir>` plus its own `npm test`

The second and third were added after the first draft produced FALSE POSITIVES
on this repo: ci.yml's "SOTA integrity-attestation gate" runs its suites under
plain `node`, and pages.yml tests apps/web-ui via working-directory. Those 11
findings were wrong, and a checker that cries wolf gets deleted. The
working-directory match is deliberately coarse (workflow-level, not job-level):
a missed gap costs less than a false alarm that blocks CI on correct code.

The allowlist is a RATCHET, not a suppression list -- seeded with what is
already unreached today so this passes on main unchanged, and anything NEW
fails. Entries require a non-empty reason; an allowlist without reasons is a
mute button and the next reader cannot tell a decision from an oversight. A
stale entry also fails, so it cannot rot into blanket permission. Deleting
entries is the point.

Seeded state (measured on 1f3b870, all cross-checked against the workflows):
  56 test files -- 45 root __tests__/ (npm run -ws excludes the root package),
                    9 services/apicompletions (outside packages/*),
                    2 kimi-k3-harness (outside packages/*, has its own
                      "test": "vitest run" that nothing invokes)
   4 crates     -- oo-agents 20, horizon 14, k3rs 9, k3-kernel-bench 1
                    (#[test] fns; each declares its own [workspace], so cargo is
                     behaving correctly -- nothing else runs them either)

I am not asserting these should run: kimi-k3-harness reads like a self-contained
experiment and nested [workspace] crates are a normal way to isolate a
dependency graph. The claim is only that nothing currently distinguishes
"deliberately not run" from "accidentally not run".

Proved able to fail, four ways, each verified to die for the right reason:
  new unreached test file      -> red, names the file and why
  allowlist entry with no reason -> red
  stale allowlist entry        -> red
  drop the `node <path>` form  -> the 2 SOTA suites reappear as findings
                                  (no syntax error; the fix is load-bearing)

actionlint clean. The added CI step uses no ${{ }} expressions.

* fix(proxy): make the pin-drift watcher self-resolving and key-aware (#174) (#178)

META_PROXY_VERSION is already current — #175 moved it 0.7.2 -> 0.7.4, and
0.7.4 is meta-proxy-dist's latest release. The pinned Ed25519 key still
verifies that release's SHA256SUMS, so the pin itself needs no change.

What is still broken is the watcher that filed #174. Its logic lived as
inline shell in the cron workflow, where nothing exercised it, and four of
its untested branches were wrong:

  - The issue title embedded both version numbers and doubled as the dedupe
    key, so any version movement broke the match and opened a second issue.
  - Nothing ever closed a resolved drift. #174 has asserted "pinned at
    0.7.2" for days after the pin reached 0.7.4.
  - Every mismatch was reported as "behind". A pin running ahead of the
    latest release is the more dangerous case — install 404s on assets that
    were never published — and it got the exact opposite advice.
  - `gh release list --limit 1` is newest-by-date, so a draft or prerelease
    would have us pinning users onto an RC.

It also never checked the signing key its own resolution text told
maintainers to confirm. A rotated key is invisible to a version comparison;
it surfaces as every `proxy install --yes` failing verification.

Move the decision into scripts/proxy-pin-drift.mjs with the `gh` and network
calls injected, so the branches are testable offline. Titles no longer carry
versions, an existing issue is retitled rather than duplicated, a resolved
drift is commented and closed, and the pinned key is verified against both
the pinned release and any release we are about to recommend.

The dedupe search still matches the old version-bearing titles, so the first
scheduled run closes #174 rather than orphaning it. Verified against live
meta-proxy-dist with gh stubbed: state=current, pinnedKey=true, closed #174.

* fix(proxy): bump META_PROXY_VERSION 0.7.4 -> 0.7.5 (#222); metaharness 0.4.12

cognitum-one/meta-proxy-dist shipped v0.7.5 on 2026-08-18; the pin stayed at
0.7.4, so "metaharness proxy install" downloaded a stale proxy and reported
success. That is exactly the drift #178's rewritten watcher is built to catch,
and running it against live data immediately reported:

  pinned=0.7.4 latest=0.7.5 state=behind pinnedKey=true -> updated #222

Safe to bump without re-pinning the key: the pinned META_PROXY_SIGNING_PUBKEY_PEM
was verified against the real SHA256SUMS of BOTH releases before changing
anything --

  pinned key verifies v0.7.4: true
  pinned key verifies v0.7.5: true

so this is a version move only, not a key rotation.

meta-proxy.test.ts asserts the pin literally. That assertion is a tripwire, not
an oversight -- it fired on this change and is updated deliberately in the same
commit, which is the whole point of having it.

474 passed / 2 skipped. Lockfile resynced; runner-coverage gate green.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* docs: ADR-251 — the MetaHarness Dream Machine (nightly cloud-scheduled evolution routine) (#179)

* docs: add ADR-251 nightly dream machine (cloud-scheduled dream cycle)

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs: ADR-251 — record created routine id trig_01T9FVWfahfGrkK9E9eCsvyw

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs(dream-cycle): prompt v2 — port Ruflo Dream Cycle v3.1 research-depth protections

Operator feedback on the first Ruflo v3 nights: research had visibly
thinned (all-None competitor rows, thin justification) because the budget
language treated research as the compressible phase. v2 flips that:

- STEP 0.6: research phase is protected; budget pressure cuts from the END
  of the pipeline (Darwin generations, corpus size, adversarial depth), and
  a shortened research pass must be disclosed, never silent
- STEP 1: sparse-ledger caution — verify dream/* branches + PRs before
  reporting a prior night as having skipped a step
- STEP 3: minimum research depth — all-None rows need a WHY, fixed lists
  are a floor not a ceiling, prefer >=1 source <12 months old, no
  same-shaped tables night after night
- STEP 7: note that a fresh corpus is graded by its own author-session,
  pointing at STEP 10's fairness check
- GLOBAL INVARIANTS: leads with trustworthy-improvement-over-activity
- ADR-251: Updated stamp + status reflects two completed runs (#181, #188)

Scheduler copy updated in the same piece of work per the mirror rule.

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs: renumber the Dream Machine ADR 251 -> 273 and conform its headings

Two defects, both caught by __tests__/adr-index.test.ts -- which never runs in
CI (root suite, allowlisted as unreached by #195/#194), so neither would have
surfaced on merge.

1. ADR NUMBER COLLISION. ADR-251 is already taken on main by
   ADR-251-governed-autonomous-variation-runtime.md (@metaharness/avo, Accepted
   and shipped). This PR added a SECOND ADR-251, and INDEX.md carried two rows
   with the same number. ADR-252 (LatentMesh) already cites "ADR-251 capability
   policy", meaning the AVO one -- so the collision made an existing
   cross-reference ambiguous. Renumbered to 273 (272 is the current high-water
   mark); the AVO reference is left pointing where it always did.

2. NON-CONFORMING HEADINGS. The ADR used numbered sections ("## 1. Context").
   235 of the repo's 236 ADRs use the unnumbered form and the test asserts it;
   this file was the sole exception. Stripped the numeric prefixes.

Also corrected the INDEX status, which claimed "routine created; first live run
pending" while LEDGER.md records 10 completed runs through 2026-08-29.

Not fixed here (pre-existing on main, unrelated to this PR): ADR-253 has no
Consequences section and fails the same test. It has no section that could be
renamed into one, so writing it is the author's call, not a mechanical fix.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

---------

Co-authored-by: ruv <ruvnet@gmail.com>

* test(proxy-pin-drift): make the PEM assertion EOL-agnostic — main is red on Windows

main has been failing on Node 20/windows and Node 22/windows since #178 merged:

  FAIL reads the pinned Ed25519 key out of the real meta-proxy.ts:
    The input did not match the regular expression /^-----BEGIN PUBLIC KEY-----\n/

meta-proxy.ts is not pinned to `eol=lf` in .gitattributes (which covers only the
draco corpus and a few golden fixtures), so a Windows checkout produces a CRLF
PEM and the LF-anchored assertion fails.

Production is NOT affected, verified rather than assumed: the PEM only ever
reaches crypto.createPublicKey(), is never string-compared or hashed, and
createPublicKey() accepts CRLF and LF alike (checked both). So the fix belongs
in the test's platform assumption, not in readPinnedPublicKey().

  simulated CRLF PEM:  OLD -> false, NEW -> true
  LF PEM:              NEW -> true (unchanged)

Root cause of it reaching main: #178 came from a fork, and fork PRs report no
checks on this repo, so its CI never ran. I merged it on local (Linux) verification
alone. The same blind spot applies to #195. Worth a follow-up on fork-PR CI.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* feat(arc): add governed AVO harness, ChatGPT adapter, and benchmarks (#220)

* feat(arc): add governed AVO harness and benchmarks

* chore(avo): 0.1.4 -> 0.1.5 — shipped code changed in this PR

packages/avo/src/operator.ts (+379/-19) and types.ts (+16) change in this PR,
but the version stayed at 0.1.4, which is already published. Merging that would
leave the repo at 0.1.4 with different content than the registry serves --
the same divergence class as #261, and exactly what the preflight gate proposed
in #262 is meant to catch.

The change is additive hardening (optional EvaluationBinding field, new failure
constants, JSON parse depth/node/byte bounds, memory retrieval cap), so a patch
bump is correct and create-agent-harness's "^0.1.4" still resolves.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* test(arc-bench): fix a racy poll that read the mid-rename .partial name

CI caught this on #220 where local runs did not: Node 20/ubuntu, Node 20/windows
and Node 22/windows failed with

  expected [ "turn_...json" ] to deeply equal [ "turn_...json.partial" ]

The product code is correct. FileBrokerModelDriver writes
`<requestId>.json.partial` and then renames it (model-driver.ts:446-448) -- a
proper atomic write. The TEST was wrong: it polled readdir() until the directory
was merely non-empty, so it could observe the temporary name mid-rename, exit
the loop, and assert against `.partial`.

Filter `.partial` out of the poll so it waits for the settled filename. Logic
difference on a mid-rename directory:

  OLD poll: exits loop, asserts against ["turn_....json.partial"]  -> fails
  NEW poll: keeps polling until the rename settles                 -> passes

Passing locally proves nothing here (it passed before too, and on 8 of 11 CI
jobs) -- the race is filesystem- and timing-dependent, which is why it showed on
ubuntu/windows and not macOS or this machine.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

---------

Co-authored-by: ruv <ruvnet@gmail.com>

* test(arc-bench): fix the SECOND racy .partial poll — my earlier fix was incomplete

main is red on Node 22/ubuntu (60491b5c):

  model-driver.test.ts:155
  expected [ "turn_....json" ] to deeply equal [ "turn_....json.partial" ]

Same race I fixed in 38e2c82c, different call site. I patched the poll at line
115 and did not check whether the pattern appeared elsewhere in the file. It
did — an identical unfiltered `readdir` poll at line 149 — so the fix was
incomplete and the flake simply moved to the other test.

Rather than patch the second copy the same way and leave a third to drift,
both call sites now share one `waitForSettledRequests()` helper that filters
`.partial`. There is now exactly one poll implementation in the file.

The remaining `readdir` (archive length) is a direct post-resolution assertion,
not a poll, and the driver only ever writes `.partial` on the request path
(model-driver.ts:446) — so it is not susceptible.

Product code remains correct throughout: write-then-rename is a proper atomic
write. 11/11 across three consecutive runs, tsc clean, coverage gate green.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(flywheel-promotion): consolidate #205/#231/#255 + close a 4th replay-trust gap (evaluated) (#258)

* dream(flywheel-promotion): #257 consolidate #205/#231/#255 + close a 4th replay-trust gap

MetaHarness Dream Cycle, 2026-09-01. Deep surface: flywheel-promotion (slot 1).

Hand-merges three semantically-compatible but git-conflicting unmerged Dream
Cycle PRs (#205, #231, #255) into one clean diff on
verifyReplayBundle/gateReExecutes in packages/flywheel/src/replay.ts, since
all three independently rewrote the same code region against different
stale bases. An independent adversarial critic then found a 4th,
undisclosed gap: BOUND_KEYS (from #255's sealedFieldsAuthentic check) did
not bind `parents`/`generation`, so two genuinely, independently signed
PROMOTED commits could be spliced into a fabricated multi-generation chain
by rewriting only those two unsigned fields. Closed in the same diff with a
regression test reproducing the exact exploit.

72/72 flywheel unit tests pass; 18/41 new-test assertions verified to fail
against unpatched main (non-vacuous); all 7 real committed ReplayBundle/
proof-bundle files in the repo re-verified unchanged PASS; full monorepo
build + 716/716 non-skipped tests across flywheel/evals-math/darwin-mode
green.

Full detail: issue #257, docs/dream-cycle/2026-09-01-gist.md,
docs/dream-cycle/2026-09-01-evidence.md, ADR-272.

Human review required. Do not self-merge. Do not autonomously promote
Flywheel state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012NE5wk64pND2VpBZmGGkQq

* dream(flywheel-promotion): record PR #258 in the ledger row

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012NE5wk64pND2VpBZmGGkQq

* chore(flywheel): 0.1.10 -> 0.1.11 — shipped code changed in this PR

packages/flywheel/src/{cli,replay,run}.ts change here, but the version stayed at
0.1.10, which is already published. Merging that would put different content
behind a version the registry already serves — the #261 divergence class, and
the second time today a dream PR has done it (see the avo 0.1.4 bump on #220).
This is exactly the case the registry preflight gate proposed in #262 would
catch automatically.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

---------

Co-authored-by: stack-check <test@test.local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* dream(process): ledger-integrity backfill + 8-PR review backlog escalation (2026-08-27) (#240)

* dream(process): backfill 8 missing ledger rows, fix STEP 25 silent-skip (#local)

The Dream Cycle ledger (docs/dream-cycle/LEDGER.md) had only 2 rows despite
8 more nightly runs (2026-08-15 through 2026-08-26) having completed their
full pipeline through a draft PR. STEP 25 ("update the ledger") silently
never landed on any of those 8 nights, even though everything upstream of
it worked. Backfilled all 8 rows from the actual GitHub PR/issue state
(hypothesis, evaluation receipt, verdict, witness prefix, prior-night
fates) and flagged the 2026-08-20 through 2026-08-23 gap, where no
dream/* branch exists at all, as unexplained rather than silently
smoothing over it.

This matters beyond bookkeeping: STEP 1's learning-signal checks (duplicate
-direction detection, the zero-merge-in-14-days bias rule, the review-
bottleneck rule) all read this table, so for two weeks they were running
against a table that looked like only the first 2 nights had ever
happened. The individual PRs partially self-corrected by reading GitHub
state directly instead of trusting the ledger, which is why output quality
held up -- but the intended durable-memory mechanism itself was broken the
whole time and nothing had a way to notice.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsupnqZFBjZrjTpv2yvVa3

* dream(process): 2026-08-27 gist + ledger row — backlog escalation, no new candidate

Issue #239. Full writeup in docs/dream-cycle/2026-08-27-gist.md. Tonight's
darwin-evolution rotation was deliberately not investigated in favor of
fixing the ledger-integrity gap (previous commit) and escalating the
8-PR / 0-merged-in-12-days review backlog as the night's real, more
actionable finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsupnqZFBjZrjTpv2yvVa3

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* dream(security-adversarial): mcp-scan missed Bash(python *) — live in vertical:ai (evaluated) (#210)

* dream(security-adversarial): #209 mcp-scan missed Bash(python *) (live) + unrestricted Bash(*) (evaluated)

harness mcp-scan's risky-bash-allow regex omitted arbitrary-code
interpreters (python/node/ruby/perl/bash/sh) - the vertical:ai
template's own settings.json.tmpl ships Bash(python *), unflagged by
any check until now. Also adds a new unrestricted-bash-allow HIGH
finding for bare Bash/Bash(*), disclosed as defense-in-depth rather
than a live generator bug after an independent critic traced the call
graph and found no shipped generator currently writes that exact
string to .claude/settings.json.

Evidence: real (non-synthetic) `metaharness --template vertical:ai`
scaffold repro plus a deterministic before/after stash repro; 15/15
mcp-scan tests, 457/457 full package suite, 0 regressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1diHYv256aiVNdEEUMfjG

* chore(metaharness): 0.4.12 -> 0.4.13 — mcp-scan.ts changed in this PR

src/mcp-scan.ts is shipped code and 0.4.12 is already published. Third dream PR
today to change published code without a bump (after avo on #220 and flywheel on
#258) — the registry preflight gate proposed in #262 would catch all three.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* ci(published-smoke): pin the gate-validated version for the whole job (#263)

My earlier fix (1ded6f21) added a tarball-fetchability gate but left a hole:
@latest is a MOVING TARGET. The gate resolves it once, then every later step
re-resolves @latest independently -- so a publish landing mid-run makes the
early steps test one version and a later step test another that has not
propagated to that runner yet.

Observed exactly that on run 33576201824 (main @ b578440b):

  run created      00:39:07Z
  0.4.13 published 00:40:51Z   <- 1m44s INTO the run
  gate             SUCCESS     (validated 0.4.12)
  --help           SUCCESS
  --version        SUCCESS
  scaffold         SUCCESS
  score            FAILURE     <- re-resolved @latest, got un-propagated 0.4.13

The artifact was never broken. Verified by clearing the npm cache and running
every assertion of that step against both versions:

  0.4.12: fit:OK mode:OK top:OK constraints:OK
  0.4.13: fit:OK mode:OK top:OK constraints:OK

(My first local reproduction appeared to show 0.4.13 failing; that was ETARGET
from a stale local npm cache, not a regression. Worth stating plainly because
it would have been easy to file as a broken publish.)

Fix: every npx step in smoke-published-cli now uses
metaharness@${{ steps.resolve.outputs.version }} -- the exact version the gate
proved fetchable -- so one job tests one consistent artifact. The resolve step
itself still reads @latest, which is the point: it decides what is under test.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* ci(published-smoke): use explicit --package for the metaharness bin (npm 12)

published-smoke failed on ALL SIX matrix legs, twice (attempt 1 and a re-run),
with:

  npx --yes metaharness@0.4.13 --help
  sh: metaharness: command not found          exit 127

This is NOT propagation and NOT a broken publish. My earlier hypothesis (the
gate validates `npm pack` while the steps need npx bin-linking) was refuted by
the re-run failing identically at a later time.

Root cause: the GitHub runners' npm has moved to a version where the bare
`npx <pkg> <args>` form no longer resolves a bin for a package with TWO bins.
metaharness ships `metaharness` and `harness`. Reproduced locally:

  npm 10.9.8:  npx metaharness@0.4.12 --help -> 0
               npx metaharness@0.4.13 --help -> 0
  npm 12.0.2:  npx metaharness@0.4.12 --help -> 127   <- 0.4.12 TOO
               npx metaharness@0.4.13 --help -> 127
               npx --package=metaharness@0.4.13 -- metaharness --help -> 0

0.4.12 fails identically, which proves this has nothing to do with anything
published today. The published tarballs are sound: both 0.4.12 and 0.4.13
contain dist/bin.js + dist/harness-bin.js with a correct shebang and bin map.

Fix: every metaharness-bin invocation now uses the explicit
`--package=metaharness@<v> -- metaharness <args>` form — the same form the
workflow already used for `harness doctor`, which was always ambiguous. The
`@metaharness/*` wrapper packages each declare exactly one bin, so their bare
invocations remain valid and are left alone.

USER-FACING IMPLICATION, filed separately: `npx metaharness ...` is the
documented entry point and it breaks the same way for anyone on npm 12.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(generator-genome): scoreTestConfidence trusted manifest, not real tests (evaluated) (#229)

* dream(generator-genome): scoreTestConfidence trusted manifest, not real tests

scoreTestConfidence credited profile.testCommands.length>0 directly, but
testCommands is inferred purely from language/manifest detection in
analyze-repo.ts (a pyproject.toml unconditionally implies 'pytest', with
no check that any test file exists). A repo with a test-capable manifest
and CI wired, but zero real test files, scored 0.8 test_confidence.

Adds RepoProfile.hasVerifiedTestFiles (real tests/__tests__/test directory
scan in inventory(), mirroring score.ts's existing dirExists-based
scoreTestCoverage) and requires it for scoreTestConfidence's base credit.
Pre-fix stash-and-rerun confirmed 4/6 new tests fail against the old
source (non-vacuous). Full package suite: 464/464 passed (2 pre-existing
skips), 0 regressions, tsc clean.

Extends 2026-08-15's #200 gist, which disclosed this exact gap as an open
next-step. Work in progress — evaluation receipt, adversarial critique,
research gist, and ledger update land in a follow-up commit on this
branch once the independent critic pass completes.

* dream(generator-genome): #228 research gist + ledger update

Research gist, witness stamp, and ledger row for tonight's
scoreTestConfidence fix. Also records the operational finding: 6
consecutive Dream Cycle PRs (2026-08-15 through 2026-08-24) remain
unmerged, including two adversarially-critiqued security/RCE fixes.

* dream(generator-genome): close critic-found gaps in the test-confidence fix

Independent adversarial critic (ACCEPT-WITH-CAVEATS) found: (1) the new
inventory() fs-scan path had zero test coverage against a real
filesystem — closed with 2 mkdtemp-based tests in analyze-repo.test.ts;
(2) a docstring overclaim that score.ts "already requires" real
directory evidence, when it only weights it as the largest of three
independent components — softened to the actual, narrower parity.

* dream(generator-genome): ledger — resolve PR #229 placeholder

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* ci(published-smoke): install once, invoke the bin file directly — drop npx (#263)

Third attempt at this workflow, and the first two were wrong. Recording both so
the next person does not repeat them:

1. 1ded6f21 — added a tarball-fetchability gate, believing CDN propagation.
   Real, but incomplete: @latest is a moving target and later steps re-resolved it.
2. e9055ce2 + a914e98d — pinned the resolved version, then switched to the
   explicit `--package ... -- metaharness` form, believing npm 12 had dropped
   bin inference for multi-bin packages. Also wrong: the failing and passing
   runners BOTH report npm 10.9.8.

Latest data: with the explicit --package form, macOS passes both legs while
ubuntu and windows fail with `sh: 1: metaharness: not found` (127) — same npm,
same command, same published artifact. Meanwhile the BARE form passed all six
legs earlier the same day. So npx bin resolution is simply not deterministic
across these runner images, and every fix that keeps depending on it is a guess
about which npx behaviour is in play.

This removes the dependency instead of adjusting it. Install the published
package once into a temp prefix, assert dist/bin.js exists, then invoke it with
`node` directly. No npx, no bin shim, no PATH or shell resolution.

That is also a STRONGER test of the thing this job exists to check. The original
failure it was written for (iter 124's 0.1.0 shipping the wrong bin name) is
caught more directly: `test -f .../dist/bin.js` fails loudly on a broken bin
map, rather than surfacing as an ambiguous "command not found" that could equally
mean npx misbehaved.

Verified locally: install + `node dist/bin.js --help` exits 0.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01G2iAKhp4FGq2Ty5CFnj8mT

* dream(darwin-evolution): ADR-249's cost seam wired into evolve() (evaluated) (#207)

* dream(darwin-evolution): #206 wire ADR-249's dangling cost seam into evolve()

EvolutionConfig gains optional costBudgetBytes; evaluateVariant now
feeds the existing variantBytes(variant.dir) parsimony signal through
scoreVariant's opt-in signals.cost seam when set, and stays
byte-identical when omitted (every current caller). Closes the gap
between ADR-249 (2026-08-10, seam shipped) and evolve()'s only call
site, which never had a way to reach it.

Deterministic before/after repro: 4 new evolve.test.ts tests fail
exactly as predicted pre-fix, package suite 632/632 passed (0
regressions) post-fix. Independent adversarial critic: ACCEPT, two
disclosed non-blocking caveats. Full receipt, competitor research, and
witness: docs/dream-cycle/2026-08-17-gist.md, issue #206.

* dream(darwin-evolution): #206 update ledger — backfill 08-15/08-16, add 08-17

Ledger on main only had 08-13/08-14 despite 4 nights of runs (08-15
generator-genome PR #200, 08-16 flywheel-promotion PR #205 both exist,
open, non-stale, with their own ledger rows sitting on unmerged
branches). Backfilled those two rows from their PR bodies (verified,
not guessed) and appended tonight's 08-17 darwin-evolution row with
the real issue #206 / PR #207 numbers.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* dream(generator-genome): scorePublishReadiness locked python/go out of 'ready' (evaluated) (#200)

* dream(generator-genome): scorePublishReadiness locked python/go out of 'ready' forever

harness genome's scorePublishReadiness credited language detection only for
typescript (+0.3) and rust (+0.15); every other language (python, go) got
+0, and analyze-repo.ts never generated a build command for either, so
their buildCommands bonus was structurally unreachable too. A fully mature
(CI-wired, tested, buildable) python or go repo capped at 0.40
publish-readiness and could never cross genome.ts's 0.75 'ready' threshold,
independent of actual quality.

- Generalize scorePublishReadiness's language credit from a hard-coded
  typescript/rust allow-list to "any detected language" (packages/
  create-agent-harness/src/genome-scorers.ts).
- Infer a real build command for python (pip install -e . / pip install -r
  requirements.txt) and go (go build ./...) in analyze-repo.ts, matching
  the existing typescript/rust behavior.
- Add packages/create-agent-harness/__tests__/genome-scorers.test.ts, the
  first dedicated unit suite for genome-scorers.ts's 5 pure functions (it
  had zero before despite its own header claiming "unit-testable without
  fixtures"). Pre-fix: 16/18 pass (2 predicted failures, non-vacuous).
  Post-fix: 18/18. Full package suite: 476 passed, 2 pre-existing skips,
  0 regressions.

Dream Cycle nightly run, 2026-08-15. Full research findings, adversarial
critique, and evaluation receipt: docs/dream-cycle/2026-08-15-gist.md
(witness pending critic verdict, finalized in a follow-up commit).

Never merge. Human review required.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KAC5ThoiBJjj8QXxthAWg

* dream(generator-genome): finalize gist with critic verdict + close 2 caveats

Independent adversarial critic reached ACCEPT-WITH-CAVEATS on the prior
commit's candidate. Two real (non-blocking) caveats, both closed here:

- The test suite proved the fix for the 4 currently-detectable languages
  but not the "any future language" generalization claim itself. Added a
  19th test constructing a hand-built RepoProfile for a language
  analyzeFiles() has never heard of, asserting the generic credit path.
- The apps/web-ui/src/generator/repo.ts sibling gap (same pre-fix
  buildCommands bug, not touched tonight) was disclosed only in the gist,
  not in the diff a reviewer would see. Added an inline comment at the
  analyze-repo.ts buildCommands block pointing to it.

Finalized docs/dream-cycle/2026-08-15-gist.md with the critic's findings
(rust threshold analysis, advisory-only buildCommands confirmation,
process note on the mid-review commit) and computed witness hash.

Full suite: 477 passed, 2 pre-existing skips, 0 regressions. tsc clean.

Never merge. Human review required.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KAC5ThoiBJjj8QXxthAWg

* dream(generator-genome): update ledger for 2026-08-15 run

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KAC5ThoiBJjj8QXxthAWg

* chore(metaharness): 0.4.13 -> 0.4.15 — genome-scorers.ts/analyze-repo.ts changed in this PR

src/genome-scorers.ts and src/analyze-repo.ts are shipped code and 0.4.13
is already published. #229 (also generator-genome) is taking 0.4.14, so
this PR takes 0.4.15 to avoid a collision between the two in-flight PRs —
flagged by reviewer, not bumped preemptively.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KAC5ThoiBJjj8QXxthAWg

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@gmail.com>

* dream(generator-genome): #248 close zero-test-coverage gap in genome-scorers.ts (evaluated) (#249)

* dream(generator-genome): #248 close zero-test-coverage gap in genome-scorers.ts (evaluated)

genome-scorers.ts's 5 pure, deterministic, exported functions feed
genome.ts's user-visible ready/needs-work/blocked verdict and process
exit code, but had zero test coverage anywhere in the package. Adds a
33-test characterization suite with zero production code changes.

Baseline: 458 passed, 2 skipped (40 files). Candidate: 491 passed, 2
skipped (41 files) -- 0 regressions. Each new test proven non-vacuous
via seeded single-line mutation (5 mutants, one per function, all
caught, source restored byte-clean). Independent critic subagent
re-verified with its own 6th mutant and returned ACCEPT-WITH-CAVEATS.

Research independently surfaced that scoreMcpRisk's local_permissive
branch is currently unreachable via the real CLI path (recommendPlan()
always assigns a hardcoded SAFE policy) -- now documented explicitly
in the new suite rather than left as a silent gap.

Deliberately does not fix the two known bugs in this file that already
have unreviewed draft PRs open (#200 scorePublishReadiness language
credit, #229 scoreTestConfidence file verification) -- this suite
instead documents their current buggy behavior with tests named
"documented gap", so those PRs land cleanly without a 3rd competing
fix deepening the review backlog.

See docs/dream-cycle/2026-08-30-gist.md for full research, competitor
comparison, and evaluation receipt. Human review required. Does not
self-merge or autonomously promote Flywheel state.

Co-Authored-By: Claude <noreply@anthropic.com>

* dream(generator-genome): #248 ledger rows for 2026-08-15..08-30

main's LEDGER.md was stuck at 2 rows (08-13, 08-1…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant