ADR_DIR pointed at `implementation/adrs` but the ADR files actually live
under `docs/implementation/adrs`. Both the bash statusline and its CJS
helper looked in the wrong place, so adrCount was always 0 in the
statusline output. Updated both to the correct path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comments referenced an external patch series identifier and
a contributor's first name. Those refs aren't useful to anyone reading
this repo on its own and rot quickly. Replaced with the underlying ADR
references (ADR-058 embedding-locality, etc.) where they apply.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hook subprocesses (`npx aqe hooks ...`) opened the shared memory.db with
the platform default 5s busy_timeout. Under contention from MCP-daemon
workers holding the WAL write-lock during dream-cycle / pattern-promotion
(which can block writers for several seconds), hook writes failed with
SQLITE_BUSY.
Added `applyHookBusyTimeout(db)` in hooks-shared.ts that runs
`PRAGMA busy_timeout = 60000` on a connection. Hook subprocesses are
short-lived, so the longer timeout is bounded to that lifetime and
doesn't affect the MCP daemon's own connections.
Workers in MCP keep the platform default (5s) so they fail fast and
retry on the next tick, yielding the lock to hooks under contention —
the asymmetric prioritization ADR-001 Option C requires.
Wired at every hook handler db-open site:
• task-hooks.ts pre-task
• command-hooks.ts post-command
• routing-hooks.ts route persistence
• hooks-dream-learning.ts (5 db handle sites incl. persistTaskOutcome,
updateHookRouterQValue, updateRoutingOutcomeQuality)
Also bumps the busyTimeout in createHybridBackendWithTimeout from 5000
to 60000 so HybridMemoryBackend consumers in hook subprocesses get the
same patient timeout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related fixes in HypergraphEngine.buildFromIndexResult — the path
that turns a code index result into hypergraph_nodes/_edges rows.
1) Phase 2 (entity nodes) now also writes a `contains` edge from each
file node to each contained entity (function, class, interface, etc).
Previously only Phase 3 imports edges were persisted, so
hypergraph_edges held import edges only and queries like
`findUntestedFunctions`, `findImpactedTests`, `findCoverageGaps`
returned empty regardless of indexing activity.
2) Phase 3 (import edges) now resolves relative import specifiers
(`./foo`, `../bar/baz`) against the source file's directory and
probes common TS/JS/Python extensions plus `/index.ext` for
directory imports. Previously a relative import never matched any
hypergraph_nodes row and was silently skipped — only bare-module
imports could match, which excluded most intra-repo imports.
Schema: extends EdgeType with 'contains' and adds it to the stats
aggregator's Record initializer so getStats() compiles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
task-executor.ts:445 hardcoded `qualityScore: success ? 0.8 : 0.2` when
recording routing outcomes via QualityFeedbackLoop. That produced only
two distinct quality_score values across all task outcomes, defeating
the point of treating quality_score as a learnable signal.
Replaced with the same 6-dim formula used by the post-task hook UPDATE
path: 0.25 * success + 0.325 baseline + 0.10 * duration_tier (where
duration_tier is a stepped function of execution time). Yields 6+
distinct quality bands per success/fail × duration combination.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The CrossPhaseHooks singleton in hooks/cross-phase-hooks.ts is created on
first use, but its initialize() (config-load + memory wiring) only runs
when explicitly called. Result: under sustained queen-event-handlers
traffic, kv_store / qcsd-memory rows did not grow because the executor's
config was never parsed.
Calling getCrossPhaseHookExecutor().initialize() right after the MCP
server is Ready means hook events fire through a fully-initialized
executor from the first request.
Also drops the patch-source attribution from the existing patch-250
comment block to keep comments evergreen for downstream readers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires task-hooks.ts both
sides:
PRE-TASK now emits and persists:
• selectedPatternIds: top-5 pattern UUIDs from routing.patterns (050)
• historicalBest: agent + avgQuality + n from past success=1 rows (090)
• priorVerdicts: kv_store namespace='verdicts' last 7d (100)
• estimatedTokenSavings: SUM(average_token_savings) for selected
patterns from qe_patterns (300)
• lowConfidence: confidence < 0.5 flag (320)
• bridgeKey: hash of description; identifies the kv_store task-bridge
entry written for post-task to consume (160 + 280)
• routing_outcomes sentinel row (success=0, quality_score=-1) for
post-task UPDATE (150 split-write)
The kv_store task-bridge entry payload now carries the full structural
state (taskType, priority, domain, complexityBucket) plus
estimatedTokenSavings — the q-learning integration in post-task derives
state_key from this without recomputing.
POST-TASK now wires three helpers (defined in hooks-dream-learning.ts):
• persistTaskOutcome — writes captured_experiences + per-pattern
experience_applications + qe_trajectories single+multi-step +
dream_insights.applied bump (060/110/120/160/180/300)
• updateRoutingOutcomeQuality — UPDATEs the sentinel from pre-task
with 6-dim outcome quality (150)
• updateHookRouterQValue — Bellman update at the structural
state_key from the bridge (280)
End-to-end smoke verified: pre-task writes sentinel, post-task UPDATEs
to quality=0.635 (0.25*1 + 0.325 + 0.10*0.6 for 850ms duration),
lowConfidence flag preserved across the UPDATE.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
routing-hooks.ts wrote routing_outcomes with quality_score = routing
confidence — semantically inconsistent with the rest of the hook flow,
which now treats quality_score as "outcome quality after task ran"
(6-dim formula). Routing confidence stays in decision_json where it
belongs.
Now writes a sentinel (success=0, quality_score=-1) so post-task can
UPDATE it with the actual outcome quality. lowConfidence flag (patch
320) is captured in decision_json and the error column for diagnostic
visibility.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test outcome wiring (patches 070, 170, 310 — all in command-hooks.ts post-command:
Patch 310: persistCommandExperience was called unconditionally for every
Bash command, flooding captured_experiences with noise from git/ls/etc.
The framework regex `isTestCmd` was computed at line 200 but never gated
the persistence call. Now gated to test/build/lint commands. The original code
observed 875+ noise rows at 8.2% success rate diluting pattern signal —
this closes that flood.
Patch 070: when a recognized test framework runs, INSERT a test_outcomes
row capturing framework, language, pass/fail, and execution time.
Provides raw signal for the 6-dim quality calculator.
Patch 170: when coverage/coverage-summary.json is present (Istanbul),
parse and INSERT a coverage_sessions row with after_lines/branches/
functions, reusing the prior session's after_* values as before_* so
delta is calculable.
reasoningBank.recordOutcome remains unconditional — it's the broader
metric path, not the pattern-specific captured_experiences write.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PatternStore.initializeHNSWInternal() had the embedding-load loop only
in the legacy fallback branch. When useUnifiedHnsw=true (our default per
ADR-071), the function returned at the unified-bridge branch BEFORE the
load loop ran. Result: existing qe_pattern_embeddings rows were never
ingested into the unified HNSW backend on first init; routing fell back
to context-only matches (cosine score 0).
PatternStore.getStats() reported the pre-init zero state because it
explicitly skipped lazy-loading. So `aqe hooks stats --json` returned
nativeAvailable:false, vectorCount:0 even on a populated store.
Patch 030: extracted loadEmbeddingsIntoHNSW() and call it from both the
unified-bridge path AND the legacy path. Cap respected (maxElements).
Logs `[PatternStore] Loaded N embeddings into HNSW (skipped M)`.
Patch 040: getStats() now awaits ensureHNSW() before reading state, so
stats reflects the actual HNSW backend (paying the bounded lazy-init
cost — the contract a stats command should fulfill).
Together these close the unified-HNSW boot gap that left routing
defaulting to context-only matches with vectorCount:0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three live writers in our codebase write to qe_patterns:
1. learning/sqlite-persistence.ts:497 SQLitePatternStore.storePattern (canonical)
2. cli/.../hooks-dream-learning.ts:305 consolidateAgentPatterns (bypass)
3. workers/.../learning-consolidation.ts:412 createPatternsFromCandidates (bypass)
Only the canonical writer paired the row with a qe_pattern_embeddings
row (via computeRealEmbedding inside RealQEReasoningBank.storeQEPattern).
Writers 2 & 3 produced "ghost" patterns: rows with no vector that load
into in-memory cache but stay invisible to HNSW pattern recall.
Observed symptom: vectorCount: 0 reported even after 79 patterns
load, because 10 ghosts had no embedding.
Adds src/learning/embed-and-insert-pattern.ts with ensurePatternEmbedding(),
a fail-soft helper that:
- Builds text = `${name} ${description} ${tags.join(' ')}`
- Calls computeRealEmbedding(text) (Xenova/all-MiniLM-L6-v2, 384-dim)
- Writes qe_pattern_embeddings row alongside the existing qe_patterns INSERT
- Logs at debug level on failure (pattern row already persisted —
embedding can be backfilled later)
Routes both bypass writers through the helper so all 3 writers speak
the same embedding-config "lingua franca" (per ADR-058 locality).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claude Code dispatches subagent tools as both `Task` (legacy) and `Agent`
(current). Our PreToolUse/PostToolUse hook matchers only matched `^Task$`,
so AQE pre-task and post-task hooks never fired on real Agent dispatch.
Result: 0 deltas in captured_experiences / experience_applications /
qe_trajectories on actual subagent invocation.
Updated:
- src/init/phases/07-hooks.ts (template that ships to users via aqe init)
- .claude/settings.json (this project's working config)
Empirically verified by upstream Tier-A e2e: pre-fix 0 deltas, post-fix
full delta set across patches 060/110/120/130/150/180/190.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
src/mcp/entry.ts:211 explicitly overrode getDaemon({autoStart:false}),
neutering workerManager.startAll() — the only call path that schedules
per-worker setInterval timers. The "[MCP] Background workers started
(11 workers)" log reads totalWorkers (registered count), not scheduled
count, so the 11 background workers register but never tick in any
process spawned from this entry (Claude Code MCP, start-daemon.cjs,
manual node bundle.js).
DEFAULT_CONFIG.autoStart=true (workers/daemon.ts:53) is the canonical
default. The shutdownDaemon() call at entry.ts:44 already uses the
default; this aligns the startup path with it.
Diagnosed via external investigation — see ADR-001
"AQE workers WAL contention strategy". gitnexus impact: LOW risk,
1 affected caller.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the ruvnet/ruflo pattern (verified live in ~/.claude/plugins/marketplaces/ruflo/):
- .claude-plugin/marketplace.json — required manifest that lists agentic-qe-fleet
with relative source path, making this repo a valid Claude Code marketplace
- .claude-plugin/plugin.json — top-level metadata (engines, MCP server,
keywords) so the marketplace itself can be referenced
- .claude-plugin/README.md — picker-surface description with install command
and plugin overview
- README.md — new "Claude Code Plugin (Alternative Install)" section showing
/plugin marketplace add path and plugin-vs-aqe-init comparison; removed the
"once published" caveat now that the marketplace files exist
Users can now install via:
/plugin marketplace add proffesor-for-testing/agentic-qe
/plugin install agentic-qe-fleet
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per /release skill §4b — release notes file at docs/releases/v3.9.17.md
plus index row at the top of docs/releases/README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The shipped `aqe init` template wired the UserPromptSubmit hook to
`npx agentic-qe hooks route --task "$PROMPT" --json`, but Claude Code
never exposed `$PROMPT` as an env var — only stdin event JSON. The
shell expanded `"$PROMPT"` to `""`, so every prompt routed as empty
and `routing_outcomes.task_json` was persisted as `{"description":""}`,
silently breaking the routing learning loop.
- routing-hooks.ts: demote --task to optional, read stdin (500ms
timeout) and extract prompt/user_prompt/command/tool_input.{prompt,
description}; explicit error when neither source has content
- 07-hooks.ts and init-wizard-hooks.ts: drop --task "\$PROMPT", let
the CLI read stdin directly. isAqeHookEntry still matches both
shapes, so existing projects upgrade on `aqe init --upgrade`
- tests/unit/cli/commands/hooks-routing.test.ts: 10 unit tests
covering all event shapes, fallback ordering, malformed JSON, and
empty-field skip
Verified end-to-end: piped a Claude Code-shaped event into a fresh
project's configured route command and confirmed task_json captures
the real prompt instead of "". Backward-compat manual --task usage
preserved.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tab completion was not generating suggestions for the newly shipped
\`aqe brain diff\`, \`aqe brain search\`, or \`aqe upgrade\` commands on
any shell. This commit wires them in so users with installed completion
scripts get the same discoverability as for older commands.
Changes:
- src/cli/completions/index.ts
* COMMANDS map: add \`brain\` (with subcommands export/import/info/
diff/search/witness-backfill) and \`upgrade\` (with --json/--strict).
* Bash generator: extend top-level commands string and add case
branches for \`brain\`/\`upgrade\`, with a \`--domain\` completion
sourced from the existing domains list for \`brain search\`.
* Zsh generator: add entries to the \`commands\` array and two new
subcommand dispatch cases.
* Fish generator: add top-level completions plus per-subcommand
guards using __fish_seen_subcommand_from.
* PowerShell \$AQE_COMMANDS map: add both entries.
- tests/unit/cli/completions.test.ts
* New assertions: COMMANDS.brain + .upgrade shape, and that all four
shell generators contain both names.
Also cleaned up 22 pre-existing no-useless-escape lint errors in the
same file (unnecessary \\$ inside JS template literals — \$ alone is
already literal). Kept \${files[@]} because ${ would trigger JS
template interpolation. Output of generateBashCompletion() is
byte-identical after this cleanup; verified via 'bash -n' syntax check.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes#383 item 2.
`aqe upgrade` is a read-only advisory command that detects which optional
native bindings load on this platform and recommends installs / flag
changes. It does NOT mutate feature flags, env vars, or config files — it
only tells the user what they'd gain.
Detects:
- better-sqlite3, web-tree-sitter (required)
- hnswlib-node (canonical HNSW, default since ADR-090)
- @ruvector/rvf-node (persistent HNSW + RVF export)
- @ruvector/solver-node (sublinear PageRank)
- @ruvector/attention (Flash Attention SIMD)
- @ruvector/gnn (GraphMAE acceleration)
Output:
- Platform + AQE version
- Per-package status (loaded / missing / required-missing) with the
first line of any load error
- Current flag state (after RUVECTOR_* env overrides)
- Recommendations: install hints for missing optionals, warnings when
a RUVECTOR_* forces a flag on but the native is missing
- Summary line with required-OK status and optional loaded/total
Flags:
--json machine-readable report
--strict exit 1 if any recommended optional native is missing
Exit codes:
0 all good (or --strict not passed with optionals missing)
1 --strict and ≥1 optional missing
2 a required native failed to load
Tests:
- 17 unit tests (tests/unit/cli-upgrade.test.ts) exercise pure
detection / recommendation / exit-code logic with injected probes
- 5 integration tests (tests/integration/cli/upgrade-command.test.ts)
spawn the built CLI and assert the JSON contract, human sections,
exit-code contract, and RUVECTOR_* env override plumbing
Also fixes a pre-existing lint error (unused originalConsoleInfo in
src/cli/index.ts) per the edit-touched-file convention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the remaining actionable items in #332:
- C-10: `aqe brain diff <a> <b>` compares two brain exports.
* Manifest-level always (version, checksum, per-table record counts,
domain delta). Works for JSONL and RVF exports.
* Record-level added/removed/changed IDs when both sides are JSONL.
Append-only tables (witness_chain, qe_pattern_usage) report counts
only — their dedup columns are identity.
* Flags: --table <name>, --verbose, --json. Exit 0 when identical,
1 on any difference.
- C-09: `aqe brain search -i <export>` runs offline filtered search.
* Default table qe_patterns; `--table <name>` targets any of the 25.
* Filters: --domain (repeatable), --pattern-type, --since, --until,
--query (substring across name + description, case-insensitive),
--limit (default 20), --json.
* Returns {totalScanned, totalMatched, hits, truncated}. Exit 3 when
no rows match (distinct from errors).
C-02, C-03, C-05, C-13 are won't-fix and documented on #332 at close.
Tests: 23 new unit tests covering identical/different exports, PK vs
append-only table semantics, domain deltas, combined filters, date
ranges, limits, and error paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotion gate documented in ADR-091 (first green CI run of
test-qe-browser.yml against real Vibium) cleared at commit
fae9fd30 / workflow run 24776640163 on 2026-04-22:
- Unit tests (CommandEvalRunner + primitives): success
- Smoke test (real Vibium + httpbin): success
- aqe eval run against real Vibium: success
Changes:
- .claude/skills/qe-browser/SKILL.md: trust_tier 2 -> 3
- ADR-091 status: In Progress -> Implemented, gate marked cleared
- v3-adrs.md index row: In Progress -> Implemented, counts
updated 79->80 Implemented, 7->6 In Progress
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The smoke job is green (--no-sandbox wrapper works), but the eval
job failed because `aqe eval run` dispatches the yaml's setup
steps verbatim, and those steps used `vibium go URL` without the
global `--headless` flag. On a CI runner with no display that
tries to open a visible Chrome window and fails.
Six setup steps were affected (tc001, tc002, tc003, tc008, tc010,
tc011 equivalents). Tc006/tc007 already had --headless from commit
23416e15. Smoke-test.sh was unaffected because it prefixes
`vibium --headless` for all its invocations.
No logic changes; aligns yaml with smoke-test.sh convention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diagnostic output from commit a4cb96c5 confirmed the residual error
is chromedriver's classic "HTTP 500 create session" — Chrome's
setuid sandbox can't initialize in the GitHub Actions runner
environment (no user namespaces, restricted proc).
Fix: after `vibium install` lays down Chrome for Testing into
~/.cache/vibium/chrome-for-testing/<version>/chrome, replace the
binary with a tiny bash wrapper that execs the real Chrome with
--no-sandbox --disable-dev-shm-usage appended. The wrapper lives
inside the ephemeral runner cache; nothing is shipped to users.
This is the standard workaround used by every Chromium-based CI
runner (Puppeteer, Playwright, chromedp all do the equivalent).
Also removed the diagnostic step added in a4cb96c5 (job green is
the signal now).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause confirmed via diagnostic (commit 0f810e3f): Vibium's
auto-launch fails with "failed to create session: HTTP 500"
because the npm package ships only the Go binary — the actual
browser and chromedriver are downloaded on demand by
`vibium install`. The earlier VIBIUM_BROWSER_PATH fix was a red
herring: Vibium drives its own bundled Chrome for Testing over
WebDriver, not the runner's system google-chrome.
Reverted:
- "Discover browser path for Vibium" step (both jobs)
- "DIAGNOSTIC — probe Vibium failure" step (smoke job)
Added:
- "Download Chrome for Testing + chromedriver" step running
`vibium install` after the npm install, in both smoke and eval
jobs. This matches the documented setup flow for Vibium.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TEMPORARY diagnostic step to surface the real error Vibium's
wrapper is hiding behind "stdout: null, stderr: null". Runs a
battery of probes with continue-on-error so the step never blocks
the smoke job itself, and prints enough to diagnose whether the
Go binary is crashing on sandbox, /dev/shm, missing lib, or
something else.
To be reverted in the next commit once the root cause is known.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause of PR #431 smoke/eval job failures: Vibium installs
correctly (reports v26.3.18) but exits 1 when it tries to drive a
browser, because the runner has no Chrome on its default PATH for
Vibium's discovery — smoke-test tc002/tc004/tc006-8/tc010 all crash
with `vibium eval exited 1` in child_process, while tests that
don't need a real navigation (tc003, tc005, tc011) pass.
Fix: added a preflight step in both `smoke` and `eval` jobs that
probes the same prioritized list the installer uses
(google-chrome → google-chrome-stable → chromium-browser → chromium),
exports VIBIUM_BROWSER_PATH via $GITHUB_ENV, and fails loudly if
none is found. Ubuntu-24.04 runners have google-chrome preinstalled,
so this resolves without adding any third-party action.
This mirrors the remediation that `aqe init --auto` prints on Linux
ARM64 hosts — the mechanism is identical, just applied on AMD64 CI
where Vibium's auto-detection also fails.
Validated with actionlint 1.7.1 (clean).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves 3 CodeQL findings (205/206/207) from github-advanced-security
on PR #431: "Workflow does not contain permissions".
Added workflow-level `permissions: contents: read`. The workflow only
reads the repo and uploads an artifact — no writes to code, issues,
PRs, or releases. The artifact upload uses the ephemeral job token,
not the `actions: write` permission.
Validated with actionlint 1.7.1 (clean).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ADR-091 (qe-browser) promoted to Implemented, trust tier 3:
- new aqe eval run --skill <skill> CLI executes skill eval YAMLs as real CommandRunner evals
- aqe init --auto on Linux ARM64 now prints an exact VIBIUM_BROWSER_PATH hint
- docs/guides/qe-browser-getting-started.md for new users
- .github/workflows/test-qe-browser.yml gates PRs with vitest + smoke + eval jobs
- qe-browser eval YAML reworked to use httpbin.org (no fixture server needed)
- Vibium pin comment corrected: ^26.3.18 is a major-line pin, not major.minor
No breaking changes. CLI surface additions only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Single commit covering the 5 concrete findings from the qe-devils-advocate
review. Does not change the underlying CommandEvalRunner design or the 5
primitives — only the claims around them and the fixture-server hack the
yaml had silently inherited.
1. Revert promotion (G4): trust_tier 3 -> 2 in SKILL.md; ADR-091 status
Implemented -> In Progress (2026-04-21); v3-adrs.md index row updated
to reflect the same; counts 80->79 Implemented, 6->7 In Progress.
The promotion gate is now documented on ADR-091: first green CI run
of test-qe-browser.yml (unit + smoke + eval against real Vibium)
before trust_tier 3 / Implemented are restored.
2. Fix yaml fixtures (G3): tc006/tc007 were referencing
http://localhost:8088/qe-browser/SKILL.md.html which required an
unstarted fixture server, so `aqe eval run --skill qe-browser` would
have failed on a fresh machine. Rewrote both to use https://httpbin.org/html
(matching scripts/smoke-test.sh tc006/tc007). Dropped tc009
(poisoned-page check-injection) from the yaml — it needs the local
serve-skills.js fixture which is out of scope for CommandEvalRunner.
Documented as an explicit GAP comment in the yaml, noted that
check-injection.js's severity path is unit-tested at
tests/unit/scripts/qe-browser-check-injection.test.ts. yaml test_cases
now 11 -> 10.
3. Correct pin comment wording (G1): the previous comment claimed
^26.3.18 was a "major.minor-line pin" — that's factually wrong under
npm semver (^26.3.18 accepts 26.99.x). Rewritten to accurately
describe the intent: major-line pin that blocks 27.0+ while
allowing auto-uptake of 26.x security patches and additive features,
with scripts/smoke-test.sh as the belt-and-suspenders API contract
gate. The spec itself stays ^26.3.18 — the correct choice for an
end-user tool under semver assumptions.
4. Add eval CI job (G2): third job in test-qe-browser.yml runs
`aqe eval run --skill qe-browser --model claude-3.5-sonnet` against
a real Vibium install after `npm run build`. This is the
end-to-end proof that CommandEvalRunner dispatch works that the
previous unit tests (all mocked CommandRunner) could not provide.
Uploads the eval JSON as a CI artifact for post-run inspection.
actionlint clean.
5. Scrub stray files (G5): git rm the coherence-comparison artifacts
from docs/reports/ that were swept in by a prior `git add -A`, and
added a focused pattern to .gitignore (not a blanket docs/reports/
ignore) so future sessions can't repeat the mistake while intentional
reports can still be committed.
Tests: 51 relevant tests still pass (3 files: command-eval-runner,
command-eval-runner-qe-browser, browser-engine-installer).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes GAP-05, GAP-08, and final verification gate.
- Linux ARM64 diagnostic (GAP-05): browser-engine-installer now probes
os.platform + os.arch on Linux aarch64 and checks a prioritized list
of system chromium locations (/usr/bin/chromium, chromium-browser,
google-chrome, google-chrome-stable, /snap/bin/chromium). When a
browser is found, the install result carries a PlatformHint with an
exact VIBIUM_BROWSER_PATH export the user can copy. When none exists,
the hint surfaces the `apt-get install chromium` remediation. Wired
into phase 09 so it prints after vibium install succeeds. 5 new tests.
- GAP-08: added explicit `vibium --headless viewport 1280 720` setup
steps to yaml tc006/tc007 so the eval runs are as deterministic in CI
as smoke-test.sh. Updated smoke-test.sh header to note the yaml is
the canonical spec and the bash script is its mirror (covers the F1
vibium-missing contract case the yaml can't express cleanly).
- Trust tier promoted 2 -> 3 now that (a) the eval is runnable via
CommandEvalRunner, (b) CI runs both unit tests + smoke gate, and
(c) all 11 dependent browser-using skills either reference qe-browser
or document their intentional Playwright fallback.
- ADR-091 status: Proposed -> Implemented (2026-04-21).
- v3-adrs.md index reflects 80 Implemented / 6 In Progress / 3 Proposed.
Verification: 643/643 tests pass across tests/unit/validation/,
tests/unit/init/, tests/unit/scripts/qe-browser-*.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes GAP-03a, GAP-03b, GAP-06, GAP-07, and revises GAP-09.
- Rephrased Playwright references in enterprise-integration-testing and
pentest-validation to point at qe-browser (batch/assert/check-injection)
so the AQE fleet's canonical browser runner is the recommended tool.
- accessibility-testing: added qe-browser / a11y-ally as the preferred
axe-core integration path ahead of the Playwright example; Playwright
kept as a documented fallback for Firefox/Safari or existing suites.
- GAP-09 revised: visual-testing-advanced and compatibility-testing are
intentional hybrids, not unfinished migrations. visual-testing-advanced
already labels its Playwright section "LEGACY: fallback"; compatibility
-testing notes that Vibium's BiDi backend is Chrome-only at v26.3.x so
Firefox/Safari coverage still needs Playwright. Both stay as-is.
- Added docs/guides/qe-browser-getting-started.md covering install,
smoke check, eval run, and the 5 primitives with example CLI calls.
- Added .github/workflows/test-qe-browser.yml gating PRs that touch the
skill, its installer, or CommandEvalRunner. Job 1 runs the full vitest
sweep; Job 2 installs a pinned Vibium and runs smoke-test.sh against
real httpbin fixtures.
- Workflow validated with actionlint 1.7.1 (clean).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes GAP-01, GAP-02, GAP-04 from the ADR-091 completion plan.
- Adds CommandEvalRunner (src/validation/command-eval-runner.ts) as a
sibling to ParallelEvalRunner. Detects shell-based eval suites by
shape (first test case has input.command), runs setup/main commands
sequentially, and evaluates exit_code, json_fields (dotted JSONPath),
severity_at_least (none < low < medium < high < critical), and
candidate_count_at_least assertions against script JSON envelopes.
- Wires aqe eval run to dispatch to CommandEvalRunner when the suite is
command-mode. LLM-prompt suites keep the pre-existing path unchanged.
- Activates .claude/skills/qe-browser/evals/qe-browser.yaml (status:
active, was design-spec) and removes the honesty note now that the
runner supports its structured assertions.
- Pins vibium@^26.3.18 via DEFAULT_VIBIUM_SPEC in browser-engine-
installer.ts so npm install -g can't silently upgrade past a version
we've verified against the 5 primitives + smoke tests.
- Drops qe-browser SKILL.md trust_tier from 3 to 2 pending eval
integration in CI; will re-promote once the full verification pass
runs green.
Tests: 31 new cases (pure helpers, runner integration with injected
runner, happy-path against the shipped qe-browser.yaml).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous regen (commit 80c8186a) still failed CI `npm ci` with the same
EUSAGE / Missing packages error. Root cause: the optional dependency
chain @claude-flow/browser + @claude-flow/codex transitively requires
@claude-flow/cli, @ruvector/*, agentdb, agentic-flow, and a wide set of
transitive packages (~880 entries). My earlier local `npm ci
--ignore-scripts` and `npm install` sequence produced a lockfile that
was missing those entries — likely because a mid-sequence step resolved
optional packages via a platform filter that excluded what CI actually
needs.
This commit: clean `rm -rf node_modules package-lock.json && npm
install` followed by strict `npm ci` verification (no --ignore-scripts).
Result is a 17874-line lockfile (up from 15239) with all transitive
deps properly enumerated, and `npm ci` exits 0 cleanly from an empty
node_modules.
Verified:
- Fresh `rm -rf node_modules package-lock.json && npm install` → 1117
packages resolved, lockfile stable at 17874 lines.
- `rm -rf node_modules && npm ci` → exit 0, no EUSAGE, no Missing errors.
- `node_modules/@claude-flow/cli` now present in lockfile as required by
@claude-flow/browser's peer/dep chain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI (`npm ci`) on PR #430 failed with:
npm error `npm ci` can only install packages when your package.json
and package-lock.json or npm-shrinkwrap.json are in sync.
npm error Missing: @claude-flow/cli@3.5.80 from lock file
npm error Missing: @ruvector/attention@0.1.32 from lock file
... (dozens of transitive deps)
Root cause: when @claude-flow/guidance was moved from dependencies to
optionalDependencies, my local `npm install` ran in a Codespace where
@claude-flow/cli and related ruflo packages were already extraneous on
disk from a previous `claude mcp add ruflo` step. The npm install
reconciled node_modules to the new package.json but produced a lockfile
that assumed those extraneous packages were still available at resolve
time — so when CI did a clean `npm ci`, the lockfile claimed resolution
info that wasn't there.
Fix: remove node_modules + package-lock.json and regenerate from
package.json alone. New lockfile has +988 resolved packages (was missing
transitive deps pulled in by the optional @claude-flow/* chain) and
passes `npm ci --ignore-scripts` with exit 0.
Verified:
- `npm run build` — CLI + MCP bundles build
- `node dist/cli/bundle.js --version` → 3.9.14
- `npm audit --omit=dev` — 0 vulnerabilities (6 highs remain in dev-only
eslint/typescript-eslint chains — separate backlog item)
- `npm ci --ignore-scripts` — exit 0, 988 packages resolved cleanly
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Security + supply-chain hardening closes five P0 release blockers from
the v3.9.13 QE audit. Shipped tarball drops 52% (19.9 MB → 9.6 MB),
15 critical runtime npm vulnerabilities are eliminated, and a
command-injection path in `aqe learning repair` is closed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Security (M-01):
- src/cli/commands/learning.ts: replace execSync shell-interpolation of
the user-controlled --file path with execFileSync + file-descriptor
redirect (dump) and stdin input (import). Closes the command-injection
vector where a crafted --file="x.db\"; rm -rf ~; \"" would escape
shell quoting.
Build / supply chain:
- Move @claude-flow/guidance from dependencies to optionalDependencies
alongside @claude-flow/browser. No stable successor exists on npm;
usage is already guarded by try/await-import/catch fallbacks so
demotion is safe. Documented in the follow-up research memo.
- Lazy-load @faker-js/faker via dynamic import in
test-data-generator.ts and mark it external in build-cli.mjs /
build-mcp.mjs. Faker is a devDep that previously got statically
bundled into shipped artefacts because of a top-level import. Tarball
drops 11.5 MB → 9.6 MB.
MCP API contracts:
- Add required:true to semantically load-bearing first parameters on
agent_metrics (agentId), coverage_analyze_sublinear (target),
accessibility_test (url), defect_predict (target), code_index
(target). Verified via live MCP tools/list handshake — required
arrays now match the intent documented in each tool's description.
CI hygiene:
- Rewrite the "Commit telemetry data" step in
qcsd-production-trigger.yml to push to a bot branch and open a PR
instead of `git push` direct to protected main. That push failed 8/10
runs on the last audit cycle because of branch protection. Artifact
upload (already present) continues to preserve the raw payload for 90
days regardless of whether the PR lands.
Verification:
- npm audit --omit=dev: 0 critical, 0 high (1 moderate in
@mapbox/node-pre-gyp — extraneous, pre-existing, unrelated).
- npm run typecheck: clean.
- CLI + MCP bundles rebuild successfully.
- 253/253 test-generation unit tests pass.
- Live MCP protocol smoke: new required flags visible on tools/list;
advisor_consult guard from v3.9.14 round 1 still fires.
Memory note: see feedback_cli_is_aqe.md — CLAUDE.md ruflo refs were
audited. Only 2 lines (204, 260-261) are stale AQE-product refs; the
other 11 swarm/memory/daemon ruflo commands are legitimate
orchestration-layer invocations and are intentionally retained.
Deferred to a dedicated docs PR so the user can review each.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two targeted investigations opened while triaging the v3.9.13 QE audit
priority matrix:
1. @claude-flow/guidance strategy — recommendation: keep + demote to
optionalDependencies. No newer stable version exists on npm; usage is
already try/await-import/catch-fallback pattern across 62 refs in 17
files; the only real concern (protobufjs CWE-94 supply-chain) is
already neutralised by the v3.9.14 overrides.
2. QE agent count recount — verdict: the "60 specialized QE agents"
claim is honest, not an overcount. Primary fleet is 53 qe-*.md under
.claude/agents/v3/ plus 7 TDD/review subagents under
.claude/agents/v3/subagents/qe-*.md. Both sets mirror into
assets/agents/v3/ for npm distribution. The earlier honesty-audit
finding undercounted by 7 because subagents were not enumerated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>