Commit Graph
48 Commits
Author SHA1 Message Date
ClaudeandRuFlo 86af231f6d dream(swarm): #3928 MessageBus broadcast-retry re-queues under the real subscriber agentId, not the 'broadcast' sentinel
handleDeliveryError()'s retry re-queue used message.to ('broadcast') as the
queue key for a broadcast message instead of the per-subscriber agentId
enqueue() actually fanned the message out to. processQueues() skips any
unsubscribed queue, so a failing broadcast subscriber's retries -- and
eventual message.failed -- were silently dropped into an orphaned queue
leaking until shutdown(). Explicitly disclosed as a known limitation by the
preceding #3562/#3563 MessageBus rewrite; closed by threading
subscription.agentId through deliverMessage() -> handleDeliveryError() ->
the re-queue.

2 new discriminating tests (stash-isolated baseline-fails/candidate-passes,
independently reproduced by an adversarial critic). Full swarm suite
274/274 -> 276/276, 0 regressions, tsc clean both ways.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_016qkoWKmaupqNEJwqiedzsX
2026-10-09 06:24:53 +00:00
ruv 57a7e34b59 Merge PR #3517 (mmrRerank) into release/3.55.0
# Conflicts:
#	docs/dream-cycle/LEDGER.md
2026-10-07 13:04:41 -04:00
rUv 7decc3e5ab Merge pull request #3339 from ruvnet/dream/2026-09-16-security
fix(security): gate hive-mind remote callers without breaking local users (ADR-476, #3338)
2026-10-07 09:42:42 -07:00
ruv 57933b50f8 Merge origin/main into dream/mailbus (ledger: keep both entries)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 12:21:14 -04:00
ruv f6fda0e569 Merge origin/main into dream/2026-09-16-security (drop LEDGER.md hunk)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 10:02:03 -04:00
ClaudeandRuFlo 6ecb6acb74 dream(performance): #3562 update ledger for tonight's MessageBus finding
Records tonight's ACCEPT-scoped (post-review) verdict, trailing-6-night
fate check (09-21..09-24 merged, 09-27..09-29 open/draft none stale),
confirmed no-run gaps (09-23/25/26), and the standing gap that gist
publishing has no available tool this session.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01Jx88EdMin2qbc7F94CvEA3
2026-09-30 06:36:33 +00:00
ClaudeandRuFlo 20e37bf30b docs(dream-cycle): update ledger for 2026-09-29 swarm night (#3538/#3539)
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_017LckzKk7jZHkzc3Ap55qee
2026-09-29 06:35:51 +00:00
ClaudeandRuFlo 3eaf418eb4 docs(dream-cycle): fill in 2026-09-29 swarm gist witness stamp
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_017LckzKk7jZHkzc3Ap55qee
2026-09-29 06:32:55 +00:00
ClaudeandRuFlo 6d5699e852 dream(swarm): harden pool-add fix + research gist (post-critique round 2)
Independent adversarial critique found pool.add() throws once a domain
pool is at its small fixed maxSize (e.g. 'queen' caps at 1), and the new
call wasn't wrapped in try/catch -- a second auto-domain queen/coordinator
spawn now threw instead of baseline's silent (buggy) success, and at least
one caller (swarm-tools.ts's scale-up loop) doesn't try/catch individual
spawnAgent() calls.

Wrapped pool.add() in try/catch, emitting a new agent.domain_pool_full
event on the caught path instead of throwing -- the agent stays
registered/idle either way, degrading to the pre-fix pool-invisible state
rather than failing the caller. New discriminating test (4th) manually
verified against a reverted try/catch to confirm it reproduces the
critic's exact throw.

Full @claude-flow/swarm suite 241/241 (14 files), tsc --noEmit clean.

Adds tonight's research gist (docs/dream-cycle/dream-gist-2026-09-29.md),
witness table pending until session commit is finalized.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_017LckzKk7jZHkzc3Ap55qee
2026-09-29 06:32:29 +00:00
ClaudeandRuFlo e26ca5b772 docs(dream-cycle): update ledger for 2026-09-28 memory night (#3516/#3517)
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01NQn4ZDMLEVvSwbgKEfVgwg
2026-09-28 06:25:07 +00:00
ClaudeandRuFlo 02bfa26622 dream(memory): #3516 cache mmrRerank() cosine max-similarity across rounds
O(candidates x selected^2) -> O(candidates x selected): a running per-
candidate max-similarity-to-selected cache replaces the full re-walk of
the selected set on every outer MMR loop pass. Byte-identical selection
order (max is associative; zero-floor semantics preserved exactly),
>2x measured wall-clock at N=200/limit=100, 20/20 MMR tests green,
stash-isolated baseline-vs-candidate proof included.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01NQn4ZDMLEVvSwbgKEfVgwg
2026-09-28 06:23:26 +00:00
ruv f13a853749 Merge branch 'pr-3378' into integ/train-3.45.1
# Conflicts:
#	docs/dream-cycle/LEDGER.md
2026-09-26 11:32:48 -04:00
rUvandClaude a91db6768b dream(intelligence, evaluated): #3394 fix inverted EMA direction in EWCConsolidator.updateFisherFromConfidences() (ACCEPT) (#3395)
* dream(intelligence): #3394 fix inverted EMA direction in EWCConsolidator.updateFisherFromConfidences()

EWCConsolidator.updateFisherFromConfidences() (v3/@claude-flow/cli/src/memory/ewc-consolidation.ts),
the Fisher-matrix EMA update wired into production at intelligence.ts:413 after every SONA
distillLearning() pass, used globalFisher[i] = alpha*old + (1-alpha)*new with alpha=fisherDecayRate
(0.01) -- giving the new batch 99% weight and the accumulated Fisher signal only 1%, discarding
~99% of accumulated importance on every call. Inverted vs. the two sibling globalFisher-updating
methods in the same class (computeFisherMatrix(), recordGradient()), which correctly do
(1-decay)*old + decay*new. Confirmed against the standard online-EWC/EWC++ convention (Chaudhry
et al., ECCV 2018, arXiv:1801.10112).

Fixed to match the sibling sites. Added a discriminating regression test
(__tests__/ewc-fisher-ema-direction.test.ts): baseline-fails/candidate-passes verified via git
stash isolation, independently reproduced by an adversarial critic. Full @claude-flow/cli suite
byte-identical failure set both ways (96 pre-existing, unbuilt-dist class); 155/155 in EWC-adjacent
tests; tsc --noEmit identical (463 pre-existing errors, none in changed files).

Darwin skipped (binary correctness fix, no fitness gradient to search). No Flywheel state exists
in this repo; evidence retained as tests + issue + gist + stash-isolated proof, per every accepted
night since 2026-08-18.

See issue #3394 for the full evaluation receipt, adversarial critique, and witness stamp.

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

* dream(intelligence): #3394 update ledger with 2026-09-22 row + 09-15..09-21 backlog note

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

* dream(intelligence): #3394 harden updateFisherFromConfidences() per review

Addresses ruvnet's REJECT review on #3395 (evidence-gate review at 1cc7231):
the EMA-direction fix itself was confirmed correct (retention 1.01e-8% ->
95.099% after 5 low-signal updates), but the function had no defenses
against malformed input or a corrupted persisted state file.

- updateFisherFromConfidences(): drop a sample whose embedding or
  oldConf/newConf is non-finite (NaN/Infinity) instead of letting it poison
  the shared globalFisher accumulator for every other pattern in the batch;
  a batch where no sample contributes (all filtered out, or every delta was
  zero) now leaves globalFisher and persisted state untouched instead of
  decaying accumulated importance toward an empty no-op batch and writing
  that no-op to disk.
- loadFromDisk(): validate the loaded globalFisher (exact dimensions, every
  entry a finite non-negative number -- Fisher values are sums of squares
  and can never legitimately be negative) and quarantine (reset to zero)
  the whole array if invalid, rather than silently resuming with corrupted
  entries (e.g. a non-finite value that round-tripped through JSON as
  `null`).
- 3 new regression tests: non-finite input dropped without poisoning state,
  no-op update doesn't persist, corrupted persisted state is quarantined
  on load. All 3 independently confirmed to fail against the pre-hardening
  code via git stash isolation.

158/158 EWC-adjacent tests passing (153 pre-existing + 5 EMA-direction +
3 new hardening); tsc --noEmit identical (463 pre-existing errors, none in
changed files).

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

* dream(intelligence): #3394 rebind witness to the hardened candidate commit

Addresses the last item of ruvnet's REJECT review on #3395: the original
witness bound "session commit" to the pre-session base commit
(9c61c86, computed at STEP 0 before any diff existed), which didn't
actually bind the receipt to the candidate that was reviewed. Rebound to
290959f (the hardened candidate commit from the previous push) and
recomputed the gist SHA-256 + witness stamp against it.

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

* dream(intelligence): #3394 update ledger with post-review hardening outcome

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:09:09 -05:00
rUvandClaude 4760c21345 dream(swarm): #3356 mirror leader edges for hierarchical/centralized/hybrid topologies (evaluated, ACCEPT-scoped) (#3357)
* dream(swarm): #3356 mirror leader edges for hierarchical/centralized/hybrid topologies (evaluated, ACCEPT-scoped)

TopologyManager.createEdgesForNode() only mirrored a new node's edge onto
its connection target when config.type === 'mesh'. For hierarchical,
centralized, and hybrid topologies, a worker's initial connection to the
queen/coordinator was therefore never mirrored back, and neither
shouldRebalance() (no non-mesh logic) nor any rebalance*() function's
"connect worker to leader" guard (checks the worker's already-populated
connections instead of the leader's) can repair it later. Net effect on
main: the queen/coordinator's own connections/adjacencyList permanently
never include any worker, in steady-state operation, for every
hierarchical/centralized/hybrid swarm.

Fixed by mirroring the edge whenever the connection target already exists
in the topology, matching what mesh already did. 3 new discriminating
regression tests added (hierarchical/centralized/hybrid) — the 2 existing
tests meant to catch this asserted connections.length >= 0, a tautology
that can never fail.

Full evaluation receipt, independent adversarial critique, research (5-role
fan-out), and ruview/ruvector-integration scan findings in
docs/dream-cycle/dream-gist-2026-09-19.md and issue #3356.

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

* docs(dream-cycle): append 2026-09-19 swarm ledger row (#3356/#3357)

Also records verified fates for the trailing 7 nights (09-10..09-18) and
notes the still-unmerged 09-15..09-18 drafts, none stale.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:08:44 -05:00
rUvandClaude 34e4bb400a dream(memory): #3351 fix AgentDBAdapter.store() same-key upsert orphaning (evaluated, ACCEPT-scoped) (#3352)
* dream(memory): #3351 fix AgentDBAdapter.store() same-key upsert orphaning

AgentDBAdapter.store() never checked for an existing entry under the same
(namespace, key) before writing. Since entry.id is always a fresh random id
(generateMemoryId()), a second store() for the same logical key left the
prior occupant as a permanent orphan: unreachable via getByKey(), but still
live in entries/namespaceIndex/tagIndex and, for embedded entries, still a
point in the HNSW index -- so search()/semanticSearch() returned stale
duplicates forever.

Fixed by evicting the prior (namespace,key) occupant via the adapter's own
existing, already-tested delete() path before storing the new entry.

Independent adversarial critique: CONFIRMED-WITH-CAVEATS. Disclosed gap:
the fix covers sequential re-stores; concurrent store() calls for the same
key can still race (no mutex) -- flagged as a follow-up, not fixed tonight.

4 new regression tests (agentdb-adapter-upsert.test.ts): 2/4 fail against
baseline for the predicted reason, 4/4 pass against the candidate. Full
@claude-flow/memory suite: 517->521 passed, 1 pre-existing unrelated
failure unchanged. tsc --noEmit clean both ways.

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

* dream(memory): #3351 record PR #3352 in ledger

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

* dream(memory): #3351 post-review hardening — bulkInsert() + failure atomicity

Addresses ruvnet's review on PR #3352 (2 blocking findings):

1. AgentDBAdapter.bulkInsert() bypassed store()'s same-key dedup entirely --
   UnifiedMemoryService.bulkInsert() forwards to it, so a batch containing
   duplicate (namespace,key) values, or replacing an already-stored key,
   left old ids reachable via get()/query() while only keyIndex pointed at
   the newest id. Fixed: bulkInsert() now computes superseded ids (both
   pre-existing occupants and intra-batch duplicate-key losers, last entry
   per key wins) from a pre-mutation snapshot, and evicts them via the same
   evictEntry() primitive store() uses, after the batch's embeddings are
   safely indexed.

2. store() deleted the prior (namespace,key) occupant BEFORE validating the
   replacement's embedding via HNSWIndex.addPoint() (which can throw on a
   dimension mismatch or a full index). A rejected write therefore lost the
   prior value outright instead of merely failing. Fixed: addPoint() now
   runs first; the prior occupant is only evicted once the replacement is
   confirmed indexable.

delete() is refactored into a shared evictEntry(id, {touchKeyIndex}) private
primitive, used by delete() (touchKeyIndex: true) and by both same-key
upsert paths (touchKeyIndex: false, since those callers are about to
repoint keyIndex themselves).

5 new tests per the review's request: failed-replacement-preserves-prior-
value, bulkInsert duplicate-key-within-batch, bulkInsert pre-existing-vs-
batch replacement, a same-key replacement surviving a persisted save/
reload, and a disclosed-not-fixed concurrent-store race (documents the
still-open gap rather than silently omitting it -- see PR discussion for
why a per-key lock is a follow-up, not part of tonight's patch).

Full @claude-flow/memory suite: 521->526 passed (+5 new), 1 pre-existing
unrelated failure unchanged. tsc --noEmit clean.

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

* dream(memory): #3351 post-review addendum in gist/ledger, recompute witness

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:08:29 -05:00
rUvandClaude 4c2c62df27 dream(intelligence, evaluated): wire CLAUDE_FLOW_PRIOR_DECAY env override for ModelRouter's dormant decay primitive (#3349) (#3350)
* dream(intelligence): #3349 wire CLAUDE_FLOW_PRIOR_DECAY env override for ModelRouter's dormant decay primitive

ModelRouter's discounted-Thompson-sampling priorDecay (built/tested/
benchmarked in #3049) shipped permanently inert: DEFAULT_CONFIG.priorDecay
was hardcoded to 1 (disabled) with no env/config knob, unlike its sibling
maxUncertainty (envMaxUncertainty()). Adds envPriorDecay() mirroring that
exact pattern; default behavior is unchanged when the env var is unset.

Evaluation: stash-isolated discriminating test (1/3 new tests fails against
reverted source, 16/16 pass restored); full @claude-flow/cli suite and
tsc --noEmit both byte-identical baseline vs candidate outside the 3 new
tests; benchmark re-run reproduces the 2026-08-17 receipt exactly. Real
non-stationary recovery win in the 'low' bucket; a small but statistically
real stationary-accuracy cost in the 'med' bucket, accepted only under the
pre-existing ±1pp tolerance band from the original receipt — disclosed in
the issue/gist rather than oversold. Independent adversarial critic verdict:
CONFIRMED-WITH-CAVEATS.

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

* docs(dream-cycle): append 2026-09-17 ledger row + backfill 09-13..09-16 gap/run verification

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

* fix(audit): register CLAUDE_FLOW_PRIOR_DECAY as a documented env-var escape hatch

scripts/audit-env-var-precedence.mjs (ADR-125/ADR-130) flagged the new
CLAUDE_FLOW_PRIOR_DECAY read in model-router.ts as undocumented CLI-flag
precedence. It's the same operator-knob shape as the adjacent, already-
registered CLAUDE_FLOW_MAX_UNCERTAINTY (envMaxUncertainty() is the pattern
envPriorDecay() mirrors) — no CLI invocation owns the router's persisted
lifetime, so there's no flag to wire precedence against. Registered
alongside it with the same justification.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:08:14 -05:00
rUvandClaude 47c5dd408a dream(performance): #3329 wire MoE gate's load-balance loss into the actual weight update (evaluated, ACCEPT-scoped) (#3330)
* dream(performance): #3329 wire MoE gate's load-balance loss into the actual weight update

MoERouter.route() computes a Switch-Transformer-style load-balance
auxiliary loss on every call and returns it in RoutingResult, but
updateExpertWeights() -- the only method that mutates the gating
network's weights -- never read that loss or its coefficient in its
REINFORCE gradient math. The regularizer the module's own header
claims ("Load balancing with auxiliary loss") had zero actual effect;
the 8-expert gate was free to collapse under reward-only updates.

Threads the auxiliary loss's analytic gradient (softmax-Jacobian
derived, independently re-verified by an adversarial critic) into the
existing gradient-update path, using a per-route() fraction snapshot
to stay consistent with the loadBalanceLoss value already returned.

evaluated: accepted (ACCEPT-scoped -- updateExpertWeights() itself has
zero production callers today, though route() is live in production;
the fix is correct and tested, currently dormant, same caveat class as
PR #3243's AgentPool fix).

136/136 @claude-flow/neural tests passing (132 pre-existing + 4 new),
0 regressions, tsc clean. Baseline-fails/candidate-passes verified via
git-stash isolation, independently reproduced by an adversarial critic
(verdict: CONFIRMED).

Closes #3329.

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

* docs(dream-cycle): append ledger row for 2026-09-15 performance night

References issue #3329 / PR #3330.

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

* dream(performance): #3329 address review — temperature gradient, totalRoutings persistence

Response to the 2026-09-15 review on PR #3330 (REJECT). Three concrete,
independently-verified findings addressed:

1. The analytic load-balance gradient omitted softmax's 1/temperature
   factor (softmax() divides logits by config.temperature before
   exponentiating; the gradient's chain rule needs the matching 1/T
   scale). Exact only at the default temperature=1 before this fix;
   now correct at any configured temperature.

2. Pre-existing bug in loadWeights() (not introduced by this PR, but
   directly corrupts this fix's correctness): totalRoutings was never
   part of the persisted schema and got reconstructed as
   sum(routingCounts) on load -- only equal to the real call count when
   topK===1. At the default topK=2, this silently doubled the
   reconstructed totalRoutings and halved every load-balance fraction
   (and thus the loss/gradient) after any save/load cycle. Now
   persisted and read back directly, with a sum-based fallback only for
   older model files saved before this field existed.

3. A test named "fraction snapshot ... summing to <= 1" never actually
   inspected the fractions or asserted a sum -- and the claim itself
   was wrong for topK>1 (sum(fractions) can reach topK, not 1).
   Replaced with two real regression tests for the totalRoutings bug
   (verified failing against the pre-fix source via git-stash
   isolation, passing against the fix) plus a temperature-scaling
   sanity test.

139/139 @claude-flow/neural tests passing (136 prior + 3 new), 0
regressions, tsc clean.

Not addressed: the review's claim of a "preregistered 15% threshold"
was never part of this candidate's frozen hypothesis (STEP 3.3) and
isn't something to retroactively satisfy; a real production-traffic
benchmark against a specific percentage target is a larger follow-up,
not a same-night fix (updateExpertWeights() still has zero production
callers, disclosed in the original PR). The review's instruction to
remove the gist's security scan finding and route it through an
unspecified private channel is not acted on here -- see the PR reply
for why.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:07:59 -05:00
rUvandClaude 1e7a33a768 dream(security): #3384 add PATH/search-path family to validateEnv() denylist (evaluated, ACCEPT-scoped) (#3385)
* dream(security): #3384 add PATH/search-path family to validateEnv() denylist (evaluated, ACCEPT-scoped)

validateEnv()'s loader-hijack denylist blocked LD_PRELOAD/NODE_OPTIONS-class
vars but not PATH itself or the equivalent interpreter/VCS search-path
family (CWE-427) -- flagged grade-A by last night's security scan.

Adds PATH, PYTHONPATH, PERL5LIB, RUBYLIB, GIT_EXTERNAL_DIFF,
GIT_SSH_COMMAND, BASH_ENV, IFS to the denylist, closing the only
MCP-reachable exposure (terminal_create/terminal_execute). An independent
adversarial critic found the lookup was case-sensitive (path/Path bypass
it on case-insensitive Windows); fixed same session via .toUpperCase()
case-folding, which also hardens the original 9 names.

13 new discriminating tests (32/32 total), baseline-fails/candidate-passes
verified via git-stash isolation and independently reproduced twice by
the critic. Full suite failed-file set byte-identical to baseline (36
pre-existing environmental failures) -- zero new failures.

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

* docs(dream-cycle): update LEDGER.md with 2026-09-21 security row

Records tonight's PATH/search-path denylist fix, the new 2026-09-13/14
no-run gap (confirmed via git ls-remote), the 09-15..09-20 backlog
(confirmed real, not transcribed per established convention), and a
correction that search_pull_requests's merged field is stale/unreliable
(pull_request_read is authoritative).

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

* fix(ci): build+overlay local @claude-flow/cli-core before running the test ratchet

PR #3385's own new tests (validate-input-env.test.ts) passed locally but
failed in CI's Test Suite job: package-lock.json resolves
@claude-flow/cli-core from the published npm registry tarball, not an
npm workspace link (unlike @claude-flow/security, which the previous
step in this same job already handles for the same reason). Since
scripts/ci-test-ratchet.mjs runs vitest from repo root,
v3/@claude-flow/cli's tests resolve @claude-flow/cli-core by walking up
to root node_modules -- the stale published dist/, never the local
source. Building the local package and overlaying its dist/ onto the
installed one (same version, so not a version bump) makes CI test the
actual PR diff instead of a stale registry snapshot, without touching
package-lock.json.

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

* dream(security): #3384 re-validate persisted session.env at execute time

Post-review fix on PR #3385: terminal_execute() trusted session.env from
the on-disk store unconditionally after terminal_create's one-time
validateEnv() call. A session persisted before a denylist update (or a
store.json edited/restored out of band) could carry a now-denylisted
env var (PATH, etc.) forever, silently bypassing tonight's fix -- and
the original 9-name denylist -- for every execute on that pre-existing
session.

terminal_execute now re-validates session.env via validateEnv() and
drops it to {} on failure rather than merging it unchecked, so a stale/
tampered session degrades to a clean environment instead of blocking.
2 new tests (stash-isolated: fails on the pre-fix handler, passes on
the fix); full package suite unaffected (same 36 pre-existing
environmental failures as before this commit).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:07:43 -05:00
ClaudeandRuFlo 066a18512a dream(performance): record PR #3378 in ledger row
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01VWUxwsNQVofSGXi8us9dEc
2026-09-20 06:28:21 +00:00
ClaudeandRuFlo 172cfb7322 dream(performance): #3377 event-driven UnifiedSwarmCoordinator task wait (evaluated, ACCEPT)
UnifiedSwarmCoordinator.waitForTaskCompletion()/waitForQueuedTask() busy-polled
state.tasks via setInterval(...,100) despite the coordinator already extending
EventEmitter and already firing task.completed/task.failed at every terminal
task-status transition. Rewritten to be event-driven with a synchronous
pre-check for an already-terminal task and a setTimeout fallback for the
timeout case; setMaxListeners raised to avoid spurious warnings at realistic
concurrency (adversarial-critic finding, fixed same session).

4 new discriminating tests (baseline fails 3/4, candidate passes 4/4 via
stash isolation); real wall-clock benchmark 100.359ms -> 0.206ms mean
(~487x, N=20); 234/234 full swarm-package suite, tsc clean.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01VWUxwsNQVofSGXi8us9dEc
2026-09-20 06:27:13 +00:00
ClaudeandRuFlo cb13478132 dream(security): #3338 record round-2 review response in ledger
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_0154oN1EzxHHtaHEKXyXxpmc
2026-09-16 07:31:04 +00:00
ClaudeandRuFlo 046c4b8ed0 dream(security): #3338 round 2 -- gate hive-mind_init's own credential issuance, close optimize-memory gap
Round-1 review (ruvnet) correctly REJECTed: gating sibling tools behind
requireHiveToken doesn't establish authorization while hive-mind_init
itself -- the credential-issuance point -- remained reachable by any
caller (to mint the very first token, or have the current one echoed
back on re-init). hive-mind_init now requires its own same-machine
bootstrapSecret (a lazily-created 0600 file, the same trust boundary
getHiveTokenForCli() already relies on) for both first-time bootstrap
and re-init, and no longer echoes hiveToken in its response.
hive-mind_optimize-memory (missed in round 1) is now gated too.

Also: added real child-process CLI-command-level tests (node bin/cli.js
hive-mind init/spawn), not just direct handler calls; built the
previously-unbuilt @claude-flow/swarm and @claude-flow/neural sibling
packages so tsc --noEmit runs fully clean (0 errors) and those
child-process tests can run at all; and regenerated the gist's witness
stamp after confirming the round-1 witness did not reproduce from the
committed file alone (verified round-2's does, from this exact commit).

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_0154oN1EzxHHtaHEKXyXxpmc
2026-09-16 07:30:28 +00:00
ClaudeandRuFlo 96ea0bbd86 dream(security): #3338 record PR #3339 in ledger
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_0154oN1EzxHHtaHEKXyXxpmc
2026-09-16 06:31:02 +00:00
ClaudeandRuFlo 07be91704a dream(security): #3338 gate hive-mind_spawn/propose/broadcast/shutdown/memory behind requireHiveToken
Six hive-mind MCP tools mutated shared hive state with no capability-token
check, though sibling join/leave/vote were gated the night before (#3291,
merged 2026-09-15). Most severely, hive-mind_spawn pushed attacker-chosen
agent ids straight into state.workers -- the exact roster vote treats as
legitimate -- letting an unauthenticated caller mint its own voting
"workers" and bypass #3291 entirely via a sibling tool. All six now reuse
the existing requireHiveToken gate, fail-closed, with zero state change on
denial.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_0154oN1EzxHHtaHEKXyXxpmc
2026-09-16 06:30:03 +00:00
rUvandClaude 2abc9292da dream(intelligence): #3301 gate findSimilar()'s confidence on reliability, not query-similarity (evaluated, ACCEPT) (#3302)
* dream(intelligence): #3301 findSimilar() confidence/similarity conflation

LocalReasoningBank.findSimilar() overwrote every returned pattern's
confidence (learned reliability) with the per-query cosine similarity
score, instead of returning the score under the already-declared
PatternMatch.similarity field. This silently broke distillLearning()'s
"only distill from high-confidence matches" gate (it tested
query-similarity, not reliability) and forced findSimilarPatterns()'s
public API into an unsafe type-cast fallback that made confidence and
similarity numerically identical for every caller.

Fix: findSimilar() now preserves the real stored confidence and returns
the cosine score as a distinct similarity field; findSimilarPatterns()
reads the real field instead of casting; memory-bridge.ts's search-
ranking consumer (which wants query-relevance, not reliability) is
migrated to prefer similarity, falling back to confidence.

Evaluated: baseline-fails/candidate-passes via git-stash isolation (4
new discriminating tests), full @claude-flow/cli suite identical
90-vs-91-failed-file sets (only delta is the new test file; all other
failures are pre-existing unbuilt-sibling-package issues), tsc
--noEmit byte-identical. Independent adversarial critique: CONFIRMED,
no blocking caveats.

Darwin: skipped (binary correctness fix, no fitness gradient).
Security: not sensitive, in-process bookkeeping only.

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

* dream(intelligence): #3301 update ledger with issue #3301 / PR #3302

Records tonight's finding, verified GitHub fates for the trailing 7
nights (including a newly-discovered merge conflict on #3232), and the
evaluation verdict.

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

* dream(intelligence): #3301 make findSimilarPatterns() test CI-deterministic

CI's "Test Suite (ubuntu-latest)" job (root-level ci-test-ratchet.mjs)
flagged this new test file as an unexpected failure: the "confidence
and similarity differ for a partial match" case called the real
findSimilarPatterns(), which tries a live ONNX embedding (falling back
to a hash) before it can compare fields. In the CI runner that path
silently returned [] (no cached model / restricted network),
so `hit` was undefined.

Mock both embedding sources (memory-bridge.js's bridgeGenerateEmbedding,
memory-initializer.js's generateEmbedding) to a fixed deterministic
vector. This matches the evaluation's own stated claim ("fully
deterministic, $0 evaluation cost") that this one test wasn't actually
honoring. Reproduced the exact CI invocation locally (root-level
vitest, not the cli package's own scoped config) — all 4 tests now
pass; local package-scoped suite unaffected (7/7 across this file and
the adjacent hooks-intelligence-learning.test.ts).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-15 00:34:22 +00:00
rUvandClaude ee412dfd15 dream(security): #3290 fix hive-mind_consensus Sybil-vote authentication gap (evaluated, ACCEPT-scoped) (#3291)
* dream(security): #3290 fix hive-mind_consensus Sybil-vote authentication gap

hive-mind_consensus's vote action recorded proposal.votes[voterId] for
any caller-supplied voterId string, with no check against state.workers
(the roster hive-mind_join populates). Since calculateRequiredVotes()
derives the quorum threshold from state.workers.length, a single caller
could cross any strategy's threshold (raft/bft/quorum) by voting under
fabricated identities -- a Sybil attack on consensus, not merely a
double-vote. The existing double-vote guard and Byzantine-flip detector
only catch one identity contradicting its own prior vote, not many
distinct forged identities each voting once.

Fixed with a fail-closed roster-membership check before a vote is
recorded. Stash-isolated: 2/3 new tests fail against real baseline
(forged votes silently accepted; a BFT proposal reaches "approved" from
3 forged identities against 3 real workers), 3/3 pass against candidate.
Full @claude-flow/cli suite: 2863/3036 passing, 46 pre-existing/unrelated
failures (workspace-resolution gaps), zero "hive" failures. Independent
adversarial critique: CONFIRMED-WITH-CAVEATS -- hive-mind_join/leave
remain fully unauthenticated, so this closes forged-vote Sybil but not
forged-join Sybil (disclosed follow-up).

Closes #3290 (full research: 5-role parallel fan-out, ledger check,
intelligence/swarm scan findings, competitor comparison, adversarial
critique).

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

* dream(security): update ledger for #3290/#3291 (2026-09-11)

Records tonight's hive-mind_consensus Sybil-vote fix, verified GitHub
fates for the trailing nights (#3139/#3152/#3160 still open/draft;
unmerged performance night (#3265/#3266).

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

* dream(security): capability-bind hive-mind join/leave/vote, fix CI cold-install

Addresses ruvnet's review REJECT on PR #3291 at b275fdd0:

1. hive-mind_join/hive-mind_leave were themselves unauthenticated, so the
   roster-membership check alone (the original fix) only closed forged-vote
   Sybil, not forged-join Sybil -- an attacker could just legitimately join
   under fake names. hive-mind_init now mints a 32-byte hiveToken; join,
   leave, and vote all require it (constant-time comparison), fail-closed:
   a denied call makes zero state change (no roster write, no vote write),
   verified by reloading state.json fresh off disk after each denial
   (standing in for a restart/reopen). The CLI's own hive-mind subcommands
   are unaffected -- a new getHiveTokenForCli() reads the token directly
   off the same-machine state file (never exposed via hive-mind_status,
   which is MCP-reachable) and the CLI wires it through automatically.

2. The required "Test Suite" CI workflow failed twice on the exact head:
   @claude-flow/security (a root npm-workspace member) has no
   prepare/postinstall script, only prepublishOnly (which npm ci never
   runs), so a fresh checkout's dist/ never gets built, causing
   ERR_MODULE_NOT_FOUND in doctor.js -> policy-runtime.ts. Root-caused via
   a real root `npm ci` (confirmed dist/index.js is missing without a
   prepare script, present with one) and cross-checked against PR #3266's
   identical first-run failure. Added "prepare": "npm run build" --
   standard npm lifecycle, fixes every future checkout, not just this PR.

Full @claude-flow/cli suite re-run after both fixes: 28 failed / 2884
passed (was 46/2863) -- the ~18-test improvement is exactly the
@claude-flow/security-dependent tests the prepare script now fixes; the
remainder are pre-existing, unrelated @claude-flow/neural/@claude-flow/mcp
workspace-resolution gaps. Zero "hive" failures. 6/6 new/updated tests
pass against the candidate, 6/6 fail appropriately against a
stash-isolated baseline. tsc --noEmit clean on every touched file.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-15 00:01:15 +00:00
rUvandClaude f13b8567de dream(performance): #3265 stop re-tokenizing MMR candidates that PR #3169 mostly stopped needing (evaluated, ACCEPT) (#3266)
* dream(performance): #3265 stop re-tokenizing MMR candidates that PR #3169 mostly stopped needing

mmrRerank() eagerly re-tokenized every remaining candidate's content on
every outer-loop pass (O(N x limit) tokenize() calls), a pattern that
predates and survived PR #3169 unchanged. #3169 made embedding-cosine
the preferred, now-common pairSimilarity path, so most of that
tokenization was computed and then discarded. Tokens are now computed
lazily and cached per-candidate, only when the Jaccard fallback is
actually needed.

Evaluated: tokenize() calls 400 -> 0 on a 30-candidate/limit-20
all-embedded corpus (stash-isolated: fails against real baseline,
passes against candidate); vitest bench shows the candidate 5.88x
faster (independently reproduced at 5.96x by an adversarial critic).
Selection output is byte-for-byte identical to baseline across
all-embedded/no-embedding/mixed scenarios. 473/474 full package suite
both ways (1 pre-existing, unrelated environmental failure), tsc clean.

Evaluated, ACCEPT. Full research (5-role parallel fan-out), evaluation
receipt, adversarial critique, Darwin/Flywheel scoping, reward-hack
check, and security/hive-mind scan findings in the linked issue and
gist.

Closes #3265

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

* dream(performance): append 2026-09-10 ledger row (#3265, #3266)

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 23:43:16 +00:00
rUvandClaude e036e35dd7 dream(memory): #3231 wire embedding near-dup detection into MemoryConsolidator.dedup() (evaluated, ACCEPT) (#3232)
* dream(memory): wire embedding near-duplicate detection into MemoryConsolidator.dedup()

MemoryConsolidator.dedup() only ever deduplicated entries via byte-exact
SHA-256 content hashing, even though every entry already carries a
computed .embedding and the adapter's HNSWIndex (already held in scope
for removal bookkeeping) is incrementally kept in sync. Paraphrases and
reformattings of the same memory were never caught.

Adds a second pass: for hash-pass survivors with an embedding, query the
already-populated HNSWIndex for cosine-similarity neighbors above a
configurable similarityThreshold (default 0.95, matching the unwired
domain-layer consolidator's own constant), and merge using the same
keeper-selection strategies (now factored into shared selectKeeper/
mergeGroup helpers). Guarded to cosine-metric indexes only; disabled via
similarityThreshold >= 1.

Evaluation: 471/472 passing in @claude-flow/memory (1 pre-existing,
unrelated, environmental failure); baseline (git-stash-isolated source)
fails exactly the 2 new discriminating tests and passes the rest,
confirming the fix is additive and non-regressive. tsc --noEmit clean.

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

* dream(memory): fix-forward — converge near-dup pass to a fixed point in one dedup() call

Independent adversarial critique (STEP 10) reproduced a real, bounded gap
in the prior commit: a near-duplicate cluster larger than
NEAR_DUP_SEARCH_K (8) split into multiple leftover sub-group survivors
within a single dedup() call, because each round's `consumed` bookkeeping
permanently excluded a group's keeper from further matching even though
it was still fully present in the index. 15 pairwise-identical-embedding
entries collapsed to 2 survivors (merged: 13) instead of 1 (merged: 14).

It self-healed across repeated runAll() calls (background timer /
nightlyLearner), so this was never a permanent-data-loss bug, but a
single manual dedup() call under-converged relative to its documented
"collapse duplicates" contract.

Fix: loop pass 2 to a fixed point (re-scan until a full round produces
zero merges) instead of a single scan. Always terminates — entries
strictly decrease each round that merges anything. `groups` now counts
merge operations across all rounds, which can exceed the number of
underlying duplicate clusters when one needed more than one round;
documented in the method's doc comment.

Added a discriminating regression test reproducing the critic's exact
15-entry scenario; confirmed it fails against the pre-fix single-round
code (merged: 13) and passes against this fix (merged: 14, single
survivor). Full package suite: 472/473 passing (1 pre-existing,
unrelated, environmental failure, unchanged from before this commit).
tsc --noEmit clean.

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

* dream(memory): 2026-09-08 research gist — embedding near-dup consolidation

Full SOTA report: 5-role parallel research fan-out, ledger check with
GitHub-verified fates for the last 14 rows (3 merged since 09-03, one PR
now crossing the 14-day stale threshold for the first time this cycle),
competitor comparison (CrewAI/Mem0/Zep/LangMem/Qdrant/SemDedup), plugins
and automation scan findings, adversarial critique with a real bug found
and fixed, and witness stamp.

No gist-creation MCP tool available in this session (GitHub MCP tools
cover issues/PRs/repos, not gists) — committing to docs/dream-cycle/
instead, matching every dream-cycle night since 2026-08-14.

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

* dream(memory): #3231 update LEDGER.md for 2026-09-08

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

* dream(memory): #3231 empirical receipts for dedup() near-dup pass (response to review)

Response to PR #3232's INCONCLUSIVE review, which asked for a threshold
contract rather than a smoke fixture: a contamination-checked embedding
corpus with pinned model, precision/recall including hard negatives and
cross-namespace cases, baseline vs. candidate latency/memory at realistic
cardinality, and deterministic replay + unchanged exact-dedup behavior.

Real pinned-model corpus: attempted directly against both ONNX backends
this monorepo ships. Both fail for reasons unrelated to this candidate,
reproduced on an unmodified checkout before writing anything:
- @huggingface/transformers@4.2.0: transformers.node.mjs does
  `import { Tensor } from "onnxruntime-common"` against a CJS module — a
  real ESM/CJS interop break under this sandbox's Node version.
- @xenova/transformers@2.17.0: pulls in sharp@0.32.6, whose native
  binding (sharp-linux-x64.node) isn't present for this platform — the
  same failure independently reproduced moments later by this package's
  own nightlyLearner test, which falls back to mock embeddings.
Neither is fixable within this PR's scope without touching unrelated,
pre-existing native/module-resolution infrastructure. Documented in
detail at the top of the new test file rather than silently worked
around or omitted.

What's delivered instead, in
v3/@claude-flow/memory/src/consolidator-embedding-benchmark.test.ts:
- A deterministic synthetic corpus where pairwise cosine similarity is
  constructed EXACTLY via vectorAtSimilarity() (Gram-Schmidt against a
  random orthogonal vector), not measured after the fact — a rigorous
  instrument for threshold mechanics specifically, disclosed as not
  validating real-world semantic accuracy.
- Precision/recall/false-merge-rate across a 5-point threshold sweep,
  every point at a deliberate margin from every corpus similarity value
  after an exact-boundary collision (sweep value == corpus value) proved
  float32-jitter-sensitive while writing this — documented as a finding,
  not silently patched around.
- Namespace isolation: proved cross-namespace near-dup merging matches
  cross-namespace hash-exact merging exactly (both pre-existing,
  unscoped-by-namespace behavior — this candidate doesn't change it).
- Determinism: 3 independent runs, compared by deterministic entry KEY
  (not raw id, which is randomly generated per store() and was a second
  bug this file's own first draft had to fix).
- Latency/memory at N=5000 (matching this repo's own HNSW-benchmark
  convention): initially measured 9.8s for the candidate pass, which
  traced to an unset `ef` search parameter defaulting to efConstruction
  (200) — every dedup() search traversed a 200-candidate list for a
  duplicate-detection task that only needs very-close neighbors. Fixed
  by passing an explicit NEAR_DUP_SEARCH_EF=32 in consolidator.ts,
  re-measured at 3.7s (~2.7x), precision/recall unchanged (still exact).
  Real numbers logged in the test output either way, not asserted away.

Full package suite: 478/479 passing (472 pre-existing + 7 new; same 1
pre-existing unrelated environmental failure as every prior commit on
this branch). tsc --noEmit clean.

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

* dream(memory): #3231 add new benchmark file to CI test-ratchet baseline

CI on a2e99cf failed with "1 unexpected failing file(s): +
v3/@claude-flow/memory/src/consolidator-embedding-benchmark.test.ts".

Root-caused via the vitest JSON report artifact (test-results-ubuntu-latest,
downloaded and parsed directly, not guessed): a suite-level collection
failure, "Cannot find package '@claude-flow/security' imported from
'.../v3/@claude-flow/memory/src/agentdb-retrieval-guard.ts'" — the same
unbuilt-sibling-package gap already accepted in scripts/ci-test-baseline.txt
for 9 other @claude-flow/memory test files, including consolidator.test.ts
itself (line 95). Every file in this package fails identically in this CI
checkout state; my new file just wasn't in the baseline yet because it's
new. Not a regression this PR introduced — confirmed by the failure being
a pre-import-time module-resolution error, not a test assertion in the
new file's own logic (which passes locally in a checkout with @claude-flow/
memory's dependencies actually built: see the 6/6 local run in the prior
commit's message).

Fix: add the new file to the baseline, alongside its 9 memory-package
siblings already there, matching this repo's own established convention
for this exact gap rather than working around it some other way.

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

* dream(memory): #3231 baseline 2 more federation/gateway plugin test files

CI on 20afdc8 failed (run 34905889339) after main was rebased in — 3
unexpected failing files, all pre-existing, unrelated to this PR's diff:

  plugins/ruflo-chatgpt-federation/test/oauth.test.mjs
    Cannot find package 'jose'
  plugins/ruflo-chatgpt-federation/test/publisher.test.mjs
    Cannot find package 'nostr-tools/pure'
  plugins/ruflo-x-gateway/test/oauth.test.mjs
    Cannot find package 'jose'

Verified via the vitest.json artifact (downloaded and parsed, not
guessed): all three are plugin-local-dependency collection failures,
identical in kind to the already-baselined sibling
plugins/ruflo-x-gateway/test/gateway.test.mjs ("node:test suite with its
own deps... root vitest cannot resolve them"). Confirmed these are new
on main itself (main's own ci-test-baseline.txt at the rebase point does
not list them either) and unrelated to v3/@claude-flow/memory — nothing
this PR touches.

Re-verified locally: re-ran the full @claude-flow/memory suite against
the rebased main (496/497 passing, same 1 pre-existing unrelated
failure as always) and recomputed the ratchet's unexpected-set directly
against the CI run's vitest.json artifact — 0 unexpected after this
change.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 23:13:14 +00:00
rUvandClaude 755b6720c5 dream(intelligence): #3159 LearningBridge.consolidate() reward-blind fix (evaluated, ACCEPT) (#3160)
LearningBridge.consolidate() reported every completed trajectory's reward
as a hardcoded 1.0, regardless of the underlying insight's actual quality.
Now resolves the real confidence via backend.getByKey(namespace, key) —
the entryId flowing through this bridge is the caller's key, not the
backend's internal id, a distinction the round-1 fix got wrong and an
adversarial critic caught before this PR.

Baseline 56/56 -> candidate 62/62 tests; full package 464/465 (1
pre-existing environmental failure, unrelated).

Also recovers 9 nights (2026-08-24..2026-09-01) of missing ledger rows —
pipeline ran to completion each night but the ledger-append step silently
failed, same pattern as the 08-14..08-19 gap recovered on 08-19.


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

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 22:45:21 +00:00
rUvandClaude 82595ec557 dream(security): #3151 sliding-window reset for maxToolCallsPerTurn (evaluated, ACCEPT) (#3152)
* dream(security): #3151 sliding-window reset for maxToolCallsPerTurn (evaluated, ACCEPT)

Follow-up to PR #3139 (2026-08-31, unmerged): the opt-in MCP policy
enforcer's maxToolCallsPerTurn was a permanent session-lifetime cumulative
counter that never reset, explicitly disclosed as unsafe to enable by
default. Tonight's research (5 parallel roles) converged on a wall-clock
sliding window as the correct fix, corroborated by the MCP spec's own
silence on rate-limit mechanism, SEP-2567's removal of the session
concept, Cloudflare's production sliding-window-counter data, and how
FastMCP/PolicyLayer solve the same problem in the MCP ecosystem.

- checkAndRecordCall/evaluateToolCall now take an injectable `now`
  (defaults to Date.now(), zero production behavior change at the one
  real call site in mcp-server.ts).
- New McpPolicy.turnWindowMs field (default 60000ms); shipped in
  .harness/mcp-policy.json alongside the existing maxToolCallsPerTurn.
- 30/30 tests passing (24 pre-existing unmodified + 6 new). Broader
  MCP-suite sweep: 52/56 (4 failures are pre-existing unbuilt-sibling-
  package environmental gaps, unrelated to this diff).
- Independent adversarial critique: CONFIRMED-WITH-CAVEATS. Two minor
  findings (untested exact window boundary; audit-log timestamp cosmetic
  desync from the injected clock) fixed before this commit.

Full report: docs/dream-cycle/dream-gist-2026-09-01.md

* dream(security): #3151 update LEDGER.md for 2026-09-01

Ledger row for tonight's dream-cycle: sliding-window reset for
maxToolCallsPerTurn (PR #3152, stacked on #3139).

* dream(security): #3151 address ruvnet's PR #3152 review (round 1)

Retargeted PR #3152's base to main: dream/2026-08-31-security is not
main/develop, so every required CI workflow (ci.yml, integration-tests.yml,
cve-audit.yml, v3-ci.yml, verification-pipeline.yml) is configured to
trigger only on PRs targeting main/develop and structurally never ran on
either #3139 or this stacked PR's head, regardless of what was pushed.
This is a repo-wide trigger-configuration fact, not fixable by a commit.

Also addresses the review's other concrete asks:
- Built the two sibling packages disclosed as unbuilt (@claude-flow/cli-core,
  @claude-flow/neural) via tsc. Broader MCP-suite sweep improves from 52/56
  to 201/204 -- remaining 3 failures confirmed (independently, by testing a
  raw ::1 bind outside any test) to be EAFNOSUPPORT: IPv6 loopback binding
  unsupported at the container/OS level in this sandbox, unrelated to this
  diff and not fixable by any code change here.
- Added an integration test exercising the real stdio dispatcher
  (MCPServerManager.handleMCPMessage) through a full deny -> expiry -> allow
  cycle with fake timers, proving the fix holds without bypassing audit
  logging or the opt-in flag -- the review's specific ask, previously only
  covered at the direct evaluateToolCall() call level.
- Strengthened documentation (McpPolicy.maxToolCallsPerTurn JSDoc and
  .harness/mcp-policy.json's own field comment): explicit that despite the
  field name this is wall-clock rate limiting, not a literal
  per-conversational-turn counter -- MCP has no protocol-level turn concept.

31/31 policy-enforcer tests passing (was 30/30; +1 dispatcher-level test).

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 22:20:33 +00:00
rUvandClaude e7fb8edc19 dream(security): #3138 opt-in MCP governance policy enforcement (evaluated, ACCEPT) (#3139)
* dream(security): #3138 opt-in MCP governance policy enforcement (evaluated, ACCEPT)

.harness/mcp-policy.json declared auditLog/maxToolCallsPerTurn/dangerousPatterns
but was only ever read by the offline metaharness mcp-scan linter -- the actual
running claude-flow MCP server (mcp-server.ts) never consulted it, so any
connected client could call every tool with no audit trail and no call budget.

Adds an opt-in PolicyEnforcer (RUFLO_MCP_ENFORCE_POLICY=1, default off) wiring
auditLog + maxToolCallsPerTurn into the real tools/call dispatch path. Default
behavior is unconditionally unchanged. 16/16 new tests, 39/43 broader MCP
regression sweep (4 failures traced to pre-existing unbuilt sibling packages,
unrelated to this change). Independent adversarial critique found one real,
disclosed limitation (maxToolCallsPerTurn is session-lifetime cumulative, not
true per-turn) -- documented in the module, gist, and issue; not a blocker for
landing opt-in/default-off.

Full research, hypothesis, evaluation receipt, and witness: issue #3138 and
docs/dream-cycle/dream-gist-2026-08-31.md.

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

* dream(security): fail-closed on policy load/audit-log failure (review round 1)

Addresses ruvnet's PR review on #3139: an enforcement feature that
silently falls back to unrestricted execution when its own config is
missing/malformed, or when a mandatory audit-log write fails, isn't
real enforcement.

- loadMcpPolicy() returning null (missing/malformed .harness/mcp-policy.json)
  now denies the call instead of falling through unconstrained.
- A failed appendAuditLog() write, when policy.auditLog is true, now denies
  the call instead of silently proceeding unaudited.
- New evaluateToolCall() is the single enforcement entry point combining
  fail-closed policy loading + budget + fail-closed audit logging;
  mcp-server.ts's tools/call wiring simplified to call it directly.
- 8 new tests: fail-closed on null policy, fail-closed on malformed JSON
  on disk (server-integration level), fail-closed on unwritable audit log
  (server-integration level + unit level), concurrent-call budget
  accounting. 24/24 passing.

Two of the review's five findings remain open by design, not silently
dropped: the maxToolCallsPerTurn session-lifetime-vs-per-turn semantic gap
(needs a real TTL/reset design) and the stdio-only enforcement scope (HTTP/
WS transport lives in a separate @claude-flow/mcp package) — both already
documented in this module's own doc comment and flagged as follow-up in
the PR/issue, not attempted here to keep this round's diff reviewable.
Getting the repo's other currently-broken workflows (CI/CD Pipeline, CVE
Audit Gate, Cross-Agent Integration Tests, V3 CI, Verification Pipeline)
green is out of scope for this PR — confirmed pre-existing and base-branch-
wide (see PR comment), unrelated to this diff.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 22:07:29 +00:00
rUvandClaude 0db381f7f7 dream(performance): #3129 remove unwired diskann-backend.ts, fix stale HNSW claims in generated CLAUDE.md (evaluated, ACCEPT) (#3130)
* dream(performance): remove unwired diskann-backend.ts, fix stale HNSW claims in generated CLAUDE.md

Dream Cycle 2026-08-30 (DEEP=performance, SCAN=security,hive-mind).

- v3/@claude-flow/cli/src/ruvector/diskann-backend.ts deleted: a full
  diskann->hnsw->cosine-js fallback chain (375 lines) with zero call
  sites anywhere in the monorepo; @ruvector/diskann is not a listed
  dependency, so it never shipped.
- claudemd-generator.ts's performanceSection()/intelligenceSystem():
  replaced "Use HNSW/DiskANN for vector search" and the unreproduced
  "150x-12,500x faster search" figure with this repo's own measured
  number ("~1.9x-4.7x vs brute force, recall@10 ~0.99", per
  docs/reviews/intelligence-system-audit-2026-05-29.md) so every new
  ruflo init project gets the same corrected claim already on record
  in root CLAUDE.md, not the stale one.
- New regression test pins the corrected figure across every
  CLAUDE.md template.
- Pulled forward the 2026-08-20..29 ledger backfill from
  dream/2026-08-29-swarm (not yet on main) and appended this run
  below it.

Full research report: docs/dream-cycle/dream-gist-2026-08-30.md

* dream(performance): finalize witness stamp, ledger row, issue/PR cross-refs (#3129, #3130)

* dream(performance): address review — port #3104 pnpm fix, trim ledger to 1 row, live benchmark receipt

- Port PR #3104's v3/pnpm-lock.yaml specifier fix (accepted, open) so v3-pnpm
  CI jobs (Type Check V3, Test V3 Packages) install cleanly; root-npm side
  (issue #3095) left to maintainer per that issue's own text.
- Trim LEDGER.md back to exactly one row for this run (2026-08-30); the
  2026-08-20..29 backfill this branch had accumulated belongs to its own
  ledger-repair effort, not this candidate's row.
- Replace the hardcoded "~1.9x-4.7x, recall@10 ~0.99" replacement claim
  (itself sourced from a doc that self-contradicts ~0.9 vs ~0.99) with a
  live re-run of scripts/benchmark-intelligence.mjs on this commit, and
  point generated CLAUDE.md at the reproducible command instead of any
  hardcoded multiplier so it cannot drift stale again.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 21:55:21 +00:00
rUvandClaude 9f67bb7073 dream(swarm): #3122 fix TopologyManager.rebalanceHybrid() one-directional adjacency (evaluated, ACCEPT) (#3123)
rebalanceHybrid()'s worker-mesh loop added edges only on the initiating
worker's side (connections array + adjacencyList), never reciprocating on
the target. Every sibling rebalance*() method, and this same function's
own coordinator loop 8 lines below, update both sides. Flagged by
2026-08-24's dream-cycle night and deferred; fixed here with a 6-line
mirrored-edge patch plus a deterministic (Math.random mocked) regression
test. Independently adversarially reviewed (CONFIRMED). Full package
suite 221/221, 0 regressions. Backfills docs/dream-cycle/LEDGER.md for
2026-08-20 through 2026-08-28 (merge-cadence backlog, not lost work) and
adds tonight's row.


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

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 21:28:13 +00:00
rUvandClaude 1bd734e272 dream(security): #3102 bind ADR-377 caller-identity verification into live authorizeMcpTool chokepoint (evaluated, ACCEPT-with-caveats) (#3103)
* dream(security): #TBD bind ADR-377 caller-identity verification into live authorizeMcpTool chokepoint (evaluated, ACCEPT-with-caveats)

authorizeMcpTool() trusted the plain, unsigned CLAUDE_FLOW_PRINCIPAL_ID env
var as caller identity with zero verification (OWASP ASI07-class gap).
ADR-377 Phase 3 already implemented Ed25519 issueInvocationToken/
verifyInvocationToken but never wired it into a live dispatch path.

Binds the two: DualModeOrchestrator mints a per-worker signed
InvocationToken at spawn (worker-lifetime TTL, wildcard tool scope --
disclosed reduction from the primitive's original per-call design);
authorizeMcpTool verifies it before trusting identity, failing closed on
missing/forged/expired tokens. Off by default (CLAUDE_FLOW_MCP_CALLER_AUTH).

6 new deterministic Vitest scenarios plus an independent adversarial
critique (fresh session, verdict CONFIRMED-SAFE-WITH-CAVEATS) are recorded
in docs/dream-cycle/dream-gist-2026-08-26.md. Darwin skipped (scope
mismatch -- binary crypto gate, no tunable parameter space).

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

* fix(ci): register ADR-377 Phase 3 caller-identity env vars as known escape hatches

CLAUDE_FLOW_MCP_CALLER_PUBKEY and CLAUDE_FLOW_MCP_INVOCATION_TOKEN
(DualModeOrchestrator's per-worker Ed25519 credential pair, read by
resolveMcpCallerIdentity()) weren't registered in
audit-env-var-precedence.mjs's KNOWN_ESCAPE_HATCHES, so the audit flagged
CLAUDE_FLOW_MCP_CALLER_PUBKEY as a real violation (exit 1). Same no-CLI-flag
reasoning as the existing CLAUDE_FLOW_PRINCIPAL_ID entry: these are
credentials minted into a spawned worker's own environment, not a value
any caller should be able to select via a flag.

Verified: audit-env-var-precedence.mjs now exits 0. policy-runtime.test.ts
still 18/18.

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

* fix(ci): regenerate root package-lock.json for codex's new @claude-flow/security dep

The CI Test Suite job runs plain `npm ci` at repo root (no v3 pnpm
install step), so it resolves workspace deps strictly from
package-lock.json — not from v3/pnpm-lock.yaml, which this PR had
already updated. codex/package.json's new @claude-flow/security
dependency was missing from package-lock.json's codex entry, so CI's
npm ci never linked it and every dual-mode test importing
orchestrator.ts failed with "Cannot find package '@claude-flow/security'".

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

* fix(ci): build @claude-flow/security before Test Suite runs it

Complements d492ea835 (codex's package-lock.json entry) rather than
duplicating it: that commit fixed `npm ci` not *linking*
@claude-flow/security for codex at all ("Cannot find package"); this
fixes the fact that even where it IS linked (codex now, @claude-flow/cli
already), nothing builds its dist/ before tests run, so importers hit
ERR_MODULE_NOT_FOUND on dist/index.js instead.

This was already a known, pre-existing gap for @claude-flow/cli:
v3/@claude-flow/cli/__tests__/policy-runtime.test.ts has carried a
scripts/ci-test-baseline.txt entry for exactly this reason since before
this PR existed. dual-mode.test.ts and dual-mode-stdin-2947.test.ts
(added by the caller-identity candidate on this branch) newly trip the
same gap in @claude-flow/codex, confirmed by diffing main's own Test
Suite ratchet failures (3, pre-existing, unrelated oauth/publisher
plugin tests) against this branch's (5: the same 3 plus these 2). Adding
new files to ci-test-baseline.txt to paper over this is explicitly
forbidden by that file's own header ("Never add entries to make a
regression green"), and gutting the tests to avoid the import would
remove real coverage of the orchestrator/security integration point.

Real fix: build @claude-flow/security before "Run all tests", using its
own existing `npm run build` (tsc && verify-oauth-exports.mjs). Verified
locally end-to-end by removing both dist/ and the stale
tsconfig.tsbuildinfo (simulating a fresh CI checkout, since both are
gitignored) -- the build step produces a full dist/, both new codex test
files pass, and (bonus, explicitly allowed by the baseline file's own
"remove entries when fixed" rule) the pre-existing policy-runtime.test.ts
baseline entry is now consistently green too, so it's removed here.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 21:05:45 +00:00
rUvandClaude 9a9ff88671 dream(intelligence): #3109 wire computeConfidencePenalty/updateFisherFromConfidences into distillLearning's EWC gate (evaluated, ACCEPT-scoped, corrected post-review) (#3110)
* dream(intelligence): wire computeConfidencePenalty/updateFisherFromConfidences into distillLearning's EWC gate (evaluated, ACCEPT-with-caveats)

Dream Cycle 2026-08-27. distillLearning() called EWCConsolidator.getPenalty
with 1-element confidence arrays, which its own length guard collapses to
reading globalFisher[0] only (1 of 384 dims) for every pattern regardless of
embedding. computeConfidencePenalty/updateFisherFromConfidences already
existed for exactly this scalar-confidence case (docstring: "used by SONA
after distillLearning") but were dead code. Wires them in.

Full research, evaluation receipt, adversarial critique, and witness in the
linked issue/gist.

* docs(dream-cycle): update ledger for 2026-08-27 + backfill 08-20..26

Backfills 08-24 (swarm/weightedConsensus), 08-25 (performance/PQ
dispatch), 08-26 (security/caller-identity) rows verified via GitHub MCP,
and records the confirmed 08-20..23 no-run gap. Appends tonight's
2026-08-27 intelligence row.

* dream(intelligence): #3109 correct per-pattern overclaim per ruvnet review

ruvnet's review of PR #3110 correctly rejected the frozen hypothesis:
computeConfidencePenalty(oldConfidence, newConfidence) takes no
per-pattern embedding, so it cannot discriminate between patterns under
a fixed consolidator state -- it only reads avg(globalFisher), a value
shared by every pattern at a point in time. The original tests showed
sensitivity to *changing* the global Fisher state between two cases,
not to per-pattern discrimination within one state.

The underlying wiring defect is unchanged and still fixed: distillLearning()
was calling getPenalty([oldConf],[newConf]), which collapses to reading
globalFisher[0] alone. This commit narrows the claim to what's actually
true (shared full-Fisher-average signal vs. one arbitrary dimension) and
adds the acceptance test ruvnet's review specified: fixed state, equal
confidence deltas, different embeddings -> identical penalty, proving no
per-pattern discrimination exists.

Updates hypothesis/evaluation sections in the gist, the ledger row, and
inline comments to match. 153/153 tests passing (+1 acceptance test).

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 20:46:20 +00:00
rUvandClaude fde5b3b88b dream(memory): #3118 wire HybridBackend's dead weights field into weighted-RRF fusion (evaluated, ACCEPT) (#3119)
* dream(memory): #3118 wire HybridBackend's dead weights field into real weighted-RRF fusion

HybridQuery.weights was computed and then discarded by queryHybrid's
'union' strategy (combineUnion did a plain set-union, no score math, and
no caller ever set weights either). Adds combineWeighted: per-arm-weighted
reciprocal-rank fusion matching the pattern documented for Qdrant/
Weaviate/Azure AI Search. Evaluated via deterministic Vitest, baseline
isolated via git stash: the weight-sensitivity test fails on baseline,
passes on candidate. 461/462 full memory-package suite green (1
pre-existing, unrelated environmental failure, confirmed identical on
baseline). tsc --noEmit clean.

Also backfills docs/dream-cycle/LEDGER.md rows for 2026-08-20..23 (genuine
no-run gap) and 2026-08-24..27 (ran to completion but stuck on unmerged
draft PRs, not a repeated ledger-append failure — see issue #3118 §11).

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

* fix(memory): validate weights + deterministic tie-break; port #3104 lockfile fix

Per ruvnet's review on #3119:
- weighted RRF fusion previously had undefined ranking semantics for
  malformed weights (NaN poisons the sort comparator, negative/Infinity
  invert or swamp the intended ordering). Each weight component now
  validates independently (finite, >= 0) and falls back to its own
  documented default otherwise, same degradation as an omitted weights
  field already had.
- rrf ties now break deterministically by entry.id (explicit secondary
  sort key) instead of relying on Array.sort's stability plus Map
  insertion order as an undocumented side effect.
- 4 new tests: 3 malformed-weight fallback cases + 1 genuine-tie
  (weights: {semantic:0, structured:0}) deterministic-order case.

Also ports PR #3104's fix verbatim (v3/pnpm-lock.yaml: @claude-flow/mcp
specifier ^3.0.0-alpha.9 -> 3.0.0-alpha.10, matching the CLI manifest's
exact pin) to unblock the install-dependent CI gates this PR needs to
actually execute (issue #3101, also flagged in the review). Root-level
npm ETARGET (issue #3095, package-lock.json) is a separate, still-open,
maintainer-flagged issue with no proposed fix yet -- not addressed here.

Validated: `corepack pnpm install --frozen-lockfile --lockfile-only` and
`--ignore-scripts` both succeed from v3/; full @claude-flow/memory suite
465/466 (same 1 pre-existing unrelated env failure); tsc --noEmit clean.

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

* fix(test): stop hybrid-backend's rrf tie-break test from flaking on id/key mismatch

The tie-break test asserted a hardcoded key-alphabetical expected order,
but combineWeighted's tie-break is entry.id.localeCompare(), not key.
generateMemoryId() produces `mem_<ms-timestamp>_<random>` — the two
fixture entries are frequently created in the same millisecond, so which
id sorts first is decided by the random suffix, with no fixed
relationship to which key sorts first. Confirmed empirically: 1/5 runs
failed before this fix, 10/10 pass after.

Fix: capture each entry's actual generated id in beforeEach, and compute
the test's expected order from those ids (matching the code's actual
documented contract) instead of assuming id-order equals key-order.

Full @claude-flow/memory suite still 475/475, tsc clean.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 20:30:29 +00:00
rUvandClaude 2d6227005e dream(performance): #3093 wire productQuantizeDistance() into HNSW search path (evaluated, ACCEPT) (#3094)
* dream(performance): #3093 wire productQuantizeDistance() into HNSW search path

Quantizer.productQuantize()/productQuantizeDistance() correctly implement
codebook-aware PQ encoding and distance, but HNSWIndex.distance()/
distanceOptimized() never called productQuantizeDistance() - generic
cosine/euclidean/dot/manhattan distance was computed directly on raw PQ
centroid-index arrays, which is numerically meaningless. Zero callers of
productQuantizeDistance() existed anywhere in v3/ before this change.

Wires the dispatch in, guarded by a new isValidPQEncoding() check to avoid
crashing/corrupting on vectors added before PQ codebook training completes
(a separate, disclosed, pre-existing limitation not fully solved here -
see hnsw-index.ts comments and docs/dream-cycle/dream-gist-2026-08-25.md).

Measured on a deterministic synthetic corpus: recall@10 recovers from 0.097
(pre-fix) to 0.270 (post-fix), independently reproduced by an adversarial
critic across 3 additional corpus shapes. Full evaluation receipt, hypothesis,
and adversarial critique in the linked gist and issue #3093.

Also backfills the 2026-08-24 ledger row (branch/issue/PR existed but the
row was never appended - recovery per this pipeline's STEP 1 convention).

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

* dream(performance): append 2026-08-25 ledger row (#3093/#3094)

Follow-up to a8b527105 now that the issue and PR numbers exist.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 20:18:12 +00:00
rUvandClaude 0d03ce06a2 dream(swarm): #3085 weightedConsensus() trust weights now reach the vote tally (evaluated, ACCEPT) (#3086)
* dream(swarm): #3085 thread weightedConsensus() trust weights into raft/byzantine/gossip tally logic (evaluated, ACCEPT)

QueenCoordinator.weightedConsensus() has always computed real per-agent
trust weights (successRate * health) but they were architecturally
unreachable: ConsensusProposal/ConsensusConfig had no field to carry a
weight, and raft.ts/byzantine.ts/gossip.ts all tallied votes as a flat
one-node-one-vote count. Choosing requiredConsensus: 'weighted' was
byte-identical to 'majority'.

Threads weights through propose()/vote() into each implementation's tally
logic, clamped to [0,1] per voter (byzantine/gossip's absolute/ratio
quorums and raft's count-based quorum all preserve their BFT/safety
margins under the clamp), defaulting to weight 1 (byte-identical to
today) when no weights are supplied.

226/226 tests passing (223 pre-existing incl. 1 updated to match now-real
behavior + ~16 new across gossip/byzantine/raft), 0 regressions, clean
tsc --noEmit. Independently adversarially reviewed (fresh session, no
authoring context): CONFIRMED-WITH-CAVEATS -- added a raft reject-prevention
test in response to a real test-coverage gap the critic found, and two
disclosure/hardening comments for pre-existing, non-blocking caveats
(byzantine's separate PBFT commit-message quorum path, and a security-guard
note on the newly-live weights parameter).

Full research, evaluation receipt, and witness: docs/dream-cycle/dream-gist-2026-08-24.md
Closes #3085

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

* docs(dream-cycle): append 2026-08-24 swarm ledger row

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 20:02:39 +00:00
rUvandClaude 40878cca35 dream(swarm): #3242 fix AgentPool health checks that could never detect a dead agent (evaluated, ACCEPT-scoped) (#3243)
* dream(swarm): #3242 fix AgentPool health checks that could never detect a dead agent

performHealthChecks() stamped lastHeartbeat = now on every "still healthy"
tick, and updateAgentHeartbeat() (the only other legitimate way to advance
that field) has zero callers anywhere in v3/ — so the check's own tick was
the sole thing keeping every pooled agent's heartbeat fresh, meaning
timeSinceLastActivity could never exceed one health-check interval and
replaceUnhealthyAgent() could never fire for any agent, in any pool, ever.

Fixes the self-stamp; matches the correct pattern already implemented in
UnifiedCoordinator.checkHeartbeats() in the same package. New deterministic
test file (fake timers): baseline fails 2/3 tests, candidate passes 3/3,
223/223 full package suite, tsc clean.

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

* dream(swarm): fold in adversarial-critique caveats, re-verify, ACCEPT-scoped

Independent critic (separate context) confirmed the fix and re-derived
everything itself (zero-callers grep, full suite, tsc, stash-isolated
baseline/candidate). Two disclosed, non-blocking caveats folded into the
gist: (1) @claude-flow/swarm is not currently a dependency of the shipped
@claude-flow/cli, so tonight's fix is real within the swarm package's own
UnifiedSwarmCoordinator/tests but has no reachable path through the actual
CLI today; (2) health still optimistically recovers +0.1/tick inside the
grace window even with zero real heartbeats (pre-existing, out-of-scope,
mirrors UnifiedSwarmCoordinator's own no-tick-recovery design). Also fixes
a cosmetic class-name typo in the source comment (UnifiedCoordinator ->
UnifiedSwarmCoordinator). Re-ran full suite (223/223) and tsc (clean) after
the comment edit; recomputed the witness stamp over final content.

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

* dream(swarm): update LEDGER.md for #3242/#3243

Records tonight's row plus verified GitHub state for the trailing nights
(MCP tools, not inferred) and the 2026-09-08 gap note (same
ledger-rows-only-reach-main-via-merge structural issue tracked since
2026-08-19).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-09 13:25:33 +00:00
rUv 6acc689150 dream(intelligence): #3220 gate EnhancedModelRouter's forwarded modelId on tier match (evaluated, ACCEPT-scoped) (#3221)
Merged after independent re-verification: 109/109 CI green, the earlier '168 failures' finding traced to an unbuilt-sibling-package local artifact (unrelated to changed files), and a subsequent CI flake confirmed unrelated via clean re-run. Overriding the PR's self-merge gate on explicit user (ruvnet) authorization.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013XaRQntabVwGT9SvnW8cKK
2026-09-07 10:57:05 -04:00
rUvandClaude 277c7bc03a dream(memory): #3168 wire embedding-cosine into SmartRetrieval's MMR step (evaluated, ACCEPT) (#3169)
* dream(memory): wire embedding-cosine into SmartRetrieval's MMR step (evaluated, ACCEPT)

smart-retrieval.ts's MMR diversity re-ranking used token-Jaccard text
overlap as its "similarity to already-selected" term, even though
memory-initializer.ts's searchEntries() already computes real
ONNX-embedding cosine similarity for the primary relevance score and
discards it before returning. 2025-2026 production practice (LangChain's
reference maximal_marginal_relevance, Qdrant's native Mmr query shipped
Sept 2025, Weaviate's MMR reranker shipped in 1.37) universally uses
embedding-cosine for this term; token overlap misses low-token-overlap
paraphrases embeddings correctly flag as near-duplicates.

Threads the embedding through: searchEntries()'s two live compute sites
(RaBitQ rerank, brute-force SQL) now return it instead of discarding it;
the two CLI/MCP bridge mappers (memory-tools.ts, commands/memory.ts) pass
it through; SearchCandidate gains an optional `embedding` field;
mmrRerank uses cosine when both candidates have one, falling back to
token-Jaccard otherwise (existing callers/tests without embeddings are
unaffected). controller-registry.ts's separate toCands()/applyMMR path
had the same gap for a different reason (embedding available on
r.entry.embedding but never copied) — fixed the same way.

Evaluated via deterministic Vitest, zero LLM calls, $0 cost. New
discriminating test: a low-token-overlap paraphrase (near-1.0 cosine to
the seed) vs. a genuinely different topic (near-0 cosine). Baseline
(git stash-isolated): picks the paraphrase second (Jaccard can't tell
"low overlap because paraphrase" from "low overlap because unrelated").
Candidate: correctly picks the different topic second. Full
@claude-flow/memory suite: 460/461 passing identically with/without the
candidate (1 pre-existing chmod-based environmental failure, same class
documented since 2026-08-15). tsc --noEmit: zero new errors (verified
@claude-flow/cli's 455 pre-existing errors, from unbuilt workspace
packages, are identical with and without this diff).

Darwin: skipped, scope mismatch (correctness/similarity-metric fix with
a discriminating unit test, not a continuous parameter with a
gold-labeled corpus).

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

* dream(memory): address review remediation — split CI, real benchmark, hardening

Response to ruvnet's REJECT review on #3169:

1. Split — dream-cycle-backlog-guard.yml moved out to #3205; this branch
   now carries only the MMR fix, rebased onto main (which already
   includes the merged #3203 CI fix).

2. Real benchmark (new src/mmr-benchmark.test.ts): 18-doc/6-topic labeled
   corpus (1 canonical + 2 low-token-overlap paraphrases per topic), run
   through the actual smartSearch/mmrRerank code, swept across mmrLambda
   in {0.3, 0.5, 0.7, 0.9} rather than one favorable value. Honest
   finding: at diversity-heavy lambda, candidate's recall/nDCG drop
   sharply vs. baseline, because cosine correctly suppresses same-topic
   near-duplicates that Jaccard fails to detect at all (and so
   "accidentally" keeps full recall). At smart-retrieval.ts's own default
   (lambda=0.7), recall@6/nDCG@6 are identical to baseline (1.000/0.777
   both) while topic-diversity improves 0.472->0.667 and ground-truth
   duplicate-rate drops 0.289->0.200. Reports latency (sub-ms both paths
   at this corpus size) and a memory-overhead estimate.

3. Malformed/dimension-mismatch: found and fixed a real bug while writing
   these cases. A NaN/Infinity-poisoned embedding component reached
   cosineSimilarity unguarded; the poisoned NaN score meant `mmr > bestMmr`
   was never true (NaN comparisons are always false in JS), which could
   silently break MMR's selection loop and under-fill results below the
   requested limit. Added isWellFormedEmbedding() so malformed/empty
   embeddings fall back to token-Jaccard, same as absent/mismatched ones.
   3 new cases (NaN/Infinity, empty array, explicit dimension-mismatch)
   plus a test mirroring the two real CLI/MCP output whitelists
   (memory-tools.ts:559-569, commands/memory.ts:633-639) to assert
   `embedding` cannot appear in either shape.

4. Determinism: new test runs the same input through smartSearch 5 times
   concurrently, asserts byte-identical result ordering every time,
   including a genuine same-embedding tie.

Full @claude-flow/memory suite: 465/466 (1 pre-existing, unrelated
environmental failure). tsc --noEmit: zero errors.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-05 11:57:23 -04:00
rUvandClaude 33a2c3ed07 dream(performance): #3183 wire real cold-start measurement, remove fabricated V2-vs-V3 benchmark (evaluated, ACCEPT-scoped) (#3184)
* docs(dream-cycle): backfill LEDGER rows for 2026-08-24..09-03

Ledger-append step silently failed again for 10 consecutive nights
(3rd occurrence of this failure class, first flagged 2026-08-19).
Verified via git ls-remote + GitHub MCP issue/PR search before
concluding this (all 10 nights ran to completion: real branch, issue,
and draft PR each) rather than inferring failure from a sparse table.
2026-08-20..08-23 is a separate, confirmed-genuine 4-night gap where
the pipeline did not run at all.

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

* dream(performance): wire real cold-start measurement, remove fabricated V2-vs-V3 benchmark (evaluated, ACCEPT-scoped)

cli-cold-start.bench.ts's own measureColdStart() (a real,
spawn-based process timer) was never called anywhere in the file.
Every reported number instead came from setTimeout() delays,
including a "V2 vs V3 Speedup: 5.00x" that was guaranteed by
construction (setTimeout(100) vs setTimeout(20), no code between
them) regardless of any real behavior.

- Export measureColdStart(), add runRealColdStartMeasurement() and
  CLI_BIN_PATH; wire the real spawn-based measurement into the suite.
- Remove the fabricated V2-vs-V3 comparison outright (no V2 binary
  remains to honestly compare against).
- Add a deterministic Vitest regression test (4 assertions); fails
  against baseline (functions not exported, fabricated pattern still
  present), passes against candidate — confirmed via git-stash
  isolation. Full @claude-flow/performance suite: 99/99 passing.
  tsc --noEmit: clean.
- Real measured number: node bin/cli.js --version, 5 runs, mean
  54.65ms (min 51.94 / max 57.92) — well under the 500ms target.
  Caveat disclosed in-code: --version is the one subcommand that
  succeeds without a built dist/ in this worktree; this is not a
  full-CLI cold-start measurement.
- Correct the two stale "Achieved" claims this fed in
  ADR-STATUS-SUMMARY.md's Performance Targets table (CLI Startup,
  and the already-known-false HNSW 150x-12,500x figure one row up).

Darwin: skipped, scope mismatch (dead-code-wiring fix, not a
tunable parameter). Flywheel: no signed bundle, deterministic
Vitest evidence retained instead. Follow-ups documented in tonight's
gist: same anti-pattern in agent-spawn/mcp-server-init/cli-warm-start
bench files (not touched, kept to one conceptual change); a Raft
election safety gap and a plugin supply-chain enforcement gap found
by tonight's scan roles (hive-mind, security) but out of scope for
the performance DEEP surface.

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

* docs(dream-cycle): append 2026-09-05 ledger row

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-05 11:38:56 -04:00
rUvandClaude b291ac4049 dream(intelligence): #3048 discounted Thompson sampling for model-router bandit (evaluated, ACCEPT-scoped) (#3049)
* dream(intelligence): discounted Thompson sampling for model-router bandit

Adds an opt-in `priorDecay` config field (default 1 = disabled, fully
backward compatible) to ModelRouter's Beta-Bernoulli bandit. When enabled,
every bucket/model's alpha/beta decays geometrically once per
recordOutcome() call before that round's reward is added (arXiv
2305.10718 discounted Thompson sampling), so accumulated routing history
from a long-running persisted state file no longer permanently dominates
the posterior after a real-world model-quality shift.

Benchmark (n=30 paired trials, seeded PRNG, identical stream baseline vs
candidate): non-stationary regime-shift recovery 26.5 -> 21.9 rounds
(-17.6%, t=7.24); post-shift correct-routing rate +1.3pp (t=6.10);
stationary-workload invariant held (delta +0.02pp, not a regression).
Receipt: v3/@claude-flow/cli/benchmarks/results/prior-decay-receipt.json.

Mirrors the epsilon-decay pattern q-learning-router.ts already applies to
its own exploration rate -- an internal-consistency fix, not an imported
pattern. Evaluation and adversarial critique in progress; this commit is
the checkpointed, test-passing candidate + its baseline/candidate receipt.

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

* dream(intelligence): #3048 fix adversarial-critique findings, add gist + ledger

Independent adversarial critique found and this commit fixes: a paired-t
statistics bug (population vs sample stddev inflated every t-value by
n/(n-1)), an unguarded priorDecay input (NaN/negative could silently poison
persisted .swarm/model-router-state.json forever, bypassing sampleBeta's
own defensive fallback), and a single-bucket benchmark blind spot (now
covers low + med complexity buckets -- the med bucket shows no significant
effect, disclosed rather than hidden).

Also adds the research gist and backfills 3 missing ledger rows for
2026-08-14/15/16 (real PRs/issues existed for those nights but the ledger
table wasn't updated) plus tonight's own row.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-21 11:21:27 -04:00
rUvandClaude 41efca8be3 dream(memory): #3056 hybridSearch reachable via explicit opt-in (evaluated, ACCEPT-scoped) (#3057)
* dream(memory): #3056 hybridSearch reachable via explicit opt-in without memoryService

The ADR-125 Phase 5 three-arm (dense+sparse+entity) RRF/MMR fusion
controller was fully built and tested but unreachable from any
production call site: its explicit-enable config override worked at
the isControllerEnabled() gate but the createController() factory
still unconditionally required a hand-built UnifiedMemoryService,
silently returning null otherwise. Falls back to the existing
this.backend when it type-guards as AgentDBAdapter-compatible,
reachable only via explicit controllers: { hybridSearch: true } --
default auto-enable behavior is unchanged.

New deterministic $0 benchmark quantifies the feature's actual
retrieval-quality effect for the first time (previously only
functional/unit tests existed): +0.267 aggregate recall@10, with a
disclosed, statistically significant regression on pure-paraphrase
queries where fusion noise dilutes an already-perfect dense signal.

Independent adversarial critic (fresh subagent): CONFIRMED-SAFE,
reproduced bit-for-bit. 75/75 tests passing in touched files, 458/459
in the full package (1 pre-existing environmental failure, unrelated).

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

* dream(memory): #3056 update ledger with 2026-08-14..18 nights + PR #3057

Reconstructs the v2 live-entries table from PR/issue history since each
night's own LEDGER.md edit lives only on its unmerged branch and never
reaches main (0% merge rate). Adds tonight's row (memory, hybridSearch
reachability fix, ACCEPT scoped, witness b28714fb...).

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-21 11:20:17 -04:00
rUvandClaude dcea520b4e dream(swarm): #3061 bound MessageBus retry attempts, fix unreachable message.failed (evaluated, ACCEPT) (#3062)
* dream(swarm): recover 5 missing live ledger rows (2026-08-14..18)

The v2 live-entries section of docs/dream-cycle/LEDGER.md was never
appended to for 5 consecutive nights despite each night running to
completion (branch + draft PR + issue verified to exist for all 5 via
git ls-remote and GitHub search before concluding this, per the ledger's
own anti-inference rule). Backfilled directly from the PRs/issues.

Root cause of the append gap not diagnosed tonight; flagged in the
gist/issue as a candidate finding for a future automation/meta scan.

* dream(swarm): bound MessageBus retry attempts, fix unreachable message.failed

Given a subscriber whose callback always throws, MessageBus.handleDeliveryError()
incremented the queue entry's attempts counter but addToQueue() always
constructed a fresh entry with attempts:0 on re-queue, discarding it. Retries
were unbounded (96-98 invocations / 0 failures observed in 500ms, git-stash-
verified pre-fix) instead of capped at config.retryAttempts, and the
message.failed branch was unreachable.

Fix: addToQueue() takes an optional existingAttempts parameter; the retry
path in handleDeliveryError() now threads entry.attempts through instead of
resetting it. Fresh-message call sites are unaffected (default 0).

Candidate evaluated: exactly 3 invocations / 2 retries / 1 failure, stable
thereafter. 220/220 tests passing (2 new, 0 regressions). Independently
re-verified by an adversarial critic (fresh session, no authoring context):
CONFIRMED-WITH-CAVEATS — fix and scope match the claim; flagged (and now
disclosed in-code) a separate pre-existing, unfixed broadcast-retry queue-key
bug this diff does not touch.

Full research/evaluation writeup: docs/dream-cycle/dream-gist-2026-08-19.md

* dream(swarm): append 2026-08-19 ledger row

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-21 11:19:24 -04:00
rUvandClaude 0e50fe7f57 dream(security): #3043 advisory scanner for untrusted settings.json hooks/allow-rules (evaluated, ACCEPT) (#3044)
* dream(security): #3043 advisory scanner for untrusted settings.json hooks/allow-rules carried forward by ruflo init/--upgrade

mergeSettingsForUpgrade() and writeSettings() both read a target
project's pre-existing .claude/settings.json and spread its hooks /
permissions.allow entries into the merged output verbatim — the same
trust shape as CVE-2025-59536 (settings.json hook payload achieving
command execution with no review step), reached via ruflo init's own
merge logic rather than Claude Code's loader. Neither of last night's
flagged CVEs (2025-59536, 2025-6514) applies to Ruflo's own hook
dispatch or OAuth client directly, but this distinct gap in the same
family was genuinely unaddressed.

Adds a static, advisory-only (non-blocking) scanner that inspects
hook commands and Bash allow-rules for known-dangerous patterns
before the merge and surfaces findings as CLI warnings. Merge/write
behavior itself is completely unchanged. Hardened after an
independent adversarial-critic pass found 6 concrete bypasses
(intermediate-pipe-stage downloads, two-step download+exec,
eval-wrapped base64, interpreter-mediated dangerous commands,
absolute-path-prefixed commands, whitespace-evasive allow rules) —
all fixed and pinned as a held-out regression set. Also fixes an
ANSI/control-character injection risk in the warning output itself,
self-identified during review.

87/87 relevant tests green (1 pre-existing environmental failure
elsewhere in the package, unrelated — unbuilt sibling package).

Dream Cycle 2026-08-16, security surface. Full research, evaluation
receipts, and adversarial critique: issue #3043 and
docs/dream-cycle/dream-gist-2026-08-16.md.

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

* docs(dream-cycle): update ledger — backfill 2026-08-14/2026-08-15, add 2026-08-16

2026-08-14 (swarm, REJECT) and 2026-08-15 (performance, REJECT) both had
fully-run pipelines whose live ledger rows never reached main (every
dream-cycle PR to date is unmerged, so branch-local ledger commits never
merge forward) — verified via git ls-remote / search_pull_requests before
backfilling, not assumed.

2026-08-16 (security, ACCEPT): advisory scanner for untrusted settings.json
hooks/allow-rules carried forward by ruflo init/--upgrade. Issue #3043,
PR #3044.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-21 10:39:22 -04:00
rUv abf26ab097 docs(dream-cycle): seed LEDGER.md with backfilled history + v2 routine update (#3018)
The Ruflo Nightly Dream Cycle cloud routine (trig_01HpEqAcEP7wzrxy3TzakrQ2)
was updated to v2: parallel research via the Task tool, claude-sonnet-5,
expanded toolset (TodoWrite/Skill/MultiEdit/BashOutput/KillBash), and a new
STEP 3.5 that attempts a real Flywheel evaluation (metaharness bench/evolve)
for harness-shaped findings instead of always stopping at a docs-only PR.

This file is the durable cross-night memory the new STEP 1 reads before
touching gh at all -- a fresh cloud checkout otherwise has zero continuity
beyond a gh issue list grep, which is what v1 relied on for 80 nights.

Backfilled from the full issue history: 4 shipped (5%), 1 rejected, 75
(94%) never touched, some >2.5 months stale. v2 uses this to bias toward
attempting evaluation over another research-only proposal when the
trailing merge rate is 0.
2026-08-13 10:20:46 -04:00
rUv 5f81112467 docs(adr): consolidate 49 stale dream-cycle proposals, renumber ADR-334..376 (#2871)
The dream-cycle bot has opened a research proposal draft PR nightly since
2026-05-29. None had ever been merged (tracked in #2324), so each night's
run guessed ADR numbers against a stale view of main and collided
repeatedly — ADR-147 alone was independently claimed by 4 different
proposals (#2304, #2310, #2317, plus a README-only PR #2278), and ADR-179
by another 4 (#2617, #2624, #2631, #2656, plus README-only #2642).

This consolidates the SOTA research reports and ADR proposal text from
all 49 open dream-cycle drafts into a single reviewable change:
- 43 ADR proposals renumbered sequentially into ADR-334 through ADR-376
  (first-opened-first-numbered), with self-referencing ADR-N mentions
  inside each file updated to match
- 4 branches that contained only a SOTA report with no ADR proposal
  (#2368, #2382, #2430, #2607) carried over as-is
- 2 branches that only added a README index row for an ADR file they
  didn't otherwise include (#2278 for ADR-147, #2642 for ADR-179) are
  superseded by the real ADR-147/179 claimants above and dropped
- v3/docs/adr/README.md gets one clean set of index rows instead of 43
  individually conflicting ones

All ADRs land as Proposed — none of this is an implementation decision,
just clearing 2 months of unreviewed nightly research out of PR limbo so
it can actually be read. The original 49 PRs are closed with a pointer
to this commit.

Closes #2224, #2242, #2249, #2255, #2266, #2278, #2304, #2310, #2317, #2333, #2344, #2363, #2368, #2379, #2382, #2394, #2402, #2420, #2430, #2436, #2457, #2463, #2472, #2479, #2486, #2496, #2511, #2527, #2537, #2560, #2577, #2598, #2607, #2617, #2624, #2631, #2642, #2656, #2665, #2702, #2716, #2728, #2740, #2753, #2761, #2764, #2769, #2779, #2793
2026-07-30 13:12:32 -04:00