Free-tier local test generation (opt-in) — cheap-first on local/free models
with a repair loop, auto-escalation to paid tiers, and self-learning routing
feedback. Plus #541 dependency fixes (ruvllm optional deps + hono security).
Version synced across all product manifests: package.json, fleetVersion in
both .claude/ and assets/ skills-manifests, and .claude-plugin/plugin.json
(the latter two had drifted at 3.10.4).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-audit of the free-tier lane found two gaps:
- Multi-file: the free-tier path generated for sourceFiles[0] only, silently
skipping the rest AND the paid path. Now it engages only for single-file
requests; multi-file falls back to the normal path so every file is covered.
(+1 regression test.)
- Exports/docs mismatch: the guide + README showed
`import ... from 'agentic-qe/routing/free-tier'`, but package.json had no
./routing export — the import would fail for npm consumers. Added the
./routing/free-tier subpath export.
Verified: project `tsc --noEmit` clean; 236 routing/coordinator/plugin tests +
18 routing-feedback tests green; no sibling breakage from the generic tracker.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MCP server reliability + database-free completeness (community issues from
@nagoodman): in-process `agentic-qe mcp` (#528), memory_delete stale-cache fix
(#535), db-free propagation to all editor MCP configs (#533), and the opt-in
--no-claude exclusive install (#532). Plus the js-yaml dev bump (#540) and the
devil's-advocate follow-up fixes (routing/merge/startup + CI guard).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #528 and #535 integration tests (tests/integration/mcp, gated on
describe.skipIf(!BUILT)) never executed in CI — a false green:
- the mcp-integration-tests job ran `npm ci` but no `npm run build`, so the
dist bundles were absent and both tests silently skipped;
- the step was `continue-on-error: true`, so even a real failure passed;
- neither test was in the release gate's test:integration:fast list.
Fixes:
- mcp-tools-test.yml: add `npm run build` before test:mcp:integration and drop
continue-on-error so the job is a real gate (the exit-124 hang tolerance
stays for the known vitest-hang flake).
- both tests: skip only for LOCAL unbuilt checkouts (`!BUILT && !process.env.CI`)
— in CI a missing build now fails loudly instead of skipping. Verified:
CI=1 with the bundle removed fails the suite instead of reporting green.
- package.json: add both tests to test:integration:fast so they also run on the
release gate (npm-publish.yml), which builds first.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0.1.5's SONA learning engine had a bug where reward feedback produced zero
weight changes (fixed upstream in 0.1.7, published 2026-06-11). AQE drives that
exact path via the trajectory API in sona-wrapper.ts
(beginTrajectory/addTrajectoryStep/endTrajectory + forceLearn), so reward
signals into SONA were effectively inert.
Verified on linux-arm64:
- 0.1.7 linux-arm64-gnu binary is a Linux ELF; native module loads (SonaEngine)
- all 12 native methods the wrapper calls exist in 0.1.7 (API compatible)
- functional smoke test: forceLearn now reports "20 trajectories -> 20 patterns",
patterns_learned 0 -> 20 (was 0 in 0.1.5 — fix confirmed)
- tsc --noEmit: 0 errors; 206 SONA unit tests pass
- better-sqlite3 native fix from prior commit intact (experience capture unaffected)
Note: 0.1.7 restructured platform binaries into optional per-platform packages
(hence the lockfile churn). Install resolves the correct binary per platform;
do not rely on a host-side install in the bind-mounted container.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI npm ci failed with ERESOLVE — v3.2.0 peers @typescript-eslint/eslint-plugin
6-7, but the project is on v8. v4.x peers ^8 (and keeps ESLint 8 support), so it
resolves cleanly. Worked locally only because it was installed with
--legacy-peer-deps; npm ci is strict.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code-intelligence TS/JS via bundled tree-sitter WASM (no typescript dep, #511) +
fix for MCP domain tools hanging on fresh install. Also fixes the release skill's
repo path (agentic-qe-new -> agentic-qe).
Per request: aqe init now installs the cross-platform Node hook shim into each
user project and routes hooks through it (instead of `npx agentic-qe hooks`).
- package.json: add `.claude/hooks` to `files` so aqe-hook.cjs ships in the npm
tarball (verified via `npm pack --dry-run`).
- 07-hooks.ts: new installHookShim() copies aqe-hook.cjs into the project's
.claude/hooks/ (source: node_modules/agentic-qe, then the package's own copy
resolved relative to the compiled module — works for npx too).
- 07-hooks.ts + init-wizard-hooks.ts: generated hooks now run
`node "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/aqe-hook.cjs" <cmd> ...`
(README/help examples left as `npx agentic-qe hooks` for manual use).
- aqe-hook.cjs: added an npx fallback (`npx -y --prefer-offline agentic-qe`)
so npx-only installs with no project-local bundle still work; disable with
AQE_HOOK_NPX=0 (tests use this for determinism). Header/scope updated (now a
shipped, init-copied file, not repo-internal).
Migration: isAqeHookEntry already matches the new `aqe-hook.cjs` command (via
the `\baqe\b` pattern) AND the old `npx agentic-qe hooks` form, so re-running
`aqe init` replaces a user's existing hooks with the shim form — no duplicates.
Verified end-to-end (real `aqe init --auto` in a temp project):
- aqe-hook.cjs copied into .claude/hooks/ ("Installed aqe-hook.cjs (copied)")
- all 11 generated hooks use `node .../aqe-hook.cjs <cmd>` (0 npx commands)
- post-task retains the #508 fix (--agent/--success true/--description)
- isAqeHookEntry matches new+old forms, not unrelated user hooks
- shim 7/7, settings-merge 17/17, task-hooks 5/5 tests pass; typecheck clean
Ports ruflo's 'smoke.sh as a plugin contract' discipline. AQE already ships
the marketplace.json + a lean auto-discovery plugin (plugins/agentic-qe-fleet:
11 agents, 9 commands, 9 skills, lean plugin.json), but had no machine-checkable
contract — so silent drift could ship a broken bundle.
plugins/agentic-qe-fleet/scripts/smoke.sh (npm run plugin:smoke) asserts:
- plugin.json valid JSON, name == agentic-qe-fleet, has a version;
- plugin.json does NOT declare skills/commands/agents arrays (Claude Code
auto-discovers them — declaring them is an error, per ruflo);
- marketplace.json indexes the plugin at ./plugins/agentic-qe-fleet;
- exact counts (11 agents / 9 commands / 9 skills), each with name+description
frontmatter / SKILL.md (bump the constants deliberately on change);
- README present; top-level plugin.json registers the agentic-qe MCP server.
Exit 0 = contract holds, 1 = any violation.
Verified: passes 10/10 checks (exit 0), and correctly FAILS (exit 1) when a
skill is removed ('skills: 8 (expected 9)').
Scope note: AQE ships ONE bundle today. Splitting the 93 QE skills into multiple
lean subset bundles (aqe-security, aqe-browser, ...) is a larger restructure of
shipped artifacts — deferred as a follow-up (needs a distribution decision); the
skills-manifest.json already has the category data to drive it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports ruflo ADR-077: seed the pattern store from the repo's OWN git history
(commits = success trajectories) through the SAME live-learning code path, so
a fresh project starts with a non-empty, project-specific pattern store instead
of only the generic PRETRAINED_PATTERNS.
scripts/pretrain-from-history.ts (npm run pretrain:history):
- git log --no-merges -> per commit: domain = deriveTaskType(subject),
success = subject !startsWith 'revert' (a revert is a failure signal);
- records each via persistTaskOutcome (the live captured_experiences +
experience_applications + Q-update path, honoring AQE_PROJECT_ROOT);
- then consolidateExperiencesToPatterns() distills them into qe_patterns.
- flags: --limit N (default 500), --dry-run (classify+histogram, write nothing),
--verbose. Extracted a pure classifyCommit() helper (19 unit tests).
Correctness fix found during verification (in the script, not prod): a brand-new
store only has core schema, so persistTaskOutcome failed with
'no such table: experience_applications'. The script now calls the canonical
ensureAllBrainTables() + initializeExperienceCapture() before recording — the
same tables production creates lazily.
Verified against a THROWAWAY AQE_PROJECT_ROOT temp store (data protection):
--limit 150 -> captured_experiences 0->150, qe_patterns 0->4, exit 0;
--dry-run -> nothing recorded (captured_experiences stays 0);
real .agentic-qe/*.rvf byte-identical (sha256) before/after; 19 tests pass.
Side-finding: AQE's real embedding (ONNX) costs ~2.3s/commit here vs ruflo's
~3ms/trajectory, so bootstrapping 500 commits takes minutes — logged as a perf
follow-up (embedding backend / batching).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports ruflo's perf-M4 (sign-random-projection + Hamming popcount). Adds
src/shared/utils/rabitq.ts: signSignature (384-bit packed into 12 Uint32
words, 48 bytes), hammingDistance (SWAR popcount), hammingSimilarity, and
topKBySignature (Hamming prefilter gated at N>=100 + exact-cosine rerank of a
recall-aware pool, so output equals exact topK when the true top-k fall in the
pool). 16 tests + scripts/benchmark-rabitq.ts (npm run benchmark:rabitq).
HONEST FINDING (verified, does NOT match ruflo's optimistic 2.7x/10.9x):
N=1000: speedup 1.31x, recall@10 100%, index 1.46MB -> 47KB (32x smaller)
N=5000: speedup 1.18x, recall@10 99.9%, 7.32MB -> 234KB (32x smaller)
The 32x INDEX-MEMORY reduction is real and unconditional. The SPEEDUP is only
~1.2-1.5x in JS, not ruflo's figure: a 1-bit sign signature in 384-dim is
coarse, so preserving recall@10 >= 0.95 needs a large exact-rerank pool
(~40-55% of N), which eats most of the prefilter win. ruflo's big win came
from replacing a LINEAR scan; AQE's main search is already native HNSW
(sublinear), so that win doesn't transfer. Tests pin this tradeoff (recall==1.0
with a sufficient pool; small pool sacrifices recall) so it can't be
mis-sold later.
NOT INTEGRATED — no zero-regression consumer exists:
- unified-memory-hnsw search() IS the ranking (no separate exact rerank to
prefilter), so Hamming-prefiltering its beam would drop true neighbors;
- coherence-gate-energy O(N^2) SUM and k-means clustering are numerically
sensitive (Hamming would change results).
Committed as a tested, benchmarked, ready-to-use utility (real memory lever for
patterns.rvf and a future prefilter->exact-rerank consumer), not wired into any
production path. No production code or .agentic-qe stores touched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports ruflo's #1874 discipline. Replaces the FAKE mcp:validate theater
(echo 'All tools registered' && exit 0) with a real smoke that boots the
actual MCP server (tsx src/mcp/entry.ts) over stdio and validates the
initialize + tools/list handshake against the MCP SPEC, not the code:
- protocolVersion is a YYYY-MM-DD string (the core ruflo #1874 guard — an
object here is what Claude Code's Zod rejects)
- capabilities is an object; serverInfo.name/version are non-empty strings
- tools/list returns a non-empty array, each entry name + object inputSchema
scripts/audit-mcp-tool-parity.mjs is the AQE-equivalent of ruflo's CLI<->MCP
parity audit (the CLI has no callMCPTool('name') string pattern, so the
meaningful surface is advertisement<->handler parity). Drives the advertised
set from a live tools/list, diffs a monotone baseline
(verification/mcp-tool-parity-baseline.json, 86 tools), fails only on NEW
discrepancies (removed tool = regression), and probes that unknown-tool
tools/call is rejected. --update-baseline to re-baseline.
Both scripts spawn the server against an isolated AQE_PROJECT_ROOT temp dir
(data protection: real .agentic-qe/*.rvf proven byte-identical before/after)
and kill the whole detached process group on exit (no leaked servers).
Verified: npm run mcp:validate -> PASS (protocolVersion 2025-11-25, 86 tools);
mcp:parity -> PASS (0 removed, 0 added). Both exit 0, real stores untouched.
Side-finding (pre-existing, not fixed here): handleToolsCall throws a plain
object for unknown tools, which escapes the request-handler safety net as
'Internal error: [object Object]' instead of a proper JSON-RPC -32601. Logged
for a dedicated fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports ruflo's benchmark-self-learning.mjs discipline (the 'reports success
but persists nothing' detector) to AQE. Proves the learning stores actually
persist what they claim, that stat aggregators agree with the underlying
index, that nothing writes accidentally, and that data survives restart.
Sections (each isolated in a temp dir, each gating):
A store persistence — N creates => totalPatterns delta == N
B outcome learning — N outcomes => learningOutcomes delta == N, successRate matches fed ratio
C negative control — read-only ops => 0 delta (no accidental writes)
D restart survival — dispose + reopen on same temp path => counts persist
E consistency — RvfPatternStore.getStats == adapter.totalVectors == bank.totalPatterns
F audit-real — copies real stores read-only, checks banner numbers round-trip
Data protection (CLAUDE.md): synthetic mode uses fresh temp dirs; audit-real
copies stores and opens only copies. Verified real .rvf stores byte-identical
(mtime+size+sha256) before/after a run.
Audit-real finding on the live store: banner numbers corroborated
(72.5% success, 39.7% confidence, 2131 routings) BUT RVF vector count (338)
!= SQLite qe_patterns rows (345), a ~7-pattern index/table drift the banner
hides — exactly the divergence this harness exists to surface (reported as a
diagnostic note, non-gating). Synthetic sections A-E pass; exit 1 on failure.
npm run benchmark:self-learning
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the ADR-043 LLM router into the production swarm path: kernel
constructs HybridRouter singleton during initialize(), threads it
through all 11 LLM-enhanced domains and MCP standalone tools. Adds
persistent aqe llm config --set, Gemini GOOGLE_API_KEY alias, 2 real
fallback-chain bug fixes (provider-discriminatory hardcoded list +
non-retryable short-circuit), and a qe-devils-advocate audit hardening
sweep closing 10 findings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the qe-reasoning-bank split: the original 622-line file ran
~43 tests in a single fork, most of which spun up a full
AQELearningEngine (transformer + HNSW + WASM coherence) via
beforeEach. Distributing across three sequential forks (pool=forks,
maxForks=1, fileParallelism=false) caps per-fork heap.
- _aqe-engine-test-helpers.ts (NEW, not a test file)
Shared createMockMemoryBackend() and createMockEventBus() factories
pulled out of the original so the splits don't duplicate. Underscore
prefix keeps it out of vitest's test-file include glob.
- aqe-learning-engine-factory.test.ts (NEW, 4 tests, no init)
Factory Functions + DEFAULT_ENGINE_CONFIG. Tests only call the
constructor — no engine.initialize() — so transformer / HNSW /
WASM aren't loaded. Safe to include in test:unit:fast.
- aqe-learning-engine-patterns.test.ts (NEW, 15 tests, full engine)
The three heaviest sub-describes: Pattern Learning, Task Tracking,
Experience Capture Integration. Each test runs a full engine init.
Excluded from test:unit:fast until step 3's dispose hooks are
proven in CI.
- aqe-learning-engine.test.ts (SLIMMED, ~21 tests, full engine)
Init / Status / Task Routing / Model Routing / Codebase Analysis /
Guidance / Dispose. Header comment updated to reference the two
companion files. Inline mock factories replaced with imports from
the shared helper.
Coverage preserved: ~43 tests still run under test:ci, across three
forks instead of one.
Issue: #448
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original 1019-line file ran 58 tests in a single vitest fork, each
spinning up a full QEReasoningBank (transformer embeddings + HNSW + WASM
coherence). Cumulative per-test memory growth blew past the heap ceiling
and the publish workflow timed out on multiple v3.9.x releases.
This commit extracts the file into three forks so the heap pressure is
distributed across three sequential processes (vitest config:
pool=forks, maxForks=1, fileParallelism=false):
- qe-reasoning-bank-utilities.test.ts (NEW, 29 tests, no bank)
Pure-function tests for qe-patterns + qe-guidance. Module-graph weight
is negligible — runs in ~10ms with no transformer load. Safe to
include in test:unit:fast.
- qe-reasoning-bank-feedback-loop.test.ts (NEW, 9 tests, full bank)
recordOutcome / qe_pattern_usage feedback-loop tests with vi.doMock
churn over '../../../src/kernel/unified-memory.js'. Carries the
heaviest mocking surface, so isolated to its own fork.
- qe-reasoning-bank.test.ts (SLIMMED, 20 tests, full bank)
Init / Pattern Storage / Task Routing / Learning Outcomes /
Guidance Generation / Statistics / Embedding. Header comment
updated to reference the two companion files.
Both heavy files (-feedback-loop and the slim core) remain excluded from
test:unit:fast for now. Re-enabling them is acceptance #2 of the issue
and requires step 3 of the proposed solution (lazy / disposable hooks on
real-embeddings.ts and coherence-service.ts) — local repro in a 16GB
Codespace shows even the slim 9-test fork still OOMs at 6GB heap,
indicating per-test cumulative growth that file-splitting alone doesn't
cure. The split is preparatory and reduces the leak slope from
58×Δ to max(20,9,0)×Δ per fork, which should give CI headroom and
clear the way for the dispose-hooks fix in step 3.
Issue: #448
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The HnswAdapter class is shipped in dist/kernel/hnsw-adapter.js but the
subpath was not registered in the package.json exports map. In Node.js
ESM strict mode, unlisted subpaths throw ERR_PACKAGE_PATH_NOT_EXPORTED,
making direct imports like:
import { HnswAdapter } from 'agentic-qe/kernel/hnsw-adapter'
fail at runtime even though the compiled file is present.
Fix: add the ./kernel/hnsw-adapter entry alongside the existing
./kernel barrel export.
Stops unbounded growth of patterns.rvf / brain.rvf.
- #495: AbortSignal in HybridMemoryBackend.initialize() so a 5s
createHybridBackendWithTimeout abort actually cancels the work
instead of leaking a 14-min runaway init (~20 GB / 12 MB/s leak
observed in the field). UnifiedMemoryManager.initialize() also
accepts {signal} with throwIfAborted() at each await seam.
- Post-dream compaction in DreamScheduler — threshold-gated compact()
against patterns.rvf and brain.rvf so append-only growth has a
steady-state janitor.
- Boot-time size guard in getSharedRvfAdapter() for one-shot recovery
of installations already in the bad state.
- Bounded SQLite→RVF backfill (top-1000 by last_used_at) so
`: > patterns.rvf` for disk recovery doesn't trigger an unbounded
replay (the "regrew to 59 GB" pathology).
- RvfDualWriter.compact() for brain.rvf parity.
Three operator env knobs added (no rebuild needed):
- AQE_RVF_SIZE_GUARD_BYTES (default 256 MB)
- AQE_RVF_DEAD_RATIO_THRESHOLD (default 0.30)
- AQE_RVF_BACKFILL_LIMIT (default 1000)
29 new unit tests. Performance gate 15/15 pass. test:ci 4035 pass
(3 pre-existing failures, verified identical on main).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xenova/transformers v2.17.2 (last publish 2024-05-29) pins
onnxruntime-web@1.14.0, which pulls onnx-proto → protobufjs <=7.5.5.
That chain has 8 GHSA advisories including a critical arbitrary-code-
execution one (GHSA-xq3m-2v4x-88gg). Our top-level `overrides` block
forced protobufjs@^7.5.6 in our own tree, hiding the vulns from
`npm audit` in this repo — but `overrides` are root-only by design and
do not propagate to downstream consumers. End users running
`npm install agentic-qe` were getting 5 vulns (4 high, 1 critical).
@huggingface/transformers@4.2.0 is the official maintained successor
(same project, renamed). It pulls onnxruntime-web@1.26 which depends
on protobufjs@^7.2.4 directly (no onnx-proto), so the version range
resolves cleanly to the patched line.
API changes handled:
- pipeline()/Tensor: drop-in compatible, just the import path changes
- `quantized: bool` → `dtype: DataType` (mapped from our QuantizationType
enum: 'none'→'fp32', 'fp16'→'fp16', 'int8'→'int8', 'binary'→'q8';
binary stays a post-process step downstream)
- progress_callback signature: ProgressInfo is now a discriminated union;
`progress` only exists on the "progress" variant — narrowed accordingly
Also added onnxruntime-node and onnxruntime-web to the CLI and MCP
bundle externals lists. @huggingface/transformers ships both runtimes
(node for Node.js, web as fallback); esbuild can't bundle the
native .node binary so it must remain external.
End-user verification (npm pack + clean install in /tmp/aqe-canary):
- 183 packages (was 180 pre-migration; same order of magnitude)
- 0 vulnerabilities (was 5: 4 high, 1 critical)
- aqe init --auto runs in 93 ms; all 13 phases pass; optional-peers
hint renders correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the previous @claude-flow/guidance treatment: moves
@claude-flow/browser from optionalDependencies to peerDependencies +
peerDependenciesMeta{optional:true}.
Why this is the high-leverage change in this cleanup pass:
@claude-flow/browser peers on @claude-flow/cli@^3.0.0-alpha.140, which
in turn pulls @claude-flow/embeddings whose peers disagree with cli's
own optional deps — that mismatch is the entire source of the ERESOLVE
warnings users see during `npm install agentic-qe`. With browser moved
to an optional peer, that whole transitive chain is no longer pulled by
default.
Tree shrinkage: 1207 → 725 packages (482 transitives removed,
~7,924 fewer lines in package-lock.json). Includes @claude-flow/cli,
@claude-flow/embeddings, agentic-flow, plus their long tail of
deprecated transitives (koa-router@14, prebuild-install@7, uuid@9,
node-domexception@1) — all of the deprecation warnings called out at
the start of this dep-cleanup pass.
Zero runtime risk: grep confirms zero `import`/`require` of
@claude-flow/browser anywhere in src/, tests/, or scripts/. The package
was only ever a marker for the separately-run @claude-flow/browser MCP
server; src/domains/visual-accessibility/services/browser-security-scanner.ts
talks to it over the MCP protocol, not via a Node import.
Verified: `npm run build` passes, `npm audit --audit-level=high
--omit=dev` clean, `node dist/cli/bundle.js --version` runs. `npm ls
@claude-flow/cli` is now empty.
Users who want the browser MCP server can still install it explicitly:
`npm install -g @claude-flow/browser@3.0.0-alpha.1`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves @claude-flow/guidance from optionalDependencies to:
- peerDependencies + peerDependenciesMeta{optional:true}: tells
consumers of agentic-qe that this is an optional integration they
can opt into, without forcing npm to install it for everyone.
- devDependencies: keeps our own build/CI deterministic without
depending on the transitive chain (@claude-flow/cli pulls guidance
as one of its own optional deps).
End-user impact: zero. The package was already transitively installed
via @claude-flow/browser → @claude-flow/cli, and runtime governance
integrations in src/governance/*-integration.ts already use lazy
`await import('@claude-flow/guidance/...')` with try/catch fallback,
so the declared-dep change does not alter what ends up in node_modules.
Type-surface check: dist/**/*.d.ts contains zero `import('@claude-flow/guidance')`
references — the internal type aliases compile away, so downstream
TypeScript consumers of agentic-qe/governance are unaffected.
Signals intent more cleanly. A bigger reducer of the upstream ERESOLVE
peer noise would be giving @claude-flow/browser the same treatment, but
that is out of scope here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- web-tree-sitter ~0.24.7 → ~0.26.8 (API moved Parser.init onto the
Parser class; adapter shim added in tree-sitter-wasm-parser.ts so we
also still work against the legacy 0.24 surface).
- @types/node ^20.19.17 → ^25.8.0 (engine "node >=18.0.0" is unchanged;
type widening only).
Deferred from Tier C (each needs its own migration PR, not a bump):
- @ruvector/attention 0.1.3 → 2.2.2: full API rewrite, classes
(FlashAttention, DotProductAttention, MultiHeadAttention,
HyperbolicAttention, LinearAttention, MoEAttention) replaced by
free functions (flashAttention, scaledDotProductAttention, …).
Requires rewriting integrations/ruvector/attention-wrapper.ts and
updating all 6 platform-binary optional deps in lockstep.
- vibium 0.1.8 → 26.x: package no longer ships dist/ — repurposed as a
CLI binary. `import { browser } from 'vibium'` no longer resolves.
Requires a different integration strategy.
- typescript 5.9 → 6.0 and eslint 8 → 10: released 1-4 weeks ago; need
their own validation pass (flat config migration for eslint).
- @ruvector/sona 0.1.5 → 0.1.6: published manifest references files
missing from the tarball (broken publish upstream).
Build passes (tsc + cli + mcp bundles). npm audit: 0 vulnerabilities.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Issue #491 exposed a structural gap in the release process: integration
coverage of the daemon-runtime seam existed (bridge-end-to-end test was
already in the repo), but it was never run on the release path —
`tests-on-tag-sha` only ran `test:unit:fast`, which excludes
`tests/integration/` by design. Every one of the four bugs in #491
lived in that unrun surface.
Two changes:
1. `package.json` — define `test:integration:fast` and
`test:integration` scripts. The "fast" variant runs the focused
daemon-runtime seam suite in ~6s:
- tests/integration/mcp/fleet-init-wires-daemon.test.ts (Bug 1+4b)
- tests/integration/workers/workers-reach-domains.test.ts (Bug 1 generalized)
- tests/integration/learning/coordinator-roundtrip.test.ts (Bug 2+3)
- tests/integration/bridge/bridge-end-to-end.test.ts (existing)
The broader `test:integration` runs all of `tests/integration/`
excluding browser/e2e for local development use.
2. `.github/workflows/npm-publish.yml` — add a new
`integration-tests-on-tag-sha` job that runs `test:integration:fast`,
wired into the publish job's `needs` and `if` conditions in the same
shape as the existing `tests-on-tag-sha`. Picked the "fast" variant
deliberately: it covers exactly the regressions #491 reported and
keeps the release gate budget tight (~10-min job ceiling, but the
work itself is ~6s). The broader integration suite is too noisy for
a release gate; the fast subset is the floor.
This is the structural complement to issue #401's pre-publish init
gate: that one catches `aqe init` regressions before users, this one
catches daemon-runtime regressions before users.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six user-reported MCP fixes (see CHANGELOG and docs/releases/v3.9.30.md):
- #467 __dirname ESM polyfill across 7 source files
- #469 real all-MiniLM-L6-v2 embeddings (was random-vector mock)
- #470 NaN guard in coherence_collapse risk categorization
- #472 default test phases when MCP wrapper omits the list
- #473 wire SessionOperationCache into MCP tools/call dispatch
- #474 validate language and auto-derive framework in test_generate
Also fixes a pre-existing field-name typo in
tests/integrations/agentic-flow/e2e-integration.test.ts (.similarity →
.score) that was vacuously passing because the previous mock embedding
generator rarely cleared the threshold to exercise the assertion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hotfix for v3.9.28 — bridge payload shape (#482 round 3)
After v3.9.28 fixed the subscriber-loading order, handlers fired for
every bridge event but immediately short-circuited because
event.payload.experience was undefined. The bridge had been publishing a
flat payload { experienceId, domain, agent, task, ... } that didn't
match handleExperienceCaptured's destructure.
Fix: bridge now publishes the canonical nested
{ experience: TaskExperience-shaped, reward } shape that matches the
existing publisher in src/learning/experience-capture.ts:1043.
Also dropped the domain-specific fan-out events (test-execution.TestRunCompleted,
coverage-analysis.CoverageGapDetected, etc.) — their handlers expect
domain-event-specific fields (runId, passed, failed, gapId, riskScore)
that hooks don't capture, so publishing them with undefined fields
recorded degenerate experiences. Universal learning.ExperienceCaptured
is now the bridge's sole publication.
Integration test now uses requirements-validation domain (per Jordi's
suggestion) so the universal-event path is the sole thing being tested,
not masked by a fan-out side effect.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hotfix for v3.9.27 — bridge subscriber wiring (#482)
The CapturedExperienceBridge shipped in v3.9.27 published events into a
kernel with no subscribers because lazyLoading: true left domain plugins
un-initialized when the bridge's first drain ran. Cursor advanced past
the rows; events were silently lost.
Fix: kernel.initialize() now eagerly loads all enabled domain plugins
before starting the bridge. CLI commands opt out via the new
enableExperienceBridge: false flag to keep their fast startup. Added
end-to-end integration test (real kernel + real plugin + real drain →
asserts kv_store has learning:experience:* key).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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>
Ten learning-pipeline fixes (#453, #454, #455, #456, #460, #461, #462,
#463, #464, #465) plus dup closures (#457-#459). Tightens the #465
sentinel sweep with the same task_json discriminator the LIMIT-1 close
uses, preserving the #451 ownership split (route sentinels owned by
post-route, pre-task sentinels by post-task). Updates the regression
suite to reflect the new sweep behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(hooks): post-route Stop hook closes route sentinels 1:1 (#451)
The `route` hook fires on UserPromptSubmit and writes a sentinel row to
routing_outcomes with quality_score=-1, expecting `post-task` to close
it. But `post-task` only fires on PostToolUse ^(Task|Agent)$, which is
rare in direct-work sessions (Bash/Edit/Read without spawning sub-
agents). Sentinels accumulated indefinitely — Jordi reported 123+
unresolved rows per session. Stream D never converged.
Changes:
1. New `aqe hooks post-route` subcommand
(src/cli/commands/hooks-handlers/routing-hooks.ts)
Closes the most-recent unresolved route sentinel using a
`task_json NOT LIKE '%"taskId"%'` discriminator that isolates
route entries from pre-task entries. Quality formula collapses the
6-dim outcome formula for unknown duration:
0.325 + 0.25·success + 0.10·1.0
= 0.675 (success) / 0.425 (failure)
2. Inverse discriminator on updateRoutingOutcomeQuality
(src/cli/commands/hooks-handlers/hooks-dream-learning.ts)
Added `task_json LIKE '%"taskId"%'` to the WHERE clause so
post-task only ever closes pre-task sentinels. Without this,
post-task could grab a stale route sentinel by accident and
miscredit duration to a row that wasn't about a Task() call.
Symmetric counterpart to the post-route filter.
3. Stop-hook wiring in both init template paths
(src/init/phases/07-hooks.ts + src/init/init-wizard-hooks.ts)
Added `npx agentic-qe hooks post-route --success true --json`
to the Stop block. Timeout 5000ms, continueOnError: true, so a
failed post-route cannot block session teardown.
4. CLI help text (src/cli/commands/hooks.ts)
Added example for the new subcommand.
5. Regression test (tests/unit/cli/commands/post-route.test.ts)
4 tests using in-memory better-sqlite3:
- Closes most-recent route sentinel; leaves pre-task sentinels
and resolved rows untouched
- quality_score = 0.425 when --success false
- No-op when only pre-task sentinels exist (discriminator works)
- No-op on second invocation when only one sentinel was outstanding
Bug-introduce verification: stashed routing-hooks.ts, ran new test —
all 4 cases failed (Commander rejects unknown subcommand). Restored
fix, all 4 pass. Test distinguishes pre-fix and post-fix states.
Co-authored-by: Jordi Izquierdo <noreply@github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(release): bump version to v3.9.25
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(hooks): post-task runs Stream B/D/F when --task-id is missing (#449)
The shipped PostToolUse hook command for Task/Agent matchers is
`npx agentic-qe hooks post-task --task-id "$TOOL_RESULT_agent_id" --success --json`
Claude Code does not populate $TOOL_RESULT_agent_id, so the flag arrives
empty and options.taskId is falsy on every real hook invocation. The
`if (options.taskId)` gate inside post-task then short-circuited the
entire Stream B/D/F learning chain:
- reasoningBank.recordOutcome — never called
- persistTaskOutcome — never called (no captured_experiences,
experience_applications, qe_trajectories, dream_insights.applied)
- updateRoutingOutcomeQuality — never called (routing_outcomes
sentinels accumulated unfilled at success=0/quality_score=-1)
- updateHookRouterQValue — never called (rl_q_values stayed empty
forever)
Same regression was fixed in v3.9.21 (patch 030) and silently came
back in v3.9.23.
Fix:
- Remove the `if (options.taskId)` gate in post-task. Use
`hook-${Date.now()}` fallback for the patternId / experience id
when the caller didn't supply one. The bridge lookup in
persistTaskOutcome keys by `ORDER BY created_at DESC LIMIT 1`
(not by taskId), so Stream F's Bellman Q-update still finds the
bridge payload it needs.
- Remove the parallel `&& options.taskId` clause from the pre-task
routing_outcomes sentinel write at line 195 — same root cause.
- Add `DO NOT REINTRODUCE` comment blocks at both sites pointing
at #449 and patch 030.
Test: tests/unit/cli/commands/task-hooks-no-taskid.test.ts mocks
hooks-shared and asserts persistTaskOutcome / updateHookRouterQValue
fire when --task-id is absent. Bug-introduce verification:
re-introducing the gate makes the no-taskId test fail with the
expected "called 1 times, but got 0 times".
Co-authored-by: Jordi Izquierdo <noreply@github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(release): bump version to v3.9.24
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes#447. Three-layer fix for the upsert-returns-wrong-UUID bug that
silently broke Stream C of self-learning:
* sqlite-persistence.ts: SELECT actual id after ON CONFLICT(name,
qe_domain, pattern_type) — the upsert keeps the existing row's UUID
but we were returning the input one, leaving downstream callers with
a UUID that didn't exist in qe_patterns.
* rvf-pattern-store.ts: capture the SQLite return value and realign
pattern.id BEFORE the HNSW ingest so the index keys stay consistent
with the source-of-truth table.
* qe-hooks.ts QEAgentCompletion: change const → let on
effectivePatternId, capture storeResult.value.id from the auto-create
storePattern call, feed it into recordOutcome. Without this, every
auto-created pattern's outcome silently failed with "Pattern not
found", which is why qe_pattern_usage stayed at 0 forever.
Also (#448): excluded tests/unit/learning/qe-reasoning-bank.test.ts and
aqe-learning-engine.test.ts from test:unit:fast — both chronically hang
the vitest fork worker on heavy module graph load. Same pattern as
domain-handlers.test.ts already excluded from test:ci. Issue #448 tracks
the root-cause investigation.
Thanks to @Jordi-Izquierdo-DDS for the #447 diagnosis.
Co-Authored-By: Jordi Izquierdo <jordi-izquierdo-dds@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes routing learning loop — bootstrap patterns now reach HNSW index
(#445). After this release, `patternCount` in routing hook output is
non-zero, existing installs auto-backfill `.agentic-qe/patterns.rvf` from
SQLite on next startup.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>