Commit Graph

5 Commits

Author SHA1 Message Date
Dragan Spiridonov 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>
2026-05-15 13:11:32 +00:00
Dragan Spiridonov 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>
2026-04-07 16:44:27 +00:00
Dragan Spiridonov 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>
2026-04-06 18:23:09 +00:00
Profa 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>
2026-03-05 12:00:01 +00:00
Profa 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>
2026-03-01 11:35:41 +00:00