Files
Dragan Spiridonov 4e011a81d0 chore(release): bump version to v3.9.27
- AbortSignal threading bounds ReasoningBank.initialize() (#478)
  prevents leaked init from runaway patterns.rvf writes
- CapturedExperienceBridge wires hook activity to domain plugins (#479)
  via kernel-side drain of captured_experiences
- Removes dead v3-qe-bridge.sh, two stale planning docs, five orphan
  workers in qe-workers.ts (subsumed by LearningConsolidationWorker)

Net: +430 / -2,090 lines

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 09:10:11 +00:00

5.7 KiB
Raw Permalink Blame History

v3.9.27 Release Notes

Release Date: 2026-05-14

Highlights

Two architectural fixes from downstream investigations against v3.9.26.

The first stops a session-start hook leak that filled a 420 GB disk in 29 minutes by appending unbounded data to patterns.rvf after a 10 s init timeout fired (#478). The fix threads AbortSignal through ReasoningBank.initialize() so the bootstrap actually cancels instead of running forever in the background.

The second wires the long-broken seam between hook-driven activity and the 13 domain plugins (#479). In default aqe init --auto deployments every plugin's subscribeToEvents() was listening to events that nothing emitted, so learning:pattern:* keys stayed at zero, qe_learning_optimize reported experiencesProcessed: 0, and the learning-consolidation worker logged "No learning patterns found" on every cycle. A new CapturedExperienceBridge runs inside QEKernelImpl and drains the shared captured_experiences SQLite table into the kernel's eventBus so domain plugins finally receive hook-driven activity.

Cleanup also removed ~1,640 lines of confirmed dead code (the bit-rotted v3-qe-bridge.sh, two stale planning docs, five orphan workers in src/optimization/qe-workers.ts whose functionality is fully covered by the live LearningConsolidationWorker).

Fixed

  • session-start hook could leak unbounded writes to patterns.rvf (#478) — getHooksSystem() bounded ReasoningBank.initialize() with Promise.race against a 10 s timeout. Promise.race does not cancel the loser, so when the timeout won the losing init promise kept running and continued to append to the RVF pattern store indefinitely. Downstream report on a vanilla install: 43.8 GB written in 29 minutes at 11–25 MB/s, disk filled to 100 %, SIGKILL required. Threaded an AbortSignal through ReasoningBank.initialize(), loadPretrainedPatterns(), and seedCrossDomainPatterns() — every awaited step now calls signal.throwIfAborted() before doing work, so the timeout actually cancels the bootstrap. The hook caller switched from Promise.race to AbortController + setTimeout. The hybrid backend init still uses race semantics (separate refactor) but now disposes the leaked backend once it eventually resolves so SQLite/WAL handles aren't held open in the background.

  • Hook-driven activity never reached the 13 domain plugins (#479) — the hook subprocess fires events on hookRegistry, the kernel-side domain plugins listen on eventBus, and the two systems were not bridged. Verified empty result on a clean v3.9.26 install: every domain plugin's subscribeToEvents() listened to events (test-execution.TestRunCompleted, coverage-analysis.CoverageGapDetected, learning.ExperienceCaptured, etc.) that no production code emitted. Hook subprocesses are short-lived npx aqe hooks ... processes with no kernel and no eventBus, so a hook-side subscriber would publish to nothing. The fix is a kernel-side drain: a new CapturedExperienceBridge polls the captured_experiences SQLite table every 5 s (already populated by hooks and MCP wrapped handlers), publishes each new row as learning.ExperienceCaptured plus a domain-specific event when the row's domain matches a known subscriber. Cursor stored in MemoryBackend so the bridge survives kernel restarts and never republishes. Wired from QEKernelImpl.initialize() / dispose() — every kernel-owning process (CLI, MCP server) automatically picks it up.

Removed

  • Dead v3-qe-bridge.sh script and its config reference — already declared dead in the v3.6.6 release notes; targeted a v3/dist/ path that no longer exists in the flat repo layout, so it silently no-op'd every invocation. Removed .claude/hooks/v3-qe-bridge.sh and the AQE_V3_HOOK_BRIDGE env var in .claude/settings.json.

  • Obsolete planning docs — docs/LEARNING_IMPROVEMENT_PLAN.md (443 lines) and docs/LEARNING_SYSTEMS_ANALYSIS.md (286 lines) were v3-alpha era artifacts that documented the broken bridge as the integration mechanism and referenced paths (v3/src/...) that haven't existed since the dist flatten. Bridge architecture is now documented by src/bridge/captured-experience-bridge.ts itself.

  • Five orphan workers in src/optimization/qe-workers.ts (949 LOC) and their tautological tests (407 LOC). PatternConsolidatorWorker, DreamConsolidatorWorker, CoverageGapScannerWorker, FlakyTestDetectorWorker, RoutingAccuracyMonitorWorker had zero internal callers and no documented use case. Their functionality is fully covered by the live LearningConsolidationWorker at src/workers/workers/learning-consolidation.ts:171 (pattern consolidation, dream cycles via runDreamCycle(), confidence decay, cross-domain identification, Phase 7 continuous learning loop) and FlakyDetectorWorker. Re-exports in src/optimization/index.ts cleaned up.

Changed

  • learning-consolidation worker error message now explains the bridge dependency instead of telling operators to "ensure the learning-optimization domain has stored pattern data" — that message predated the bridge fix and gaslighted users on fresh installs where no path produced patterns.

Net diff

+430 lines (bridge implementation, kernel wiring, abort-signal threading, focused unit tests covering 9 scenarios) versus −2,090 lines (deleted artifacts above), for a net −1,660 lines while making the platform's default learning loop functional under hook-driven workloads.

Credits

Both issues filed by @Jordi-Izquierdo-DDS with thorough source-level investigation, reproduction recipes, and measured production impact data.