mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
transformers-fastest-validation-session
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
112fffc466 |
fix(init,mcp): --no-claude routing (C1), db-free continuedev merge (C2), startup exit (H3)
Devil's-advocate review of today's branch surfaced three real gaps: C1 (init-handler.ts): bare `aqe init --no-claude` (no --with-<platform>, no --no-database) fell through to runStandardInit and installed the FULL Claude surface it was meant to suppress — `noClaude` was only honored inside the modular path. Add `options.claude === false` to the modular routing guard. Verified: `aqe init --no-claude --minimal` now writes no .claude/, .mcp.json, or CLAUDE.md (and the empty-install warning fires). C2 (continuedev-installer.ts): the mergeExistingYamlConfig branch (existing `mcpServers:` + --overwrite) appended a hardcoded AQE_MEMORY_PATH entry, ignoring memoryBackend — re-introducing the #533 db leak in db-free installs over an existing Continue config. Honor memoryBackend on this path too. Adds a regression test. H3 (entry.ts): main() ran fire-and-forget, so a startup rejection that escaped its internal try hit the unhandledRejection handler (which intentionally keeps the server alive at runtime) → on the in-process `agentic-qe mcp` path the CLI wrapper would hang on its never-resolving promise with a zero exit. main() now `.catch`es and exits non-zero on a failed startup. Re-verified #528/#535 integration tests still green (normal startup unaffected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5975171fe5 |
feat(init): db-free MCP propagation (#533) + --no-claude exclusive mode (#532)
#533 — database-free mode now propagates AQE_MEMORY_BACKEND=memory to ALL generated MCP-server configs, not just opencode.json. Previously `aqe init --no-database` left .mcp.json (Claude Code) and every editor config pointed at .agentic-qe/memory.db, so launching the server via any non-OpenCode client recreated the db at runtime and defeated the db-free install. - platform-config-generator.ts: generateMcpConfig(platformId, { memoryBackend }) emits AQE_MEMORY_BACKEND=memory and drops AQE_MEMORY_PATH for JSON/TOML/YAML; covers the 8 shared-generator installers (cursor/cline/continuedev/kilocode/ roocode/windsurf/codex/copilot). - 08-mcp.ts (.mcp.json) and kiro-installer.ts: same db-free env; learning/workers not forced on in db-free mode (they persist to SQLite). - 09-assets.ts threads memoryBackend into every platform installer. Default (persistent) output is byte-for-byte unchanged. #532 — new opt-in `--no-claude` suppresses the default Claude Code surface (.claude/ skills+agents, .mcp.json, CLAUDE.md, governance, hooks) so `--with-<platform>` flags become the only install targets — e.g. a clean OpenCode-only install. Gated via shouldRun/run on phases 07-hooks, 08-mcp, 09-assets (core assets), 11-claude-md, 13-governance. Default install (no flag) is unchanged; warns if --no-claude is passed with no platform. Verified by real `aqe init` runs in temp dirs: - `--no-database --with-codex --with-cursor`: .mcp.json/.cursor/.codex all emit AQE_MEMORY_BACKEND=memory; no memory.db created. - `--no-claude --with-opencode --no-database`: .opencode present; .claude/, .mcp.json, CLAUDE.md all absent. - default `--with-cursor`: full surface + persistent env intact (no regression). Adds db-free + no-claude cases to platform-config-generator and mcp-phase tests; all 406 init unit tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4c0bdfafb9 |
feat(observability): daemon pidfile fix + learning loop-health (#488 Phase 1)
Phase 1 of the #488 production-readiness work, scoped to additive changes that don't need new ADRs. Two parts: B.1 — Daemon pidfile points at the npx wrapper, not the MCP server ================================================================= When neither `node_modules/.bin/aqe-mcp` nor the local `node_modules/agentic-qe/dist/mcp/bundle.js` exists, the generated `.agentic-qe/workers/start-daemon.cjs` falls back to `npx --yes agentic-qe mcp`. `npx` exits as soon as it has forked the real bundle, so `child.pid` is the wrapper PID and the pidfile becomes stale within seconds. `aqe daemon status` then misreports liveness, and the idempotency check at the top of the script spawns duplicate daemons — the reporter hit this twice in two days. Adds `require.resolve('agentic-qe/dist/mcp/bundle.js')` as a 3rd candidate (try/catch-guarded) before the npx fallback. Globally-installed shops (`npm install -g agentic-qe` — the typical case the npx fallback was silently covering) now spawn the real bundle directly; `child.pid` is the long-lived MCP server. The npx fallback remains as a last resort for environments where neither local nor global install is reachable. When taken, it now logs a WARNING to daemon.log so operators can see the degraded pidfile contract. B.2 — `learning:loop-health` observability ========================================== Operators previously had no way to answer "is the self-learning loop closing end-to-end?" without DB-mining `dream_cycles`, `kv_store`, and `routing_outcomes` separately. Cumulative counters in `aqe learning stats` grow forever and can't distinguish "healthy loop" from "loop wedged 3 hours ago with stale totals". Adds a single `learning:loop-health` kv key with per-component liveness: { overallLastSuccess, bootedAt, components: { bridge?: { lastSuccessAt, ticksSinceBoot, ... }, learningWorker?: { lastSuccessAt, ticksSinceBoot, ... }, dreamScheduler?: { lastSuccessAt, ticksSinceBoot, ... }, } } Writers (best-effort — observability MUST NOT crash the observed component): - CapturedExperienceBridge.drainSafe — every poll, success or failure - LearningConsolidationWorker.doExecute — end of every tick - DreamScheduler reserved for #488 Phase 2 (the field stays undefined until Phase 2 wires the scheduler in-kernel) Surface: - new `aqe learning loop-health [--json]` CLI subcommand with component verdicts (live/stale/never-ran) based on per-component staleness thresholds (bridge: 30s; worker/scheduler: 2h) - distinct from the existing `aqe learning health` (per-domain regret analysis); the new command is pipeline liveness, not agent outcome quality Tests: - 12 tests in tests/unit/learning/loop-health.test.ts for the utility: fresh record creation, tick counters, error capture + clear-on-success, multi-component isolation, overallLastSuccess max-computation, throw-safety when the memory backend is broken, staleness verdicts - 4 tests in tests/unit/init/phases/10-workers-daemon-pidfile.test.ts asserting the require.resolve probe is present, try/catch-guarded, ordered before the npx fallback, and that the warning string is in place 541/541 tests pass across CLI commands, workers, bridge, learning, and init/phases suites; build clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
23416e1577 |
feat(adr-091): promote to Implemented — trust_tier 3, platform hint, yaml/smoke unify
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> |
||
|
|
2fe2300c68 |
feat(adr-091): make qe-browser.yaml a runnable eval + pin Vibium
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> |
||
|
|
2988cbcc7c |
fix(qe-browser): Phase 2 high-severity fixes from devil's-advocate review
H1: detectVibium reads stderr too, extracts semver
- Many Go CLIs (including some Vibium versions) write --version to stderr.
detectVibium used to read only stdout and silently report 'unknown',
polluting the init log with "vibium unknown (already installed)".
- Fix: read both streams, prefer stdout, extract bare semver via regex
so output is consistent regardless of where the binary printed it.
- Tests: 5 new regression tests covering stderr fallback, stdout
preference, verbose-format extraction, prerelease tags, fallback to
first whitespace token.
- Note: result.version is now bare semver (26.3.18) not v-prefixed.
Two pre-existing tests updated to match the new contract.
H2: instructions_in_html_comment dead-code regex
- TreeWalker(SHOW_COMMENT).textContent yields the inner text without
the <!-- --> delimiters, so the pattern that requires the literal
`<!--` prefix could never fire. Eval tc009 was passing only by
accident (ignore_previous_instructions fired on the same fixture).
- Fix: re-wrap each comment node in `<!-- ... -->` before adding to
the hidden bucket. Pattern can now actually match.
- Tests: 2 new regression tests asserting wrapped form fires AND
unwrapped form does NOT fire (the bug condition).
H4: e2e-flow-verifier frontmatter regression — INVALID FINDING
- Verified against `git show main:` — the skill always had minimal
frontmatter on main (just name + description + user-invocable: true)
and has no evals/, schemas/, or scripts/ directories. It is a
user-invocable runbook-style skill, not trust-tier-3 validated.
No metadata to restore. Marked closed-as-invalid.
H6: log-before-spawn for the 3-minute Vibium install
- spawnSync(npm install -g vibium) blocks the event loop for up to
3 minutes on a cold cache while Chrome for Testing downloads. The
user saw zero output and would Ctrl-C thinking init hung.
- Fix: pre-flight detect call (5s timeout) short-circuits when vibium
is already installed (the common case, no banner). When the install
is actually about to run, log a clear "this can take 1-3 minutes,
downloads Chrome for Testing lazily" message BEFORE the spawn.
H7: scoped scripts/package.json survives npm pack — VERIFIED
- `npm pack --dry-run` confirms both
.claude/skills/qe-browser/scripts/package.json (225B) AND
assets/skills/qe-browser/scripts/package.json (225B)
are included in the published tarball. The CommonJS override that
keeps the helper scripts loadable from an ESM project root will
survive `npm install` after publication. No fix needed.
H8: eval yaml uses unsupported runner fields
- The structured assertion fields I invented (exit_code, json_fields,
severity_at_least, candidate_count_at_least) are NOT understood by
src/validation/parallel-eval-runner.ts which expects must_contain
keyword matching. The yaml as written is unrunnable.
- Honest fix: relabel evals/qe-browser.yaml as `status: design-spec`
with a HONESTY NOTE explaining it's a specification, not a runnable
eval. Two paths to make it runnable documented (extend runner OR
rewrite as must_contain).
- Parallel artifact: scripts/smoke-test.sh — a runnable bash smoke
test against the same pinned httpbin.org fixtures. THIS is the
script that gates PR-reopen per ADR-091 Phase 3.
Bonus from B2/H5 already in Phase 1:
- assert.js now uses ?? instead of || for the `expected` field
Verification:
- 50/50 qe-browser tests pass (was 36 in initial PR; +14 regressions)
- 392/392 init tests pass (was 387; +5 from H1)
- npm run build: clean
- npm pack --dry-run: scoped package.json confirmed in tarball
- eslint on all touched source files: clean
- bash -n smoke-test.sh: syntax OK
Phase 3 (real Vibium smoke test) still gating PR reopen per ADR-091.
Branch intentionally not pushed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
cd4ea7e451 |
feat(skills): add qe-browser fleet skill with Vibium engine
Introduces a new AQE-owned browser automation skill layered over Vibium (WebDriver BiDi, single 10MB Go binary) and migrates 11 browser-using QE skills to use it instead of raw Playwright/Puppeteer. qe-browser ships five helper scripts that add QE primitives Vibium doesn't cover on its own: typed assertions (16 check kinds), batch execution, pixel-diff against stored baselines, prompt-injection scanning, and semantic intent scoring ported from gsd-browser (MIT/Apache). Each script emits a structured JSON envelope matching schemas/output.json so hooks and CI gates can parse results without stdout grep. Vibium installs automatically during `aqe init` via a new graceful browser-engine installer that shells out to `npm install -g vibium` and reports `already-installed`, `installed`, `install-failed`, or `npm-unavailable` without ever failing init. Skills migrated to reference qe-browser: a11y-ally, e2e-flow-verifier, qe-visual-accessibility, security-visual-testing, visual-testing-advanced, testability-scoring, compatibility-testing, accessibility-testing, localization-testing, observability-testing-patterns, enterprise-integration-testing. Ships 36 new unit tests (browser-engine-installer, assert, intent-score, check-injection) with dependency-injected spawners to avoid touching real processes. All 387 existing init tests still pass. Eval harness uses pinned public fixtures (httpbin.org, Vibium docs at a pinned tag) plus a local static server that wraps this repo's own skill docs, per the "no synthetic fixtures" rule. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
05dcfe92dd |
fix(init): release-gate corpus + --json contract (#401)
Addresses the v3.9.1–v3.9.4 init regression series by building the verification layer that #401's post-mortem identified as structurally missing. The load-bearing changes are the real-public-repo corpus, the --json contract, and the restructured error handling in phase 06 that stops lying about success when a non-critical phase fails. What landed ----------- * `aqe init --json` — structured InitResult output with schema version 1, stricter exit code semantics (exit 1 on any step.status='error', not just on critical failures). Stable contract for the gate and other CI consumers. See InitJsonOutput in src/cli/handlers/init-handler.ts. * Phase 06 no longer swallows errors as `{status:'skipped',entries:0}`. Exceptions now propagate to BasePhase.execute() and surface as real step errors in result.steps[]. Fixed a resource leak where kgService and memory handles were leaked on the old throw path — now always released via try/finally. * `tests/fixtures/init-corpus/` — 4 pinned real public repo fixtures: - tiny-ts (developit/mitt@b240473) - mid-ts (sindresorhus/p-queue@55d306b) - multi-lang-real (ruvnet/RuView@2a05378 — contains the exact 28,745 byte / 776 line ruview_live.py that triggered the v3.9.4 hang, sha256-pinned to detect content drift) - self-dogfood (agentic-qe HEAD) * 22 gate assertions per fixture (A1–A22) including per-step JSON error inspection (A10), snapshot-based KG threshold with tolerance (A12), skills/agents/MCP/CLAUDE.md/workers/config.yaml presence (A13–A20), subthreshold stall detection (A21), and a second init pass that exercises the delta-scan path of phase 06 — the actual surface that hung in v3.9.1 ruview, never reached on a first init (A22). * `.github/workflows/npm-publish.yml` — new pre-publish-gate job that runs the corpus against the freshly-built tarball before publish; new tests-on-tag-sha job that re-runs fast unit tests on release events (replaces a buggy gh-api conditional caught by devils-advocate review). * `.github/workflows/post-publish-canary.yml` — fires on real publishes only (not workflow_dispatch dry runs), polls npm CDN via `npm install --dry-run` (actual CDN edge, not just registry metadata), runs the corpus against the published package, opens P0 issue on failure via heredoc-based body. * Watchdog effectiveness unit test (tests/unit/init/phases/code-intelligence-watchdog.test.ts) — 4 cases proving the async-stall branches of runBoundedScan work and documenting the sync-block limitation that requires AQE_SKIP_CODE_INDEX or (future) worker isolation. * `.github/PULL_REQUEST_TEMPLATE.md` — single load-bearing checkbox: every PR failure mode must have a test or tracking issue. Honor-system today; CI enforcement tracked in #408. * AQE_SKIP_CODE_INDEX promoted from "temporary escape hatch" to permanent supported flag in docs, CLI help, and source comments. Verification ------------ * `npm run typecheck` — clean * `npx eslint` on all touched files — clean (plus fixed two pre-existing unused-var warnings in init-handler.ts) * `aqe security --sast` on all touched source + workflows — 0 findings * `tests/unit/init/` — 377/377 pass * `tests/unit/init/phases/code-intelligence-watchdog.test.ts` — 4/4 pass * Local gate against `npm pack`'d tarball — 4/4 fixtures pass all 22 assertions including double-init delta path and sha256 regression marker Failure paths independently verified (F1–F5 injection tests): * F1 wrong sha256 → A3 fires, exit 2, actionable diagnostic * F2 absurd expectedKgEntries → A12 fires, exit 2, shows actual vs expected * F3 expectedElapsedSec=0 → A21 fires on slow fixture, A22 fires on double-init — same `(( elapsed > soft_cap ))` math proven in both paths * F4 injected throw in runCodeIntelligenceScan → reproduces the exact v3.9.3 failure shape (`success:true` at orchestrator level, phase 06 step.status='error'). A7 catches via strict exit code, A10 catches as defense-in-depth via jq inspection. Both layers verified. * F5 expectedSkillsInstalled=999 → A13 fires with OR-logic showing json=84, disk=84 vs expected 999 Deferred with tracking issues ----------------------------- * Phase 06 worker_threads isolation — #407 * PR template CI enforcement — #408 * VERIFICATION.md + release-notes matrix — #409 * Chaos workflow for pathological inputs — #410 * Mirror init-corpus tarballs to GitHub Releases — #411 What is NOT verified -------------------- * The CI workflows have never actually executed in a real Actions run. YAML syntactically validated via js-yaml, job dependency graph traced, but the first real execution is the first push of this branch. * The canary on a real publish is unexecuted. First execution is the first real release after merge. Refs: #401, #407, #408, #409, #410, #411 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
db99c17c7d |
feat(init): warn on stale ./vectors.db post hnswlib-node migration (#399)
Prior to ADR-090, NativeHnswBackend wrapped @ruvector/router's
VectorDb, whose constructor unconditionally wrote a `vectors.db`
redb file to the current working directory — outside .agentic-qe/,
in a non-SQLite format, never read by anything in production
(its HNSW search returned wrong answers anyway). Users who upgrade
from a pre-#399 version will have an orphaned multi-MB file in
their project root.
`aqe init` now detects `./vectors.db` in the project root and logs
a one-time warning identifying it as stale from the @ruvector/router
era and suggesting `rm vectors.db` for cleanup.
The phase does NOT auto-delete the file. Per CLAUDE.md data
protection rules, AQE never overwrites, replaces, recreates, or
removes any .db file without explicit user confirmation. Users who
want to clean up run `rm vectors.db` themselves.
Three new unit tests in `tests/unit/init/phases/database-phase.test.ts`:
- asserts the warning fires when `./vectors.db` is present
- asserts the warning does not fire when it is absent
- asserts the phase never calls fs.unlinkSync or fs.rmSync,
regardless of whether vectors.db exists (data protection guard)
Refs #399, ADR-090.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
ca0c6e7c5e |
fix: use CLAUDE_PROJECT_DIR for hook paths and remove ruflo permissions from aqe init
Hook commands using relative paths (node ./dist/...) or git rev-parse
broke when invoked from subfolders. Adopted the CLAUDE_PROJECT_DIR
pattern (sh -c 'exec node "${CLAUDE_PROJECT_DIR:-.}/..."') which
Claude Code sets to the project root.
Also: removed ruflo/claude-flow permissions from _aqePermissions
injected by aqe init — only AQE-specific entries belong in user
settings. Fixed init-wizard-hooks.ts missing union-merge for
permissions (#362 parity).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
418d8d9c52 |
fix(hooks): remove hardcoded absolute paths from generated hook commands (#369)
Hook commands generated by `aqe init` embedded the host machine's absolute path as a fallback, making settings.json non-portable across machines. Since Claude Code runs hooks with cwd=project root and the helpers already use __dirname internally, simple relative paths are sufficient. Also fixes stale test that asserted on old `permissions` key renamed to `_aqePermissions` in #362. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
6442491a09 |
fix: deduplicate brain-checkpoint hooks and fix governance time budget (#344, #345)
Hook deduplication: add brain-checkpoint.cjs and .claude/helpers/ patterns to AQE_COMMAND_PATTERNS so mergeHooksSmart() correctly identifies them as AQE-owned and removes old copies on re-init instead of accumulating duplicates. Governance time budget: change budgetRemaining.timeMs to measure idle time since last action instead of total elapsed since first action, and increase default idleTimeoutMs from 5 to 15 minutes. Prevents false "Budget exhausted: time" blocks on requirements_validate and coverage_analyze_sublinear. Closes #344, closes #345 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
e2fb4a2f14 |
feat(multi-lang): add docs, ADRs, tests, and fixtures for multi-language support
Update ADRs 075-079 with implementation details, revise the multi-language GOAP implementation plan, add test generators and parser test fixtures for Go, Rust, Java, C#, Swift, Python. Include skill validation schema updates and v2→v3 migration skill. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
2253d05618 |
feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code, tests, configs, and assets directly to the project root. Archive v2/ (dead code, 847MB) to v2-archive.tar.gz. Key changes: - Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/ - Move v3/tsconfig.json, v3/vitest.config.ts to root - Merge v3/package.json into root package.json (ESM, scripts, deps, exports) - Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/ - Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes - Fix all init installer path resolution (3-level-up → 2-level-up) - Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe" - Update settings.json ADR/DDD directories to docs/implementation/ - Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks) - Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces - Update 15 guidance shards: v3/src/ → src/ path references - Fix sync interfaces: remove v3/ and v2/ path references - Fix test path calculations (process.cwd() + '..' no longer needed) - Fix flaky perf test threshold (500ms → 1000ms for CI environments) - Fix complexity-analyzer test to match ADR-051 keyword-based eligibility Build passes, 17,901 tests pass, CLI and MCP bundles verified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |