Commit Graph

334 Commits

Author SHA1 Message Date
Dragan Spiridonov 4a3b96d112 chore(release): bump version to v3.11.2 2026-06-27 11:36:40 +00:00
Dragan Spiridonov e25a1ef95e chore(release): bump version to v3.11.1 2026-06-25 08:25:02 +00:00
Dragan Spiridonov c0cfc16d27 feat(mcp): default-deny MCP policy gate — plan 05 / A1 (G1)
Closes G1 of the cross-pollination plan: AQE now governs its own ~90-tool
MCP surface with a default-deny policy + CI gate ("npm audit for agent tools").

- .harness/mcp-policy.json: truthful default-deny snapshot; _enforcement labels
  what is wired (tool-scoping default-deny, witness-chain audit) vs posture/
  stated-intent — not theater.
- scripts/mcp-policy-gate.mjs: self-contained mirror of MetaHarness mcp-scan's
  HIGH checks; also reads .mcp.json (closing the scan false-negative where AQE's
  server is declared there, not in .claude/settings.json). Exit 1 on any HIGH.
- .github/workflows/mcp-policy-gate.yml + `npm run security:mcp-policy`.
- tool-scoping: fix the interface doc-comment that claimed "empty/undefined ->
  allowAll" (the code DENIES by default); export ALL_AGENT_ROLES.
- tests/unit/mcp/mcp-policy-gate.test.ts: drift guard (policy roles <-> enforcement),
  default-deny posture. 46/46 green; scan = 0 HIGH; fails-closed verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 07:42:27 +00:00
Dragan Spiridonov 440d7fab99 chore(release): bump version to v3.11.0
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>
2026-06-20 13:10:20 +00:00
Dragan Spiridonov 318d988060 fix(test-gen): audit fixes — multi-file fallback + missing package export
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>
2026-06-20 12:55:07 +00:00
Dragan Spiridonov 7d3e977b75 chore(release): bump version to v3.10.9
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>
2026-06-17 16:07:13 +00:00
Dragan Spiridonov 8eb060b6e2 ci(mcp): make the MCP integration regression tests actually run (C3)
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>
2026-06-17 15:46:16 +00:00
Dragan Spiridonov 3ca830344e chore(release): bump version to v3.10.8
Rolls up three merged PRs:
- #531 database-free OpenCode install + MCP stdio client-compat fixes (@nagoodman)
- #537 protobufjs + ws production CVE fixes
- #538 vite 8.0.9 -> 8.0.16 (supersedes #536)

