[Dream Cycle 2026-09-01] security: maxToolCallsPerTurn was a session-lifetime cumulative cap, never resets (evaluated, ACCEPT) + intelligence,swarm scan
- Dominant language
- TypeScript
- Stars
- 72.7k
- Forks
- 8.6k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 85
Description
## 1. Tonight's Rotation
| Field | Value |
|---|---|
| Date | 2026-09-01 |
| Deep surface | **security** (SLOT=1) |
| Scan surfaces | intelligence, swarm |
| Session commit (start) | `29f048fc3b556f857cf2b126d2a84c19d2daa0d0` |
| Branch | `dream/2026-09-01-security` (stacked on unmerged `dream/2026-08-31-security`, PR #3139) |
## 2. Ledger Check
Read `docs/dream-cycle/LEDGER.md`. Directly verified via GitHub MCP (`gh` CLI unavailable in this environment — used `mcp__github__*` tools throughout, consistent with every recent night) two things the ledger table itself doesn't show:
- **The ledger table's live-append section is stale since 2026-08-19**, but the pipeline itself has run every night since — confirmed via `git ls-remote --heads origin "dream/*"` and `mcp__github__list_pull_requests`/`search_issues`, per STEP 1's anti-inference rule. Branches and PRs exist for 2026-08-24 through 2026-08-31 (#3086, #3094, #3103, #3110, #3119, #3123, #3130, #3139), all still **OPEN**, none merged.
- **A genuine 4-night gap exists**, distinct from the cosmetic ledger staleness: 2026-08-20 through 2026-08-23 have **no branch and no issue** — confirmed by direct `git ls-remote` and `search_issues` (not inferred). Root cause not diagnosed tonight (out of scope for STEP 1); flagged as a candidate finding for a future `automation`/meta-surface night, on top of the already-flagged ledger-append-silently-fails pattern from 2026-08-19's recovery note.
- **Zero of the last 14 dream-cycle candidate PRs have merged** (#3026 through #3139). Per STEP 1.1, this biases tonight toward a small, easily reviewable candidate — one file, one mechanism, one measurable improvement.
**Prior gist self-score (2026-08-31, security):** ~9/10 against the standing rubric (2/2 grade-A sourcing incl. direct MCP-spec/SEP-2567 reads, 2/2 for 6+ competitor rows, 2/2 for 3 executable recommendations, 2/2 valid witness, 1/1 under 1500 words, 1/1 novel — the MCP-governance-never-enforced finding was genuinely new; would be 10/10 but one of its own recommendations became the reason for tonight's follow-up).
**Duplicate-direction check (STEP 1.1):** this is a direct, human-reviewer-driven continuation of last night's own PR #3139 (review round 1 already fixed 3 of 5 findings; this candidate closes the remaining `maxToolCallsPerTurn` semantic-mismatch finding, explicitly flagged by both the module's own doc comment and last night's recommendation #1 as "the one real blocker to turning this on"). Not a rediscovery of an exhausted direction — it's follow-through on an open, live PR thread.
## 3. Deep Dive Findings
Full SOTA report: `docs/dream-cycle/dream-gist-2026-09-01.md` (committed on this branch).
Five parallel research roles (Deep Researcher, Scan A/intelligence, Scan B/swarm, Competitor Analyst, Ruflo Architecture Reviewer) converged independently on the same design: a **wall-clock sliding window**, not a turn-count reset (gameable — a chatty loop could cheaply re-arm its own budget) and not a token bucket (wrong shape for a hard per-window ceiling). Key primary-source finding: the MCP spec's 2026-07-28 revision (SEP-2567) is **actively removing the session concept from the protocol entirely** — read directly, not summarized — which bears on `sessionId`-keyed state as a design basis going forward, independent of tonight's fix. Cloudflare's public sliding-window-counter rate limiter (0.003% wrong-decision rate across 400M requests) and the two purpose-built MCP rate limiters found (FastMCP middleware, PolicyLayer) both corroborate wall-clock anchoring as the correct, established pattern.
## 4. Hypothesis
> Given a stdio MCP session under Ruflo's opt-in `RUFLO_MCP_ENFORCE_POLICY` governance, when `maxToolCallsPerTurn` enforcement changes from a permanent session-lifetime cumulative counter to a wall-clock sliding window (new `turnWindowMs` policy field, default 60000ms), then a session that pauses beyond the window has its call budget restored, relative to today's baseline (permanent lockout once exhausted, until process restart), subject to: (1) default/flag-unset behavior is byte-for-byte unchanged; (2) all existing policy-enforcer and MCP-related tests remain green; (3) fully deterministic coverage via an injectable clock, zero LLM cost; (4) no change required at the `mcp-server.ts` call site.
Frozen before implementation; not modified after seeing results.
## 5. Evaluation Receipt
**evaluated: accepted.** Real evaluator: `vitest run`, deterministic, $0, zero LLM calls.
- `__tests__/mcp-policy-enforcer.test.ts`: **30/30 passing** — 24 pre-existing tests pass unmodified (none crossed a window boundary), 6 new (5 direct `checkAndRecordCall` sliding-window cases + 1 `evaluateToolCall` fake-timer integration case using this package's existing `vi.useFakeTimers()` pattern).
- Broader regression sweep across all 11 MCP-related test files: **52/56 passing**. The 4 failures trace entirely to two unbuilt sibling packages in this fresh checkout — `@claude-flow/cli-core/dist` and `@claude-flow/neural/dist` (confirmed missing via direct `test -d` before any candidate code was touched) — the same disclosed environmental-gap class as 2026-08-17's and 2026-08-31's nights. `git diff --stat` confirms tonight's diff touches exactly 3 files; none of the failing tests import any of them.
- One-time environment fix (disclosed, not a candidate change): `pnpm install` had never been run for the v3 workspace in this fresh checkout; `@claude-flow/mcp` was unbuilt, breaking Vite's static transform for tests importing `mcp-server.ts` — built via plain `tsc` before running tests.
## 6. Darwin Results
Skipped — deliberately, not by default. This is a binary correctness fix (the counter resets on schedule, or it doesn't), same scope-mismatch class as 5 of the last 6 dream-cycle nights. One numeric parameter (`turnWindowMs`) is plausibly Darwin-eligible (evolve against a synthetic legitimate-burst-vs-abusive-loop corpus to tune the throttling/false-lockout tradeoff), but building that corpus tonight would expand scope well beyond the "small, reviewable" bias STEP 1.1 calls for given zero of the last 14 PRs have merged. Flagged as a legitimate future-night candidate.
## 7. Flywheel Evidence
No `.claude-flow/flywheel/` state exists in this repo; no signed `@metaharness/flywheel` bundle. Evidence retained as: the committed test file, this issue, and the gist. Classified: OBSERVATION (session-lifetime cap never resets, verified by direct code read) / MEASUREMENT (30/30 new-suite, 52/56 broader sweep, environmental failures isolated and confirmed pre-existing) / DECISION (ship sliding window, same opt-in/default-off gate as the parent feature) / REJECTION (none for this candidate).
## 8. Reward Hack Check
Manual checklist (no generic reward-hack CLI reachable — `@metaharness/weight-eft` is a LoRA-distillation tool, not a diff/benchmark scanner, consistent with every prior night). No existing test weakened — diffed the full test file; every change either adds a block or *strengthens* an assertion. No benchmark/gold data exists to weaken (confirmed, not just asserted — grepped for any corpus referencing this module). No cherry-picked cases (independent critic specifically flagged and closed one coverage gap — see below). No seed manipulation (fully deterministic, explicit timestamps or fake timers throughout). $0 cost confirmed (zero LLM calls in candidate or tests).
## 9. Security Review
Independent adversarial-critic subagent (no authoring context, re-derived correctness itself rather than trusting my framing) verdict: **CONFIRMED-WITH-CAVEATS**. Both findings were real but minor, and both were fixed before this report was finalized:
1. **Untested exact boundary** (`now === cutoff`): tests covered `now-1` (denied) and `now+1` (allowed) but not the exact cutoff. Fixed: added a pinned test confirming the window reopens exactly on the boundary (strict `>`, not `>=`) — this favors the caller, not an attacker, but needed an explicit pin so a future refactor can't silently flip the comparison unnoticed.
2. **Audit-log timestamp cosmetic desync**: `evaluateToolCall`'s audit entry stamped real wall-clock `Date.now()` instead of the injected `now` parameter — harmless in production (both default to `Date.now()`) but could desync from the enforcement decision under a synthetic test clock. Fixed: now derives from `new Date(now).toISOString()`.
Critic also independently confirmed: default (flag-unset) behavior is byte-for-byte unchanged (verified by reading the `mcp-server.ts` call site directly, not trusting tests); the new `Map` does not introduce a meaningfully worse resource-exhaustion risk than the old design at production scale (one live session per stdio process, ≤200 timestamps ≈1.6KB); latency impact is immaterial (O(n) filter, n≤200, sub-microsecond); and — the sharpest question — a wall-clock sliding window does **not** introduce a new gaming vector relative to the old (broken) design: the "restart the process to reset" bypass already existed identically before this diff, since `sessionState` was never persisted either way. Independently re-ran the test suite and confirmed 29/29 (30/30 after the two fixes above) rather than trusting the claim.
## 10. Scan Findings: intelligence
**Finding (Grade B):** arXiv:2603.18596 "Elastic Weight Consolidation Done Right for Continual Learning" (Liu & Chang, CVPR 2026, code released) identifies that classic EWC's Fisher-Information-Matrix computation causes gradient vanishing and over-constrains irrelevant parameters; proposes a one-line "Logits Reversal" fix. **Does not transplant directly to Ruflo**: direct inspection of `v3/@claude-flow/cli/src/memory/ewc-consolidation.ts` confirms Ruflo's "EWC++" already documents that its `F_i` is a heuristic embedding-magnitude proxy, not a true gradient-based FIM — there's no backprop signal in this pattern-memory context for Logits Reversal to act on. Concrete, code-verified gap between what 2026 literature refines (true FIM) and what Ruflo actually computes; worth a doc callout, not a code fix. No material change found on MoE-gate-specific literature beyond what's already covered.
## 11. Scan Findings: swarm
**Finding 1 (Grade B):** "Resilient Consensus in Agentic AI" (arXiv:2606.15024, June 2026) — a controlled experiment showing prompted LLM agents fail to reach agreement that classical Byzantine-resilient-consensus theory guarantees is achievable, stable across temperature/reasoning-horizon; wrapping agents with an explicit classical resilient-consensus *filter* layer recovers agreement. Directly relevant to Ruflo's `byzantine-coordinator` — evidence that raw agent-reported consensus, unfiltered, is a known failure mode independent of the already-flagged `weightedConsensus()` gap.
**Finding 2 (Grade B):** "Predictive Maps of Multi-Agent Reasoning" (arXiv:2605.11453, May 2026) — a pre-inference spectral diagnostic (successor representation of the communication operator) for scoring topology choice (chain/star/mesh) before running it, validated on a 12-step state-tracking task. Distinct from previously-covered topology-*generation* work (SwarmAgentic PSO) — this is a cheap topology-*scoring* primitive.
Plus independent corroboration (WMAC 2026, Ojha et al., GAT-based trust-weighted MARL consensus) further strengthening — now triple-corroborated — the case for wiring `QueenCoordinator.weightedConsensus()`'s already-computed trust weights into the actual vote tally on a future swarm-surface night.
## 12. Competitors Reviewed
LangGraph, OpenAI Agents SDK, Google ADK, CrewAI, AutoGen/AG2, Anthropic's MCP reference SDK, FastMCP (community MCP middleware), PolicyLayer (dedicated MCP firewall) — full sourced table with confidence grades in the gist. Synthesis: MCP itself has no rate-limiting concept by protocol design; among agent frameworks, the "session-lifetime cumulative counter, never resets" pattern Ruflo shipped last night is **not a Ruflo-only mistake** — it's literally Google ADK's shipped default (`RunConfig.max_llm_calls`) — but that doesn't make it good practice. The two purpose-built MCP rate limiters that solved this well (FastMCP, PolicyLayer) both anchor resets to wall-clock time, which is exactly tonight's fix.
## 13. Gist
`docs/dream-cycle/dream-gist-2026-09-01.md` (committed on this branch; no gist-creation tool available in this session — no `gh` CLI, no MCP gist tool — consistent with every dream-cycle night since 2026-08-14).
## 14. Witness
| Field | Value |
|---|---|
| Session commit | `29f048fc3b556f857cf2b126d2a84c19d2daa0d0` |
| Report SHA-256 (pre-witness content) | `75fa8021ab6b9890ab5202217c7bf343c97ad18a9c4e313c85d09eda3385f990` |
| Witness stamp | `7d93a48202ac2ee6c8568fd6f038b043f96deb624da06d59ae38a77310de91f8` |
Verifier procedure: take the gist's content with the Witness table's two value cells blanked back out, SHA-256 it, concatenate with the session commit above, SHA-256 again — result must equal the witness stamp.
## 15. Recommendation
1. **Merge #3139 and this follow-up together** (or squash) — tonight's fix is meaningless without last night's enforcer; both are small, reviewable, and this one directly closes the human reviewer's own round-1 feedback on #3139.
2. **A future night should prototype Darwin-tuning `turnWindowMs`** against a synthetic legitimate-burst-vs-abusive-loop corpus now that a real reset mechanism exists to tune against.
3. **Thread `QueenCoordinator.weightedConsensus()` trust weights into the actual vote tally** on the next swarm-surface night — now triple-corroborated (2026-08-19 original, DySCo on 2026-08-31, and tonight's independent findings).
4. **A future `automation`/meta-surface night should investigate the 2026-08-20 through 2026-08-23 pipeline gap** (4 nights with no branch or issue at all, distinct from the already-flagged ledger-append-silently-fails pattern) — direct evidence, not inferred, that something beyond cosmetic ledger staleness failed those nights.
Contributor guide
Research direction
Start with __tests__/mcp-policy-enforcer.test.ts and the mcp-server.ts call site mentioned in the issue. Run the focused Vitest suite first, then confirm the maxToolCallsPerTurn behavior across the stated window boundary; done means the deterministic sliding-window cases pass without changing default flag-unset behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100