- 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>
5.7 KiB
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-starthook could leak unbounded writes topatterns.rvf(#478) —getHooksSystem()boundedReasoningBank.initialize()withPromise.raceagainst a 10 s timeout.Promise.racedoes 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 %,SIGKILLrequired. Threaded anAbortSignalthroughReasoningBank.initialize(),loadPretrainedPatterns(), andseedCrossDomainPatterns()— every awaited step now callssignal.throwIfAborted()before doing work, so the timeout actually cancels the bootstrap. The hook caller switched fromPromise.racetoAbortController+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 oneventBus, and the two systems were not bridged. Verified empty result on a clean v3.9.26 install: every domain plugin'ssubscribeToEvents()listened to events (test-execution.TestRunCompleted,coverage-analysis.CoverageGapDetected,learning.ExperienceCaptured, etc.) that no production code emitted. Hook subprocesses are short-livednpx 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 newCapturedExperienceBridgepolls thecaptured_experiencesSQLite table every 5 s (already populated by hooks and MCP wrapped handlers), publishes each new row aslearning.ExperienceCapturedplus a domain-specific event when the row'sdomainmatches a known subscriber. Cursor stored inMemoryBackendso the bridge survives kernel restarts and never republishes. Wired fromQEKernelImpl.initialize()/dispose()— every kernel-owning process (CLI, MCP server) automatically picks it up.
Removed
-
Dead
v3-qe-bridge.shscript and its config reference — already declared dead in the v3.6.6 release notes; targeted av3/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.shand theAQE_V3_HOOK_BRIDGEenv var in.claude/settings.json. -
Obsolete planning docs —
docs/LEARNING_IMPROVEMENT_PLAN.md(443 lines) anddocs/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 bysrc/bridge/captured-experience-bridge.tsitself. -
Five orphan workers in
src/optimization/qe-workers.ts(949 LOC) and their tautological tests (407 LOC).PatternConsolidatorWorker,DreamConsolidatorWorker,CoverageGapScannerWorker,FlakyTestDetectorWorker,RoutingAccuracyMonitorWorkerhad zero internal callers and no documented use case. Their functionality is fully covered by the liveLearningConsolidationWorkeratsrc/workers/workers/learning-consolidation.ts:171(pattern consolidation, dream cycles viarunDreamCycle(), confidence decay, cross-domain identification, Phase 7 continuous learning loop) andFlakyDetectorWorker. Re-exports insrc/optimization/index.tscleaned up.
Changed
learning-consolidationworker 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.