Version bumped across package.json, package-lock.json, and
skills-manifest.json fleetVersion. CHANGELOG + release notes added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 13:39:47 +00:00
Dragan Spiridonov 2671db28a0 fix(security): bump protobufjs >=7.6.3 and ws >=8.21.0 to clear high CVEs (#537)
Production-dependency high-severity advisories surfaced by the Security
Audit gate (npm audit --omit=dev --audit-level=high):

- protobufjs (transitive via @grpc/proto-loader, @huggingface/transformers,
  onnx-proto): GHSA-f38q-mgvj-vph7 (property shadowing) and
  GHSA-wcpc-wj8m-hjx6 (DoS via unbounded Any expansion). Was pinned to
  ^7.5.6 (resolved 7.5.8); bumped to ^7.6.3 (resolves 7.6.4), staying
  within the 7.x major.
- ws (transitive): GHSA-96hv-2xvq-fx4p (memory-exhaustion DoS). Added
  ^8.21.0 override (resolves 8.21.0).

Overrides + resolutions updated in lockstep; lockfile regenerated.
`npm audit --omit=dev --audit-level=high` => 0 vulnerabilities.
Lockfile-only dependency change; no source changes.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 14:51:22 +02:00
Dragan Spiridonov b57c0c0026 chore(release): bump version to v3.10.7 2026-06-12 13:55:23 +00:00
Dragan Spiridonov 7a0c289cf6 chore(deps): bump @ruvector/sona 0.1.5 -> 0.1.7 (SONA learning fix)
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>
2026-06-12 08:48:25 +00:00
Dragan Spiridonov b77a4cc6ea chore(release): bump version to v3.10.6
Pattern Space cross-pollination (#522): evidence-class labels on
findings, pass/fail safety eval for the data-protection absolutes,
shipped-agent invariant CI, benchmark lineage + interaction benchmark,
kept-nulls learning. ADR-105–110.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 16:39:11 +00:00
Dragan Spiridonov bd0bb213ca feat(scripts): shipped-agent invariant verifier per ADR-107 (issue #522)
config/agent-invariants.json manifest + verify-shipped-invariants.ts:
section-level content assertions (not keyword greps), shipped-vs-source
divergence on invariant sections, assets-only-qe rule, loud exemptions,
version-policy warnings. npm run verify:invariants.

Found pre-existing drift on first run: qe-integration-architect.md
(legacy format, no XML sections) and qe-queen-coordinator.md (missing 3
sections) — exempted with reasons pending maintainer decision; 53 agents
carry frontmatter 3.0.0/3.1.0 vs package 3.10.5 (warn until semantics
decided).

Verified: baseline run 0 violations/55 warnings exit 0; mutation tests
9/9 (hollow-section, removed-section, divergence, reword-passes); E2E
smoke on mutated tree exits 1 catching both hollow + divergence rules.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:25:01 +00:00
Dragan Spiridonov a483d36239 chore(release): bump version to v3.10.5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:31:24 +00:00
Dragan Spiridonov d4fba4b9fc chore(release): bump version to v3.10.4
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 14:49:13 +00:00
Dragan Spiridonov 7790a8c001 fix(deps): bump eslint-plugin-unused-imports to v4 (supports @typescript-eslint 8)
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>
2026-06-03 13:22:35 +00:00
Dragan Spiridonov 0f09a06363 chore(release): bump version to v3.10.3
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).
2026-06-03 13:16:48 +00:00
Dragan Spiridonov 94b026e2d6 chore(lint): auto-remove dead imports via eslint-plugin-unused-imports
Add eslint-plugin-unused-imports (devDependency) and switch unused-vars handling:
- unused-imports/no-unused-imports (error, autofixable) removes dead imports
- unused-imports/no-unused-vars (error, report-only) keeps dead locals visible
- @typescript-eslint/no-unused-vars disabled to avoid double-reporting

Ran the autofix across the tree: removed 478 unused imports in 251 files.
Lint problems: 1031 -> 553. No bare side-effect imports (`import 'x'`) were
removed. Verified: typecheck passes, build passes, 4507 unit/integration tests
pass. No behavioral change — purely dead-import removal.
2026-06-03 09:21:38 +00:00
Dragan Spiridonov f96159683f feat(init): ship the hook shim and wire aqe init to install + use it
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
2026-06-02 13:45:19 +00:00
Dragan Spiridonov e84a911d1f chore(release): bump version to v3.10.2
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 12:27:08 +00:00
Dragan Spiridonov 98a6b19c88 feat(plugin): machine-checkable smoke contract for agentic-qe-fleet bundle (#510 item 10)
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>
2026-06-02 10:45:10 +00:00
Dragan Spiridonov 3196c05edd feat(learning): pretrain-from-history bootstrap (#510 item 9)
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>
2026-06-02 10:41:35 +00:00
Dragan Spiridonov 0d80eb56ec feat(perf): RaBitQ 1-bit signature utility + benchmark (#510 item 8)
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>
2026-06-02 10:30:10 +00:00
Dragan Spiridonov b1a462fba2 feat(mcp): protocol-compliance smoke + tool-parity audit (#510 item 4)
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>
2026-06-02 09:40:51 +00:00
Dragan Spiridonov 9cb44d3252 feat(learning): self-learning verification harness (#510 item 1)
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>
2026-06-02 08:29:42 +00:00
Dragan Spiridonov a2200f2b7a chore(release): bump version to v3.10.1
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>
2026-05-22 07:55:37 +00:00
Dragan Spiridonov e5585582cb chore(release): bump version to v3.10.0
Minor bump — new opt-in feature: external embedder endpoint (#503, ADR-097).
2026-05-20 08:04:18 +00:00
Dragan Spiridonov eea53fcdef chore(release): bump version to v3.9.36
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 14:41:30 +00:00
Dragan Spiridonov 91d9ab19a0 chore(release): bump version to v3.9.35
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 12:44:25 +00:00
Dragan Spiridonov c6b3142f09 test(learning): split aqe-learning-engine.test.ts into three forks (issue #448 step 2)
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>
2026-05-19 12:02:12 +00:00
Dragan Spiridonov ea3566f9a2 test(learning): split qe-reasoning-bank.test.ts into three forks (issue #448 step 2)
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>
2026-05-19 09:45:16 +00:00
JLMA 4123ef6774 fix: add ./kernel/hnsw-adapter to package exports map (#497)
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.
2026-05-19 11:09:49 +02:00
Dragan Spiridonov c83c0345b3 chore(release): bump version to v3.9.34
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>
2026-05-18 17:42:55 +00:00
Dragan Spiridonov 33096de66d chore(release): bump version to v3.9.33 2026-05-18 09:49:18 +00:00
Dragan Spiridonov 122f223c9a fix(security): migrate from @xenova/transformers to @huggingface/transformers
@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>
2026-05-18 09:27:22 +00:00
Dragan Spiridonov bb2e9a4090 chore(deps): declare @claude-flow/browser as optional peer
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>
2026-05-18 08:54:49 +00:00
Dragan Spiridonov 016eda1421 chore(deps): declare @claude-flow/guidance as optional peer
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>
2026-05-18 08:51:45 +00:00
Dragan Spiridonov 713652cd81 chore(deps): tier C — runtime-safe breaking bumps
- 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>
2026-05-18 07:23:38 +00:00
Dragan Spiridonov d90093544c chore(deps): tier B — tooling majors, fixes 6 high CVEs
- @typescript-eslint/eslint-plugin ^6.13.0 → ^8.59.3
- @typescript-eslint/parser       ^6.13.0 → ^8.59.3
- commander                       ^12.1.0 → ^14.0.3
- esbuild                         ^0.27.2 → ^0.28.0

Clears all 6 high-severity advisories (minimatch chain via
@typescript-eslint/typescript-estree). npm audit: 0 vulnerabilities.

Deferred to Tier C: @ruvector/sona@0.1.6 (broken npm publish, manifest
points to non-existent files) and web-tree-sitter@0.26 (breaking API
move of Parser.init onto the Parser class).

Build passes (tsc + cli + mcp bundles).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:20:14 +00:00
Dragan Spiridonov c67942026b chore(release): bump version to v3.9.32 2026-05-17 09:31:05 +00:00
Dragan Spiridonov 2f39f2210b ci(release): gate publish on daemon-runtime integration tests (#491)
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>
2026-05-17 09:03:53 +00:00
Dragan Spiridonov 33eb0020d6 chore(release): bump version to v3.9.31
Self-learning loop ships end-to-end. Closes #480, #486, #487, #488.
Introduces ADR-094 (kernel-side dream cycles + hooks-as-producers
boundary) and ADR-095 (three-signal routing with Q-blend + ε-greedy +
mincut safety gate).

8 commits in this release:
  - 66553141 fix(hooks): post-edit dream trigger (#480) + pre-task gate (#487)
  - be32ff09 feat(workers): mineExperiences auto-trigger (#486 Gap A)
  - e266bae9 refactor(learning): single writer for pattern usage (#486 Gap B)
  - 4c0bdfaf feat(observability): daemon pidfile + loop-health (#488 Phase 1)
  - 6236a2cd feat(kernel): kernel-side dream cycles (ADR-094, #488 Phase 2)
  - 874ae39c feat(learning,bridge): dream_insights TTL + cursor guard (#488 Phase 3)
  - 70154c1b feat(routing): three-signal routing (ADR-095, #488 Phase 4)
  - 43ebcaa3 fix(routing,kernel,cli): brutal-honesty audit follow-ups

Version sites updated:
  - package.json + package-lock.json
  - .claude/skills/skills-manifest.json fleetVersion
  - assets/skills/skills-manifest.json fleetVersion
  - .claude-plugin/plugin.json version

CHANGELOG and docs/releases/v3.9.31.md added.
docs/releases/README.md row added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:54:00 +00:00
Dragan Spiridonov a664b679e0 chore(release): bump version to v3.9.30
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>
2026-05-14 14:32:40 +00:00
Dragan Spiridonov f7acdd5707 chore(release): bump version to v3.9.29
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>
2026-05-14 11:56:00 +00:00
Dragan Spiridonov 062b413b70 chore(release): bump version to v3.9.28
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>
2026-05-14 09:50:54 +00:00
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
Dragan Spiridonov bb34aeace4 chore(release): bump version to v3.9.26
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>
2026-05-13 14:20:24 +00:00
Dragan Spiridonov fe373e28ff fix(deps): patch 11 Dependabot alerts (protobufjs + OpenTelemetry) (#476)
Bump transitive deps to safe versions via resolutions/overrides:

protobufjs 7.5.5 -> 7.5.8 (resolves GHSA-685m-2w69-288q, GHSA-66ff-xgx4-vchm,
GHSA-2pr8-phx7-x9h3, GHSA-fx83-v9x8-x52w, GHSA-75px-5xx7-5xc7,
GHSA-jvwf-75h9-cwgg, GHSA-q6x5-8v7m-xcrf)

@protobufjs/utf8 1.1.0 -> 1.1.1 (resolves GHSA-q6x5-8v7m-xcrf in utf8 sub-pkg)

@opentelemetry/sdk-node 0.52.1 -> 0.218.0
@opentelemetry/auto-instrumentations-node 0.47.1 -> 0.76.0
@opentelemetry/exporter-prometheus 0.52.1 -> 0.218.0
(all resolve GHSA-q7rr-3cgh-j5r3 - Prometheus exporter process crash via
malformed HTTP request)

All patches verified:
- npm audit --omit=dev: 0 vulnerabilities
- npm run build: clean
- Fast unit suite: 7477/7477 passing

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:24:12 +02:00
Dragan Spiridonov b2e6090c6d chore(release): v3.9.25 (#452)
* 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>
2026-05-12 15:05:29 +02:00
Dragan Spiridonov ca714ac1a7 chore(release): v3.9.24 (#450)
* 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>
2026-05-12 09:54:33 +02:00