agentic-qe 3.7.15 → 3.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/helpers/brain-checkpoint.cjs +11 -0
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +22 -0
- package/dist/cli/bundle.js +75 -22
- package/dist/cli/handlers/brain-handler.js +2 -1
- package/dist/domains/test-generation/coordinator.js +6 -4
- package/dist/feedback/feedback-loop.d.ts +5 -0
- package/dist/feedback/feedback-loop.js +12 -0
- package/dist/feedback/index.d.ts +1 -1
- package/dist/feedback/index.js +1 -1
- package/dist/kernel/hnsw-adapter.d.ts +3 -0
- package/dist/kernel/hnsw-adapter.js +11 -1
- package/dist/kernel/unified-memory-schemas.d.ts +1 -1
- package/dist/kernel/unified-memory-schemas.js +2 -0
- package/dist/kernel/unified-memory.js +25 -0
- package/dist/learning/experience-capture-middleware.js +24 -0
- package/dist/learning/sqlite-persistence.d.ts +3 -0
- package/dist/learning/sqlite-persistence.js +9 -0
- package/dist/learning/token-tracker.js +4 -0
- package/dist/mcp/bundle.js +190 -29
- package/dist/mcp/handlers/handler-factory.js +92 -11
- package/dist/routing/routing-feedback.d.ts +5 -0
- package/dist/routing/routing-feedback.js +29 -3
- package/dist/sync/pull-agent.js +2 -1
- package/dist/test-scheduling/pipeline.d.ts +7 -0
- package/dist/test-scheduling/pipeline.js +9 -0
- package/package.json +1 -1
|
@@ -38,6 +38,17 @@ function exportBrain() {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
try {
|
|
41
|
+
// Checkpoint WAL to ensure all pending writes are flushed to main DB
|
|
42
|
+
try {
|
|
43
|
+
execSync(`sqlite3 "${DB_PATH}" "PRAGMA wal_checkpoint(TRUNCATE);"`, {
|
|
44
|
+
timeout: 10000,
|
|
45
|
+
encoding: 'utf-8',
|
|
46
|
+
});
|
|
47
|
+
log('WAL checkpoint completed');
|
|
48
|
+
} catch (walErr) {
|
|
49
|
+
log(`WAL checkpoint warning: ${walErr.message}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
// Remove existing to avoid LockHeld errors
|
|
42
53
|
if (fs.existsSync(RVF_PATH)) {
|
|
43
54
|
fs.unlinkSync(RVF_PATH);
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ All notable changes to the Agentic QE project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.7.16] - 2026-03-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Tier 3 baseline collection and instrumentation** — Collect benchmark baselines for all Tier 3 features and add Priority 2 instrumentation: routing tier tags, HNSW/FTS5 search latency tracking, token tracker auto-save, and pipeline step timers.
|
|
13
|
+
- **MCP persistence pipeline fix** — Wire `recordDomainFeedback` into the feedback loop (handler-factory Step 5d) so `test_outcomes` and `coverage_sessions` receive data from live MCP tool calls.
|
|
14
|
+
- **Quality feedback loop singleton** — `getQualityFeedbackLoop()` provides cross-module access to the feedback loop instance.
|
|
15
|
+
- **Experience embedding on capture** — Embedding computation now runs automatically when experiences are captured.
|
|
16
|
+
- **Routing tier tracking** — New `model_tier` column in `routing_outcomes` with tier inference for cost analysis.
|
|
17
|
+
- **Search latency instrumentation** — `performance.now()` timing added to HNSW search and FTS5 `searchFTS` for benchmarking.
|
|
18
|
+
- **Token metrics auto-persistence** — `TokenMetricsCollector` now saves to DB automatically on initialization.
|
|
19
|
+
- **Pipeline step latencies** — `TestSchedulingPipeline` results now include per-step timing data.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **Critical: Test DB isolation** — Fixed `goap-planner.test.ts` and `q-value-persistence.test.ts` using relative `.agentic-qe/memory.db` paths that deleted the production database during test cleanup. Tests now use `os.tmpdir()`.
|
|
24
|
+
- **Critical: Project root cache leak** — `resetUnifiedMemory()` now calls `clearProjectRootCache()` to prevent stale path cache from redirecting tests to the production DB.
|
|
25
|
+
- **DB path safety redirect** — `UnifiedMemoryManager._doInitialize()` now detects and redirects when a test process (with `AQE_PROJECT_ROOT` set) tries to open a production `.agentic-qe/memory.db`.
|
|
26
|
+
- **`process.cwd()` DB path bypasses** — `pull-agent.ts` and `brain-handler.ts` now use `findProjectRoot()` instead of `process.cwd()` to resolve the DB path, respecting `AQE_PROJECT_ROOT`.
|
|
27
|
+
- **Optional native module graceful degradation** — FlashAttention and DecisionTransformer now degrade gracefully when native modules are unavailable.
|
|
28
|
+
- **WAL checkpoint before RVF export** — Brain checkpoint now runs a WAL checkpoint before RVF export to ensure data consistency.
|
|
29
|
+
|
|
8
30
|
## [3.7.15] - 2026-03-09
|
|
9
31
|
|
|
10
32
|
### Added
|
package/dist/cli/bundle.js
CHANGED
|
@@ -1876,7 +1876,19 @@ var init_hnsw_adapter = __esm({
|
|
|
1876
1876
|
this.backend.add(id, vector, metadata);
|
|
1877
1877
|
}
|
|
1878
1878
|
search(query, k68) {
|
|
1879
|
-
|
|
1879
|
+
const start = performance.now();
|
|
1880
|
+
const results = this.backend.search(query, k68);
|
|
1881
|
+
const elapsed = performance.now() - start;
|
|
1882
|
+
if (elapsed > 50) {
|
|
1883
|
+
console.warn(`[HNSW] search took ${elapsed.toFixed(1)}ms (k=${k68}, results=${results.length})`);
|
|
1884
|
+
}
|
|
1885
|
+
this._lastSearchLatencyMs = elapsed;
|
|
1886
|
+
return results;
|
|
1887
|
+
}
|
|
1888
|
+
/** Last search latency in ms, for instrumentation */
|
|
1889
|
+
_lastSearchLatencyMs = 0;
|
|
1890
|
+
get lastSearchLatencyMs() {
|
|
1891
|
+
return this._lastSearchLatencyMs;
|
|
1880
1892
|
}
|
|
1881
1893
|
remove(id) {
|
|
1882
1894
|
return this.backend.remove(id);
|
|
@@ -3073,10 +3085,12 @@ var init_unified_memory_schemas = __esm({
|
|
|
3073
3085
|
quality_score REAL NOT NULL,
|
|
3074
3086
|
duration_ms REAL NOT NULL,
|
|
3075
3087
|
error TEXT,
|
|
3088
|
+
model_tier TEXT,
|
|
3076
3089
|
created_at TEXT DEFAULT (datetime('now'))
|
|
3077
3090
|
);
|
|
3078
3091
|
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_agent ON routing_outcomes(used_agent);
|
|
3079
3092
|
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_created ON routing_outcomes(created_at);
|
|
3093
|
+
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_tier ON routing_outcomes(model_tier);
|
|
3080
3094
|
|
|
3081
3095
|
-- Coverage sessions (ADR-023: Coverage Learning)
|
|
3082
3096
|
CREATE TABLE IF NOT EXISTS coverage_sessions (
|
|
@@ -4070,6 +4084,7 @@ __export(unified_memory_exports, {
|
|
|
4070
4084
|
validateTableName: () => validateTableName
|
|
4071
4085
|
});
|
|
4072
4086
|
import * as fs from "fs";
|
|
4087
|
+
import * as os from "os";
|
|
4073
4088
|
import * as path from "path";
|
|
4074
4089
|
function clearProjectRootCache() {
|
|
4075
4090
|
_cachedProjectRoot = null;
|
|
@@ -4226,6 +4241,7 @@ var init_unified_memory = __esm({
|
|
|
4226
4241
|
_UnifiedMemoryManager.instance = null;
|
|
4227
4242
|
}
|
|
4228
4243
|
_UnifiedMemoryManager.instancePromise = null;
|
|
4244
|
+
clearProjectRootCache();
|
|
4229
4245
|
}
|
|
4230
4246
|
async initialize() {
|
|
4231
4247
|
if (this.initialized) return;
|
|
@@ -4237,6 +4253,17 @@ var init_unified_memory = __esm({
|
|
|
4237
4253
|
async _doInitialize() {
|
|
4238
4254
|
if (this.initialized) return;
|
|
4239
4255
|
try {
|
|
4256
|
+
const envRoot = process.env.AQE_PROJECT_ROOT;
|
|
4257
|
+
if (envRoot) {
|
|
4258
|
+
const resolvedPath = path.resolve(this.config.dbPath);
|
|
4259
|
+
const resolvedRoot = path.resolve(envRoot);
|
|
4260
|
+
if (!resolvedPath.startsWith(resolvedRoot) && !resolvedPath.startsWith(os.tmpdir()) && resolvedPath.includes(".agentic-qe")) {
|
|
4261
|
+
console.error(
|
|
4262
|
+
`[UnifiedMemory] WARNING: DB path "${this.config.dbPath}" points to a production .agentic-qe/ while AQE_PROJECT_ROOT="${envRoot}". Redirecting to test-safe path.`
|
|
4263
|
+
);
|
|
4264
|
+
this.config.dbPath = path.join(envRoot, ".agentic-qe", "memory.db");
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4240
4267
|
const dir = path.dirname(this.config.dbPath);
|
|
4241
4268
|
if (!fs.existsSync(dir)) {
|
|
4242
4269
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -24571,6 +24598,7 @@ var init_pipeline = __esm({
|
|
|
24571
24598
|
const startTime = Date.now();
|
|
24572
24599
|
let selectedTests = [];
|
|
24573
24600
|
let ranAllTests = this.config.runAllTests ?? false;
|
|
24601
|
+
const selectionStart = performance.now();
|
|
24574
24602
|
if (!ranAllTests) {
|
|
24575
24603
|
const selectionResult = await this.selector.selectAffectedTests();
|
|
24576
24604
|
if (selectionResult.runAllTests) {
|
|
@@ -24584,19 +24612,26 @@ var init_pipeline = __esm({
|
|
|
24584
24612
|
console.log(`[TestSchedulingPipeline] Selected ${selectedTests.length} affected tests`);
|
|
24585
24613
|
}
|
|
24586
24614
|
}
|
|
24615
|
+
const selectionMs = performance.now() - selectionStart;
|
|
24616
|
+
const executionStart = performance.now();
|
|
24587
24617
|
let phaseResults;
|
|
24588
24618
|
if (ranAllTests) {
|
|
24589
24619
|
phaseResults = await this.scheduler.run();
|
|
24590
24620
|
} else {
|
|
24591
24621
|
phaseResults = await this.runWithSelectedTests(selectedTests);
|
|
24592
24622
|
}
|
|
24623
|
+
const executionMs = performance.now() - executionStart;
|
|
24624
|
+
const analysisStart = performance.now();
|
|
24593
24625
|
const flakyAnalysis = this.flakyTracker.analyze();
|
|
24594
24626
|
if (this.config.flakyHistoryPath) {
|
|
24595
24627
|
await saveFlakyTracker(this.flakyTracker, this.config.flakyHistoryPath);
|
|
24596
24628
|
}
|
|
24629
|
+
const analysisMs = performance.now() - analysisStart;
|
|
24630
|
+
const reportingStart = performance.now();
|
|
24597
24631
|
if (this.ciEnvironment.isCI) {
|
|
24598
24632
|
await this.reporter.writeOutput(phaseResults);
|
|
24599
24633
|
}
|
|
24634
|
+
const reportingMs = performance.now() - reportingStart;
|
|
24600
24635
|
const totalDurationMs = Date.now() - startTime;
|
|
24601
24636
|
return {
|
|
24602
24637
|
phaseResults,
|
|
@@ -24604,7 +24639,8 @@ var init_pipeline = __esm({
|
|
|
24604
24639
|
ranAllTests,
|
|
24605
24640
|
flakyAnalysis,
|
|
24606
24641
|
ciEnvironment: this.ciEnvironment,
|
|
24607
|
-
totalDurationMs
|
|
24642
|
+
totalDurationMs,
|
|
24643
|
+
stepLatencies: { selectionMs, executionMs, analysisMs, reportingMs }
|
|
24608
24644
|
};
|
|
24609
24645
|
}
|
|
24610
24646
|
/**
|
|
@@ -26769,6 +26805,7 @@ var init_sqlite_persistence = __esm({
|
|
|
26769
26805
|
if (!this.db) throw new Error("Database not initialized");
|
|
26770
26806
|
if (!query.trim()) return [];
|
|
26771
26807
|
const sanitized = '"' + query.replace(/"/g, '""') + '"';
|
|
26808
|
+
const start = performance.now();
|
|
26772
26809
|
try {
|
|
26773
26810
|
const rows = this.db.prepare(`
|
|
26774
26811
|
SELECT p.id, rank AS fts_score
|
|
@@ -26778,6 +26815,11 @@ var init_sqlite_persistence = __esm({
|
|
|
26778
26815
|
ORDER BY rank
|
|
26779
26816
|
LIMIT ?
|
|
26780
26817
|
`).all(sanitized, limit);
|
|
26818
|
+
const elapsed = performance.now() - start;
|
|
26819
|
+
if (elapsed > 50) {
|
|
26820
|
+
console.warn(`[FTS5] searchFTS took ${elapsed.toFixed(1)}ms (results=${rows.length})`);
|
|
26821
|
+
}
|
|
26822
|
+
this._lastFtsLatencyMs = elapsed;
|
|
26781
26823
|
const maxAbsScore = Math.max(...rows.map((r54) => Math.abs(r54.fts_score)), 1);
|
|
26782
26824
|
return rows.map((r54) => ({
|
|
26783
26825
|
id: r54.id,
|
|
@@ -26787,6 +26829,11 @@ var init_sqlite_persistence = __esm({
|
|
|
26787
26829
|
return [];
|
|
26788
26830
|
}
|
|
26789
26831
|
}
|
|
26832
|
+
/** Last FTS5 search latency in ms, for instrumentation */
|
|
26833
|
+
_lastFtsLatencyMs = 0;
|
|
26834
|
+
get lastFtsLatencyMs() {
|
|
26835
|
+
return this._lastFtsLatencyMs;
|
|
26836
|
+
}
|
|
26790
26837
|
/**
|
|
26791
26838
|
* Ghost pattern check: find patterns in SQLite that have no embeddings.
|
|
26792
26839
|
* Used by aqe_health to detect data integrity issues.
|
|
@@ -44853,7 +44900,7 @@ function resolveRequest(request) {
|
|
|
44853
44900
|
import { execSync } from "child_process";
|
|
44854
44901
|
import * as fs3 from "fs";
|
|
44855
44902
|
import * as path3 from "path";
|
|
44856
|
-
import * as
|
|
44903
|
+
import * as os2 from "os";
|
|
44857
44904
|
var COMPILE_COMMANDS = {
|
|
44858
44905
|
typescript: { check: "npx tsc --noEmit --strict", fileExt: ".ts" },
|
|
44859
44906
|
java: { check: "javac -d /dev/null", fileExt: ".java" },
|
|
@@ -44874,7 +44921,7 @@ var CompilationValidator = class {
|
|
|
44874
44921
|
suggestions: [`No compilation check available for ${language} -- syntax validation skipped`]
|
|
44875
44922
|
};
|
|
44876
44923
|
}
|
|
44877
|
-
const tmpDir = fs3.mkdtempSync(path3.join(
|
|
44924
|
+
const tmpDir = fs3.mkdtempSync(path3.join(os2.tmpdir(), "aqe-compile-"));
|
|
44878
44925
|
const tmpFile = path3.join(tmpDir, `test_validation${config.fileExt}`);
|
|
44879
44926
|
try {
|
|
44880
44927
|
fs3.writeFileSync(tmpFile, code, "utf-8");
|
|
@@ -61036,8 +61083,8 @@ var TestGenerationCoordinator = class extends BaseDomainCoordinator {
|
|
|
61036
61083
|
);
|
|
61037
61084
|
console.log("[TestGenerationCoordinator] QEFlashAttention initialized for test-similarity");
|
|
61038
61085
|
} catch (error) {
|
|
61039
|
-
console.
|
|
61040
|
-
|
|
61086
|
+
console.warn("[TestGenerationCoordinator] QEFlashAttention unavailable (optional native module), continuing without it:", toErrorMessage(error));
|
|
61087
|
+
this.flashAttention = null;
|
|
61041
61088
|
}
|
|
61042
61089
|
}
|
|
61043
61090
|
if (this.config.enableDecisionTransformer) {
|
|
@@ -61048,8 +61095,8 @@ var TestGenerationCoordinator = class extends BaseDomainCoordinator {
|
|
|
61048
61095
|
});
|
|
61049
61096
|
console.log("[TestGenerationCoordinator] DecisionTransformer created for test case selection");
|
|
61050
61097
|
} catch (error) {
|
|
61051
|
-
console.
|
|
61052
|
-
|
|
61098
|
+
console.warn("[TestGenerationCoordinator] DecisionTransformer unavailable (optional native module), continuing without it:", toErrorMessage(error));
|
|
61099
|
+
this.decisionTransformer = null;
|
|
61053
61100
|
}
|
|
61054
61101
|
}
|
|
61055
61102
|
this.subscribeToEvents();
|
|
@@ -76635,7 +76682,7 @@ function getCodeMetricsAnalyzer() {
|
|
|
76635
76682
|
}
|
|
76636
76683
|
|
|
76637
76684
|
// src/shared/metrics/system-metrics.ts
|
|
76638
|
-
import * as
|
|
76685
|
+
import * as os3 from "os";
|
|
76639
76686
|
var SystemMetricsCollector = class {
|
|
76640
76687
|
lastCpuUsage = null;
|
|
76641
76688
|
lastCpuTime = 0;
|
|
@@ -76667,8 +76714,8 @@ var SystemMetricsCollector = class {
|
|
|
76667
76714
|
* Collect CPU metrics
|
|
76668
76715
|
*/
|
|
76669
76716
|
collectCpuMetrics() {
|
|
76670
|
-
const cpus2 =
|
|
76671
|
-
const loadAverage =
|
|
76717
|
+
const cpus2 = os3.cpus();
|
|
76718
|
+
const loadAverage = os3.loadavg();
|
|
76672
76719
|
let totalIdle = 0;
|
|
76673
76720
|
let totalTick = 0;
|
|
76674
76721
|
for (const cpu of cpus2) {
|
|
@@ -76688,8 +76735,8 @@ var SystemMetricsCollector = class {
|
|
|
76688
76735
|
* Collect memory metrics
|
|
76689
76736
|
*/
|
|
76690
76737
|
collectMemoryMetrics() {
|
|
76691
|
-
const total =
|
|
76692
|
-
const free =
|
|
76738
|
+
const total = os3.totalmem();
|
|
76739
|
+
const free = os3.freemem();
|
|
76693
76740
|
const used = total - free;
|
|
76694
76741
|
const usage = used / total * 100;
|
|
76695
76742
|
return {
|
|
@@ -76712,7 +76759,7 @@ var SystemMetricsCollector = class {
|
|
|
76712
76759
|
const cpuPercent = totalCpuUs / elapsedUs * 100;
|
|
76713
76760
|
this.lastCpuUsage = cpuUsage;
|
|
76714
76761
|
this.lastCpuTime = now;
|
|
76715
|
-
const totalMem =
|
|
76762
|
+
const totalMem = os3.totalmem();
|
|
76716
76763
|
const memPercent = memUsage.rss / totalMem * 100;
|
|
76717
76764
|
return {
|
|
76718
76765
|
cpuUsage: Math.min(100, Math.round(cpuPercent * 100) / 100),
|
|
@@ -132739,6 +132786,9 @@ var TokenMetricsCollectorImpl = class _TokenMetricsCollectorImpl {
|
|
|
132739
132786
|
if (config) {
|
|
132740
132787
|
this.costConfig = { ...DEFAULT_COST_CONFIG, ...config };
|
|
132741
132788
|
}
|
|
132789
|
+
this.initializeDb().catch(() => {
|
|
132790
|
+
});
|
|
132791
|
+
this.startAutoSave();
|
|
132742
132792
|
}
|
|
132743
132793
|
/**
|
|
132744
132794
|
* Set cost configuration for token pricing.
|
|
@@ -132794,6 +132844,7 @@ var TokenMetricsCollectorImpl = class _TokenMetricsCollectorImpl {
|
|
|
132794
132844
|
this.totalTokensSaved += tokensSaved;
|
|
132795
132845
|
}
|
|
132796
132846
|
this.isDirty = true;
|
|
132847
|
+
this.maybePersistToKv();
|
|
132797
132848
|
}
|
|
132798
132849
|
/**
|
|
132799
132850
|
* Record pattern reuse for a task (tokens saved by skipping LLM call).
|
|
@@ -134400,7 +134451,7 @@ init_safe_json();
|
|
|
134400
134451
|
import { randomUUID as randomUUID17 } from "crypto";
|
|
134401
134452
|
import * as fs18 from "fs";
|
|
134402
134453
|
import * as path19 from "path";
|
|
134403
|
-
import * as
|
|
134454
|
+
import * as os4 from "os";
|
|
134404
134455
|
init_safe_json();
|
|
134405
134456
|
init_error_utils();
|
|
134406
134457
|
var DEFAULT_CONFIG_DIR = ".aqe";
|
|
@@ -134427,7 +134478,7 @@ var PersistentScheduler = class {
|
|
|
134427
134478
|
* Prevents writing to arbitrary filesystem locations
|
|
134428
134479
|
*/
|
|
134429
134480
|
validateSchedulesPath(schedulesPath) {
|
|
134430
|
-
const homeDir =
|
|
134481
|
+
const homeDir = os4.homedir();
|
|
134431
134482
|
const resolvedPath = path19.resolve(schedulesPath);
|
|
134432
134483
|
const resolvedHome = path19.resolve(homeDir);
|
|
134433
134484
|
if (resolvedPath.startsWith(resolvedHome + path19.sep) || resolvedPath === resolvedHome) {
|
|
@@ -134438,7 +134489,7 @@ var PersistentScheduler = class {
|
|
|
134438
134489
|
if (resolvedPath.startsWith(resolvedCwd + path19.sep) || resolvedPath === resolvedCwd) {
|
|
134439
134490
|
return;
|
|
134440
134491
|
}
|
|
134441
|
-
const tmpDir =
|
|
134492
|
+
const tmpDir = os4.tmpdir();
|
|
134442
134493
|
const resolvedTmp = path19.resolve(tmpDir);
|
|
134443
134494
|
if (resolvedPath.startsWith(resolvedTmp + path19.sep) || resolvedPath === resolvedTmp) {
|
|
134444
134495
|
return;
|
|
@@ -134451,7 +134502,7 @@ var PersistentScheduler = class {
|
|
|
134451
134502
|
* Get the default path for schedules.json
|
|
134452
134503
|
*/
|
|
134453
134504
|
getDefaultSchedulesPath() {
|
|
134454
|
-
const homeDir =
|
|
134505
|
+
const homeDir = os4.homedir();
|
|
134455
134506
|
return path19.join(homeDir, DEFAULT_CONFIG_DIR, SCHEDULES_FILE);
|
|
134456
134507
|
}
|
|
134457
134508
|
/**
|
|
@@ -134901,7 +134952,7 @@ var ALL_DOMAINS2 = [
|
|
|
134901
134952
|
"enterprise-integration"
|
|
134902
134953
|
];
|
|
134903
134954
|
function getAQEVersion() {
|
|
134904
|
-
return true ? "3.7.
|
|
134955
|
+
return true ? "3.7.16" : "3.0.0";
|
|
134905
134956
|
}
|
|
134906
134957
|
function createDefaultConfig(projectName, projectRoot) {
|
|
134907
134958
|
return {
|
|
@@ -143106,6 +143157,7 @@ function createProtocolHandler(cleanupAndExit2, ensureInitialized2) {
|
|
|
143106
143157
|
}
|
|
143107
143158
|
|
|
143108
143159
|
// src/cli/handlers/brain-handler.ts
|
|
143160
|
+
init_unified_memory();
|
|
143109
143161
|
import path20 from "path";
|
|
143110
143162
|
import chalk9 from "chalk";
|
|
143111
143163
|
|
|
@@ -144373,7 +144425,7 @@ Examples:
|
|
|
144373
144425
|
}
|
|
144374
144426
|
};
|
|
144375
144427
|
function defaultDbPath() {
|
|
144376
|
-
return path20.join(
|
|
144428
|
+
return path20.join(findProjectRoot(), ".agentic-qe", "memory.db");
|
|
144377
144429
|
}
|
|
144378
144430
|
function formatBytes(bytes) {
|
|
144379
144431
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -156941,6 +156993,7 @@ async function syncIncrementalToCloud(since, config) {
|
|
|
156941
156993
|
init_esm_node();
|
|
156942
156994
|
import * as fs29 from "fs";
|
|
156943
156995
|
import * as path29 from "path";
|
|
156996
|
+
init_unified_memory();
|
|
156944
156997
|
init_error_utils();
|
|
156945
156998
|
init_logging();
|
|
156946
156999
|
var logger21 = LoggerFactory.create("pull-agent");
|
|
@@ -157162,7 +157215,7 @@ var PullSyncAgent = class {
|
|
|
157162
157215
|
if (this.config.targetDb) {
|
|
157163
157216
|
return path29.resolve(this.config.targetDb);
|
|
157164
157217
|
}
|
|
157165
|
-
return path29.resolve(
|
|
157218
|
+
return path29.resolve(findProjectRoot(), ".agentic-qe/memory.db");
|
|
157166
157219
|
}
|
|
157167
157220
|
backupLocalDb() {
|
|
157168
157221
|
if (this.config.dryRun) return;
|
|
@@ -164260,7 +164313,7 @@ async function cleanupAndExit(code = 0) {
|
|
|
164260
164313
|
process.exit(code);
|
|
164261
164314
|
}
|
|
164262
164315
|
var program = new Command21();
|
|
164263
|
-
var VERSION = true ? "3.7.
|
|
164316
|
+
var VERSION = true ? "3.7.16" : "0.0.0-dev";
|
|
164264
164317
|
program.name("aqe").description("Agentic QE - Domain-Driven Quality Engineering").version(VERSION);
|
|
164265
164318
|
var registry2 = createCommandRegistry(context, cleanupAndExit, ensureInitialized, ensureInitializedStrict);
|
|
164266
164319
|
registry2.registerAll(program);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
+
import { findProjectRoot } from '../../kernel/unified-memory.js';
|
|
9
10
|
import { exportBrain, importBrain, brainInfo, witnessBackfill, } from '../brain-commands.js';
|
|
10
11
|
// ============================================================================
|
|
11
12
|
// Brain Handler
|
|
@@ -270,7 +271,7 @@ Examples:
|
|
|
270
271
|
// Helpers
|
|
271
272
|
// ============================================================================
|
|
272
273
|
function defaultDbPath() {
|
|
273
|
-
return path.join(
|
|
274
|
+
return path.join(findProjectRoot(), '.agentic-qe', 'memory.db');
|
|
274
275
|
}
|
|
275
276
|
function formatBytes(bytes) {
|
|
276
277
|
if (bytes < 1024)
|
|
@@ -140,8 +140,9 @@ export class TestGenerationCoordinator extends BaseDomainCoordinator {
|
|
|
140
140
|
console.log('[TestGenerationCoordinator] QEFlashAttention initialized for test-similarity');
|
|
141
141
|
}
|
|
142
142
|
catch (error) {
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
// Graceful degradation: native module may not be available on all platforms
|
|
144
|
+
console.warn('[TestGenerationCoordinator] QEFlashAttention unavailable (optional native module), continuing without it:', toErrorMessage(error));
|
|
145
|
+
this.flashAttention = null;
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
// Initialize Decision Transformer for test case selection
|
|
@@ -155,8 +156,9 @@ export class TestGenerationCoordinator extends BaseDomainCoordinator {
|
|
|
155
156
|
console.log('[TestGenerationCoordinator] DecisionTransformer created for test case selection');
|
|
156
157
|
}
|
|
157
158
|
catch (error) {
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
// Graceful degradation: native module may not be available on all platforms
|
|
160
|
+
console.warn('[TestGenerationCoordinator] DecisionTransformer unavailable (optional native module), continuing without it:', toErrorMessage(error));
|
|
161
|
+
this.decisionTransformer = null;
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
164
|
// Subscribe to relevant events
|
|
@@ -176,4 +176,9 @@ export declare function createQualityFeedbackLoop(config?: Partial<FeedbackConfi
|
|
|
176
176
|
* Create and initialize a quality feedback loop with DB persistence
|
|
177
177
|
*/
|
|
178
178
|
export declare function createInitializedFeedbackLoop(config?: Partial<FeedbackConfig>): Promise<QualityFeedbackLoop>;
|
|
179
|
+
/**
|
|
180
|
+
* Get the initialized feedback loop singleton.
|
|
181
|
+
* Returns null if not yet initialized (call createInitializedFeedbackLoop first).
|
|
182
|
+
*/
|
|
183
|
+
export declare function getQualityFeedbackLoop(): QualityFeedbackLoop | null;
|
|
179
184
|
//# sourceMappingURL=feedback-loop.d.ts.map
|
|
@@ -295,6 +295,18 @@ export function createQualityFeedbackLoop(config) {
|
|
|
295
295
|
export async function createInitializedFeedbackLoop(config) {
|
|
296
296
|
const loop = new QualityFeedbackLoop(config);
|
|
297
297
|
await loop.initialize();
|
|
298
|
+
_feedbackLoopInstance = loop;
|
|
298
299
|
return loop;
|
|
299
300
|
}
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Singleton accessor for cross-module integration
|
|
303
|
+
// ============================================================================
|
|
304
|
+
let _feedbackLoopInstance = null;
|
|
305
|
+
/**
|
|
306
|
+
* Get the initialized feedback loop singleton.
|
|
307
|
+
* Returns null if not yet initialized (call createInitializedFeedbackLoop first).
|
|
308
|
+
*/
|
|
309
|
+
export function getQualityFeedbackLoop() {
|
|
310
|
+
return _feedbackLoopInstance;
|
|
311
|
+
}
|
|
300
312
|
//# sourceMappingURL=feedback-loop.js.map
|
package/dist/feedback/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { CoverageLearner, createCoverageLearner, } from './coverage-learner.js';
|
|
|
11
11
|
export { QualityScoreCalculator, createQualityScoreCalculator, } from './quality-score-calculator.js';
|
|
12
12
|
export { PatternPromotionManager, createPatternPromotionManager, } from './pattern-promotion.js';
|
|
13
13
|
export type { PatternMetrics } from './pattern-promotion.js';
|
|
14
|
-
export { QualityFeedbackLoop, createQualityFeedbackLoop, createInitializedFeedbackLoop, } from './feedback-loop.js';
|
|
14
|
+
export { QualityFeedbackLoop, createQualityFeedbackLoop, createInitializedFeedbackLoop, getQualityFeedbackLoop, } from './feedback-loop.js';
|
|
15
15
|
export type { FeedbackLoopStats, RoutingAnalysis, RoutingOutcomeInput, } from './feedback-loop.js';
|
|
16
16
|
export { RoutingFeedbackCollector, createRoutingFeedbackCollector, } from '../routing/routing-feedback.js';
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/feedback/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export { QualityScoreCalculator, createQualityScoreCalculator, } from './quality
|
|
|
14
14
|
// Pattern Promotion Manager
|
|
15
15
|
export { PatternPromotionManager, createPatternPromotionManager, } from './pattern-promotion.js';
|
|
16
16
|
// Main Feedback Loop Integrator
|
|
17
|
-
export { QualityFeedbackLoop, createQualityFeedbackLoop, createInitializedFeedbackLoop, } from './feedback-loop.js';
|
|
17
|
+
export { QualityFeedbackLoop, createQualityFeedbackLoop, createInitializedFeedbackLoop, getQualityFeedbackLoop, } from './feedback-loop.js';
|
|
18
18
|
// Re-export routing feedback for direct access
|
|
19
19
|
export { RoutingFeedbackCollector, createRoutingFeedbackCollector, } from '../routing/routing-feedback.js';
|
|
20
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -31,6 +31,9 @@ export declare class HnswAdapter implements IHnswIndexProvider {
|
|
|
31
31
|
constructor(name: string, config?: Partial<HnswConfig>);
|
|
32
32
|
add(id: number, vector: Float32Array, metadata?: Record<string, unknown>): void;
|
|
33
33
|
search(query: Float32Array, k: number): SearchResult[];
|
|
34
|
+
/** Last search latency in ms, for instrumentation */
|
|
35
|
+
private _lastSearchLatencyMs;
|
|
36
|
+
get lastSearchLatencyMs(): number;
|
|
34
37
|
remove(id: number): boolean;
|
|
35
38
|
size(): number;
|
|
36
39
|
dimensions(): number;
|
|
@@ -76,8 +76,18 @@ export class HnswAdapter {
|
|
|
76
76
|
this.backend.add(id, vector, metadata);
|
|
77
77
|
}
|
|
78
78
|
search(query, k) {
|
|
79
|
-
|
|
79
|
+
const start = performance.now();
|
|
80
|
+
const results = this.backend.search(query, k);
|
|
81
|
+
const elapsed = performance.now() - start;
|
|
82
|
+
if (elapsed > 50) {
|
|
83
|
+
console.warn(`[HNSW] search took ${elapsed.toFixed(1)}ms (k=${k}, results=${results.length})`);
|
|
84
|
+
}
|
|
85
|
+
this._lastSearchLatencyMs = elapsed;
|
|
86
|
+
return results;
|
|
80
87
|
}
|
|
88
|
+
/** Last search latency in ms, for instrumentation */
|
|
89
|
+
_lastSearchLatencyMs = 0;
|
|
90
|
+
get lastSearchLatencyMs() { return this._lastSearchLatencyMs; }
|
|
81
91
|
remove(id) {
|
|
82
92
|
return this.backend.remove(id);
|
|
83
93
|
}
|
|
@@ -17,6 +17,6 @@ export declare const QE_PATTERNS_SCHEMA = "\n -- QE Patterns table (unified fro
|
|
|
17
17
|
export declare const MINCUT_SCHEMA = "\n -- MinCut Graph Snapshots (ADR-047)\n CREATE TABLE IF NOT EXISTS mincut_snapshots (\n id TEXT PRIMARY KEY,\n timestamp TEXT NOT NULL DEFAULT (datetime('now')),\n vertex_count INTEGER NOT NULL,\n edge_count INTEGER NOT NULL,\n total_weight REAL NOT NULL DEFAULT 0.0,\n is_connected INTEGER NOT NULL DEFAULT 1,\n component_count INTEGER NOT NULL DEFAULT 1,\n vertices_json TEXT NOT NULL,\n edges_json TEXT NOT NULL,\n created_at TEXT DEFAULT (datetime('now'))\n );\n\n -- MinCut History (time-series MinCut values)\n CREATE TABLE IF NOT EXISTS mincut_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp TEXT NOT NULL DEFAULT (datetime('now')),\n mincut_value REAL NOT NULL,\n vertex_count INTEGER NOT NULL,\n edge_count INTEGER NOT NULL,\n algorithm TEXT NOT NULL DEFAULT 'weighted-degree',\n duration_ms INTEGER,\n snapshot_id TEXT,\n created_at TEXT DEFAULT (datetime('now')),\n FOREIGN KEY (snapshot_id) REFERENCES mincut_snapshots(id) ON DELETE SET NULL\n );\n\n -- MinCut Weak Vertices (detected bottlenecks)\n CREATE TABLE IF NOT EXISTS mincut_weak_vertices (\n id TEXT PRIMARY KEY,\n vertex_id TEXT NOT NULL,\n weighted_degree REAL NOT NULL,\n risk_score REAL NOT NULL,\n reason TEXT NOT NULL,\n domain TEXT,\n vertex_type TEXT NOT NULL,\n suggestions_json TEXT,\n detected_at TEXT NOT NULL DEFAULT (datetime('now')),\n resolved_at TEXT,\n snapshot_id TEXT,\n created_at TEXT DEFAULT (datetime('now')),\n FOREIGN KEY (snapshot_id) REFERENCES mincut_snapshots(id) ON DELETE SET NULL\n );\n\n -- MinCut Alerts\n CREATE TABLE IF NOT EXISTS mincut_alerts (\n id TEXT PRIMARY KEY,\n severity TEXT NOT NULL,\n message TEXT NOT NULL,\n mincut_value REAL NOT NULL,\n threshold REAL NOT NULL,\n affected_vertices_json TEXT,\n remediations_json TEXT,\n acknowledged INTEGER DEFAULT 0,\n acknowledged_at TEXT,\n acknowledged_by TEXT,\n timestamp TEXT NOT NULL DEFAULT (datetime('now')),\n created_at TEXT DEFAULT (datetime('now'))\n );\n\n -- MinCut Healing Actions (self-healing history)\n CREATE TABLE IF NOT EXISTS mincut_healing_actions (\n id TEXT PRIMARY KEY,\n action_type TEXT NOT NULL,\n action_params_json TEXT NOT NULL,\n success INTEGER NOT NULL,\n mincut_before REAL NOT NULL,\n mincut_after REAL NOT NULL,\n improvement REAL NOT NULL DEFAULT 0.0,\n error_message TEXT,\n duration_ms INTEGER NOT NULL,\n triggered_by TEXT,\n snapshot_before_id TEXT,\n snapshot_after_id TEXT,\n created_at TEXT DEFAULT (datetime('now')),\n FOREIGN KEY (snapshot_before_id) REFERENCES mincut_snapshots(id) ON DELETE SET NULL,\n FOREIGN KEY (snapshot_after_id) REFERENCES mincut_snapshots(id) ON DELETE SET NULL\n );\n\n -- MinCut Strange Loop Observations (P1: self-organizing)\n CREATE TABLE IF NOT EXISTS mincut_observations (\n id TEXT PRIMARY KEY,\n iteration INTEGER NOT NULL,\n mincut_value REAL NOT NULL,\n weak_vertex_count INTEGER NOT NULL DEFAULT 0,\n weak_vertices_json TEXT,\n snapshot_id TEXT,\n prediction_json TEXT,\n actual_vs_predicted_diff REAL,\n timestamp TEXT NOT NULL DEFAULT (datetime('now')),\n FOREIGN KEY (snapshot_id) REFERENCES mincut_snapshots(id) ON DELETE SET NULL\n );\n\n -- MinCut Indexes\n CREATE INDEX IF NOT EXISTS idx_mincut_history_timestamp ON mincut_history(timestamp DESC);\n CREATE INDEX IF NOT EXISTS idx_mincut_history_value ON mincut_history(mincut_value);\n CREATE INDEX IF NOT EXISTS idx_mincut_weak_vertex ON mincut_weak_vertices(vertex_id);\n CREATE INDEX IF NOT EXISTS idx_mincut_weak_risk ON mincut_weak_vertices(risk_score DESC);\n CREATE INDEX IF NOT EXISTS idx_mincut_weak_resolved ON mincut_weak_vertices(resolved_at);\n CREATE INDEX IF NOT EXISTS idx_mincut_alerts_severity ON mincut_alerts(severity);\n CREATE INDEX IF NOT EXISTS idx_mincut_alerts_ack ON mincut_alerts(acknowledged);\n CREATE INDEX IF NOT EXISTS idx_mincut_healing_type ON mincut_healing_actions(action_type);\n CREATE INDEX IF NOT EXISTS idx_mincut_healing_success ON mincut_healing_actions(success);\n CREATE INDEX IF NOT EXISTS idx_mincut_observations_iter ON mincut_observations(iteration);\n";
|
|
18
18
|
export declare const SONA_PATTERNS_SCHEMA = "\n -- SONA Patterns table (ADR-046: Pattern Persistence for Neural Backbone)\n CREATE TABLE IF NOT EXISTS sona_patterns (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n domain TEXT NOT NULL,\n state_embedding BLOB,\n action_embedding BLOB,\n action_type TEXT NOT NULL,\n action_value TEXT,\n outcome_reward REAL NOT NULL DEFAULT 0.0,\n outcome_success INTEGER NOT NULL DEFAULT 0,\n outcome_quality REAL NOT NULL DEFAULT 0.0,\n confidence REAL DEFAULT 0.5,\n usage_count INTEGER DEFAULT 0,\n success_count INTEGER DEFAULT 0,\n failure_count INTEGER DEFAULT 0,\n metadata TEXT,\n created_at TEXT DEFAULT (datetime('now')),\n updated_at TEXT DEFAULT (datetime('now')),\n last_used_at TEXT\n );\n CREATE INDEX IF NOT EXISTS idx_sona_patterns_type ON sona_patterns(type);\n CREATE INDEX IF NOT EXISTS idx_sona_patterns_domain ON sona_patterns(domain);\n CREATE INDEX IF NOT EXISTS idx_sona_patterns_confidence ON sona_patterns(confidence DESC);\n CREATE INDEX IF NOT EXISTS idx_sona_patterns_updated ON sona_patterns(updated_at DESC);\n";
|
|
19
19
|
export declare const WITNESS_CHAIN_SCHEMA = "\n -- Witness Chain (ADR-070: Cryptographic audit trail for QE decisions)\n CREATE TABLE IF NOT EXISTS witness_chain (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n prev_hash TEXT NOT NULL,\n action_hash TEXT NOT NULL,\n action_type TEXT NOT NULL,\n action_data TEXT,\n timestamp TEXT NOT NULL,\n actor TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_witness_action_type ON witness_chain(action_type);\n CREATE INDEX IF NOT EXISTS idx_witness_timestamp ON witness_chain(timestamp);\n";
|
|
20
|
-
export declare const FEEDBACK_SCHEMA = "\n -- Test outcomes (ADR-023: Quality Feedback Loop)\n CREATE TABLE IF NOT EXISTS test_outcomes (\n id TEXT PRIMARY KEY,\n test_id TEXT NOT NULL,\n test_name TEXT NOT NULL,\n generated_by TEXT NOT NULL,\n pattern_id TEXT,\n framework TEXT NOT NULL,\n language TEXT NOT NULL,\n domain TEXT NOT NULL,\n passed INTEGER NOT NULL,\n error_message TEXT,\n coverage_lines REAL DEFAULT 0,\n coverage_branches REAL DEFAULT 0,\n coverage_functions REAL DEFAULT 0,\n mutation_score REAL,\n execution_time_ms REAL NOT NULL,\n flaky INTEGER DEFAULT 0,\n flakiness_score REAL,\n maintainability_score REAL NOT NULL,\n complexity REAL,\n lines_of_code INTEGER,\n assertion_count INTEGER,\n file_path TEXT,\n source_file_path TEXT,\n metadata_json TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_pattern ON test_outcomes(pattern_id);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_agent ON test_outcomes(generated_by);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_domain ON test_outcomes(domain);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_created ON test_outcomes(created_at);\n\n -- Routing outcomes (ADR-022: Adaptive QE Agent Routing)\n CREATE TABLE IF NOT EXISTS routing_outcomes (\n id TEXT PRIMARY KEY,\n task_json TEXT NOT NULL,\n decision_json TEXT NOT NULL,\n used_agent TEXT NOT NULL,\n followed_recommendation INTEGER NOT NULL,\n success INTEGER NOT NULL,\n quality_score REAL NOT NULL,\n duration_ms REAL NOT NULL,\n error TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_routing_outcomes_agent ON routing_outcomes(used_agent);\n CREATE INDEX IF NOT EXISTS idx_routing_outcomes_created ON routing_outcomes(created_at);\n\n -- Coverage sessions (ADR-023: Coverage Learning)\n CREATE TABLE IF NOT EXISTS coverage_sessions (\n id TEXT PRIMARY KEY,\n target_path TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n technique TEXT NOT NULL,\n before_lines REAL DEFAULT 0,\n before_branches REAL DEFAULT 0,\n before_functions REAL DEFAULT 0,\n after_lines REAL DEFAULT 0,\n after_branches REAL DEFAULT 0,\n after_functions REAL DEFAULT 0,\n tests_generated INTEGER DEFAULT 0,\n tests_passed INTEGER DEFAULT 0,\n gaps_json TEXT,\n duration_ms REAL NOT NULL,\n started_at TEXT NOT NULL,\n completed_at TEXT NOT NULL,\n context_json TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_technique ON coverage_sessions(technique);\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_agent ON coverage_sessions(agent_id);\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_created ON coverage_sessions(created_at);\n";
|
|
20
|
+
export declare const FEEDBACK_SCHEMA = "\n -- Test outcomes (ADR-023: Quality Feedback Loop)\n CREATE TABLE IF NOT EXISTS test_outcomes (\n id TEXT PRIMARY KEY,\n test_id TEXT NOT NULL,\n test_name TEXT NOT NULL,\n generated_by TEXT NOT NULL,\n pattern_id TEXT,\n framework TEXT NOT NULL,\n language TEXT NOT NULL,\n domain TEXT NOT NULL,\n passed INTEGER NOT NULL,\n error_message TEXT,\n coverage_lines REAL DEFAULT 0,\n coverage_branches REAL DEFAULT 0,\n coverage_functions REAL DEFAULT 0,\n mutation_score REAL,\n execution_time_ms REAL NOT NULL,\n flaky INTEGER DEFAULT 0,\n flakiness_score REAL,\n maintainability_score REAL NOT NULL,\n complexity REAL,\n lines_of_code INTEGER,\n assertion_count INTEGER,\n file_path TEXT,\n source_file_path TEXT,\n metadata_json TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_pattern ON test_outcomes(pattern_id);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_agent ON test_outcomes(generated_by);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_domain ON test_outcomes(domain);\n CREATE INDEX IF NOT EXISTS idx_test_outcomes_created ON test_outcomes(created_at);\n\n -- Routing outcomes (ADR-022: Adaptive QE Agent Routing)\n CREATE TABLE IF NOT EXISTS routing_outcomes (\n id TEXT PRIMARY KEY,\n task_json TEXT NOT NULL,\n decision_json TEXT NOT NULL,\n used_agent TEXT NOT NULL,\n followed_recommendation INTEGER NOT NULL,\n success INTEGER NOT NULL,\n quality_score REAL NOT NULL,\n duration_ms REAL NOT NULL,\n error TEXT,\n model_tier TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_routing_outcomes_agent ON routing_outcomes(used_agent);\n CREATE INDEX IF NOT EXISTS idx_routing_outcomes_created ON routing_outcomes(created_at);\n CREATE INDEX IF NOT EXISTS idx_routing_outcomes_tier ON routing_outcomes(model_tier);\n\n -- Coverage sessions (ADR-023: Coverage Learning)\n CREATE TABLE IF NOT EXISTS coverage_sessions (\n id TEXT PRIMARY KEY,\n target_path TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n technique TEXT NOT NULL,\n before_lines REAL DEFAULT 0,\n before_branches REAL DEFAULT 0,\n before_functions REAL DEFAULT 0,\n after_lines REAL DEFAULT 0,\n after_branches REAL DEFAULT 0,\n after_functions REAL DEFAULT 0,\n tests_generated INTEGER DEFAULT 0,\n tests_passed INTEGER DEFAULT 0,\n gaps_json TEXT,\n duration_ms REAL NOT NULL,\n started_at TEXT NOT NULL,\n completed_at TEXT NOT NULL,\n context_json TEXT,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_technique ON coverage_sessions(technique);\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_agent ON coverage_sessions(agent_id);\n CREATE INDEX IF NOT EXISTS idx_coverage_sessions_created ON coverage_sessions(created_at);\n";
|
|
21
21
|
export declare const STATS_TABLES: string[];
|
|
22
22
|
//# sourceMappingURL=unified-memory-schemas.d.ts.map
|
|
@@ -551,10 +551,12 @@ export const FEEDBACK_SCHEMA = `
|
|
|
551
551
|
quality_score REAL NOT NULL,
|
|
552
552
|
duration_ms REAL NOT NULL,
|
|
553
553
|
error TEXT,
|
|
554
|
+
model_tier TEXT,
|
|
554
555
|
created_at TEXT DEFAULT (datetime('now'))
|
|
555
556
|
);
|
|
556
557
|
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_agent ON routing_outcomes(used_agent);
|
|
557
558
|
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_created ON routing_outcomes(created_at);
|
|
559
|
+
CREATE INDEX IF NOT EXISTS idx_routing_outcomes_tier ON routing_outcomes(model_tier);
|
|
558
560
|
|
|
559
561
|
-- Coverage sessions (ADR-023: Coverage Learning)
|
|
560
562
|
CREATE TABLE IF NOT EXISTS coverage_sessions (
|
|
@@ -25,6 +25,7 @@ import Database from 'better-sqlite3';
|
|
|
25
25
|
import { safeJsonParse } from '../shared/safe-json.js';
|
|
26
26
|
import { toErrorMessage } from '../shared/error-utils.js';
|
|
27
27
|
import * as fs from 'fs';
|
|
28
|
+
import * as os from 'os';
|
|
28
29
|
import * as path from 'path';
|
|
29
30
|
import { MEMORY_CONSTANTS } from './constants.js';
|
|
30
31
|
import { LoggerFactory } from '../logging/index.js';
|
|
@@ -207,6 +208,11 @@ export class UnifiedMemoryManager {
|
|
|
207
208
|
UnifiedMemoryManager.instance = null;
|
|
208
209
|
}
|
|
209
210
|
UnifiedMemoryManager.instancePromise = null;
|
|
211
|
+
// CRITICAL: Clear the cached project root so the next getInstance() call
|
|
212
|
+
// re-reads AQE_PROJECT_ROOT from the environment. Without this, tests that
|
|
213
|
+
// call resetUnifiedMemory() would still use the stale cached path, potentially
|
|
214
|
+
// opening the production database instead of the test database.
|
|
215
|
+
clearProjectRootCache();
|
|
210
216
|
}
|
|
211
217
|
async initialize() {
|
|
212
218
|
if (this.initialized)
|
|
@@ -220,6 +226,25 @@ export class UnifiedMemoryManager {
|
|
|
220
226
|
if (this.initialized)
|
|
221
227
|
return;
|
|
222
228
|
try {
|
|
229
|
+
// SAFETY: Detect test processes trying to open the production DB.
|
|
230
|
+
// If AQE_PROJECT_ROOT is set to a temp dir (vitest isolation) but the
|
|
231
|
+
// dbPath resolves to the REAL project's .agentic-qe/memory.db, redirect.
|
|
232
|
+
// Only redirect production paths — leave explicitly-set temp paths alone.
|
|
233
|
+
const envRoot = process.env.AQE_PROJECT_ROOT;
|
|
234
|
+
if (envRoot) {
|
|
235
|
+
const resolvedPath = path.resolve(this.config.dbPath);
|
|
236
|
+
const resolvedRoot = path.resolve(envRoot);
|
|
237
|
+
// Only redirect if path points OUTSIDE the env root AND into a real
|
|
238
|
+
// .agentic-qe directory (not another temp test dir)
|
|
239
|
+
if (!resolvedPath.startsWith(resolvedRoot) &&
|
|
240
|
+
!resolvedPath.startsWith(os.tmpdir()) &&
|
|
241
|
+
resolvedPath.includes('.agentic-qe')) {
|
|
242
|
+
console.error(`[UnifiedMemory] WARNING: DB path "${this.config.dbPath}" points to a ` +
|
|
243
|
+
`production .agentic-qe/ while AQE_PROJECT_ROOT="${envRoot}". ` +
|
|
244
|
+
`Redirecting to test-safe path.`);
|
|
245
|
+
this.config.dbPath = path.join(envRoot, '.agentic-qe', 'memory.db');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
223
248
|
const dir = path.dirname(this.config.dbPath);
|
|
224
249
|
if (!fs.existsSync(dir)) {
|
|
225
250
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -268,11 +268,35 @@ async function persistExperience(context, outcome) {
|
|
|
268
268
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), ?)
|
|
269
269
|
`);
|
|
270
270
|
stmt.run(outcome.id, context.task, context.agent, context.domain, outcome.success ? 1 : 0, outcome.quality, outcome.durationMs, context.modelTier || null, safeJsonStringify(context.routing), safeJsonStringify(outcome.steps), safeJsonStringify(outcome.result), outcome.error || null, context.startedAt.toISOString(), 'middleware');
|
|
271
|
+
// Fire-and-forget: compute and store embedding for this experience
|
|
272
|
+
computeExperienceEmbedding(db, outcome.id, context.task, context.domain).catch(() => { });
|
|
271
273
|
}
|
|
272
274
|
catch (error) {
|
|
273
275
|
console.error('[ExperienceCaptureMiddleware] Failed to persist experience:', error);
|
|
274
276
|
}
|
|
275
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Compute and store embedding for a captured experience (async, non-blocking).
|
|
280
|
+
* Uses the shared ONNX transformer model (all-MiniLM-L6-v2, 384-dim).
|
|
281
|
+
*/
|
|
282
|
+
async function computeExperienceEmbedding(db, experienceId, task, domain) {
|
|
283
|
+
try {
|
|
284
|
+
const { computeRealEmbedding } = await import('./real-embeddings.js');
|
|
285
|
+
const text = `${domain}: ${task}`.slice(0, 512); // Cap input length
|
|
286
|
+
const embedding = await computeRealEmbedding(text);
|
|
287
|
+
if (!embedding || embedding.length === 0)
|
|
288
|
+
return;
|
|
289
|
+
const buffer = Buffer.from(new Float32Array(embedding).buffer);
|
|
290
|
+
db.prepare(`
|
|
291
|
+
UPDATE captured_experiences
|
|
292
|
+
SET embedding = ?, embedding_dimension = ?
|
|
293
|
+
WHERE id = ? AND embedding IS NULL
|
|
294
|
+
`).run(buffer, embedding.length, experienceId);
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// Non-critical — embedding will be backfilled later if needed
|
|
298
|
+
}
|
|
299
|
+
}
|
|
276
300
|
/**
|
|
277
301
|
* Persist to sona_patterns for learning integration
|
|
278
302
|
*/
|
|
@@ -93,6 +93,9 @@ export declare class SQLitePatternStore {
|
|
|
93
93
|
id: string;
|
|
94
94
|
ftsScore: number;
|
|
95
95
|
}>;
|
|
96
|
+
/** Last FTS5 search latency in ms, for instrumentation */
|
|
97
|
+
private _lastFtsLatencyMs;
|
|
98
|
+
get lastFtsLatencyMs(): number;
|
|
96
99
|
/**
|
|
97
100
|
* Ghost pattern check: find patterns in SQLite that have no embeddings.
|
|
98
101
|
* Used by aqe_health to detect data integrity issues.
|