agentic-qe 3.7.21 → 3.8.0

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.
Files changed (164) hide show
  1. package/.claude/helpers/brain-checkpoint.cjs +4 -1
  2. package/.claude/helpers/statusline-v3.cjs +3 -1
  3. package/.claude/skills/skills-manifest.json +1 -1
  4. package/CHANGELOG.md +45 -0
  5. package/README.md +2 -14
  6. package/assets/helpers/statusline-v3.cjs +3 -1
  7. package/dist/cli/brain-commands.js +6 -10
  8. package/dist/cli/bundle.js +7441 -4327
  9. package/dist/cli/commands/audit.d.ts +43 -0
  10. package/dist/cli/commands/audit.js +125 -0
  11. package/dist/cli/commands/hooks.js +29 -6
  12. package/dist/cli/commands/init.js +1 -73
  13. package/dist/cli/commands/learning.js +270 -13
  14. package/dist/cli/commands/ruvector-commands.d.ts +15 -0
  15. package/dist/cli/commands/ruvector-commands.js +271 -0
  16. package/dist/cli/handlers/init-handler.d.ts +0 -1
  17. package/dist/cli/handlers/init-handler.js +0 -6
  18. package/dist/cli/index.js +4 -2
  19. package/dist/context/sources/defect-source.js +2 -2
  20. package/dist/context/sources/memory-source.js +2 -2
  21. package/dist/context/sources/requirements-source.js +2 -2
  22. package/dist/coordination/behavior-tree/decorators.d.ts +108 -0
  23. package/dist/coordination/behavior-tree/decorators.js +251 -0
  24. package/dist/coordination/behavior-tree/index.d.ts +12 -0
  25. package/dist/coordination/behavior-tree/index.js +15 -0
  26. package/dist/coordination/behavior-tree/nodes.d.ts +165 -0
  27. package/dist/coordination/behavior-tree/nodes.js +338 -0
  28. package/dist/coordination/behavior-tree/qe-trees.d.ts +105 -0
  29. package/dist/coordination/behavior-tree/qe-trees.js +181 -0
  30. package/dist/coordination/coherence-action-gate.d.ts +284 -0
  31. package/dist/coordination/coherence-action-gate.js +512 -0
  32. package/dist/coordination/index.d.ts +4 -0
  33. package/dist/coordination/index.js +8 -0
  34. package/dist/coordination/reasoning-qec.d.ts +315 -0
  35. package/dist/coordination/reasoning-qec.js +585 -0
  36. package/dist/coordination/task-executor.d.ts +16 -0
  37. package/dist/coordination/task-executor.js +99 -0
  38. package/dist/coordination/workflow-orchestrator.d.ts +29 -0
  39. package/dist/coordination/workflow-orchestrator.js +42 -0
  40. package/dist/domains/visual-accessibility/cnn-visual-regression.d.ts +135 -0
  41. package/dist/domains/visual-accessibility/cnn-visual-regression.js +327 -0
  42. package/dist/domains/visual-accessibility/index.d.ts +1 -0
  43. package/dist/domains/visual-accessibility/index.js +4 -0
  44. package/dist/governance/coherence-validator.d.ts +112 -0
  45. package/dist/governance/coherence-validator.js +180 -0
  46. package/dist/governance/index.d.ts +1 -0
  47. package/dist/governance/index.js +2 -0
  48. package/dist/governance/witness-chain.d.ts +311 -0
  49. package/dist/governance/witness-chain.js +509 -0
  50. package/dist/init/index.d.ts +0 -2
  51. package/dist/init/index.js +0 -1
  52. package/dist/init/init-wizard-steps.d.ts +10 -0
  53. package/dist/init/init-wizard-steps.js +87 -1
  54. package/dist/init/init-wizard.d.ts +1 -9
  55. package/dist/init/init-wizard.js +3 -69
  56. package/dist/init/orchestrator.js +0 -1
  57. package/dist/init/phases/01-detection.js +0 -27
  58. package/dist/init/phases/07-hooks.js +6 -4
  59. package/dist/init/phases/phase-interface.d.ts +0 -1
  60. package/dist/init/settings-merge.js +1 -1
  61. package/dist/integrations/browser/qe-dashboard/clustering.d.ts +48 -0
  62. package/dist/integrations/browser/qe-dashboard/clustering.js +183 -0
  63. package/dist/integrations/browser/qe-dashboard/index.d.ts +12 -0
  64. package/dist/integrations/browser/qe-dashboard/index.js +15 -0
  65. package/dist/integrations/browser/qe-dashboard/pattern-explorer.d.ts +165 -0
  66. package/dist/integrations/browser/qe-dashboard/pattern-explorer.js +260 -0
  67. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.d.ts +144 -0
  68. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +277 -0
  69. package/dist/integrations/ruvector/cognitive-container-codec.d.ts +51 -0
  70. package/dist/integrations/ruvector/cognitive-container-codec.js +180 -0
  71. package/dist/integrations/ruvector/cognitive-container.d.ts +125 -0
  72. package/dist/integrations/ruvector/cognitive-container.js +306 -0
  73. package/dist/integrations/ruvector/coherence-gate.d.ts +309 -0
  74. package/dist/integrations/ruvector/coherence-gate.js +631 -0
  75. package/dist/integrations/ruvector/compressed-hnsw-integration.d.ts +176 -0
  76. package/dist/integrations/ruvector/compressed-hnsw-integration.js +301 -0
  77. package/dist/integrations/ruvector/dither-adapter.d.ts +122 -0
  78. package/dist/integrations/ruvector/dither-adapter.js +295 -0
  79. package/dist/integrations/ruvector/domain-transfer.d.ts +129 -0
  80. package/dist/integrations/ruvector/domain-transfer.js +220 -0
  81. package/dist/integrations/ruvector/feature-flags.d.ts +214 -2
  82. package/dist/integrations/ruvector/feature-flags.js +167 -2
  83. package/dist/integrations/ruvector/filter-adapter.d.ts +71 -0
  84. package/dist/integrations/ruvector/filter-adapter.js +285 -0
  85. package/dist/integrations/ruvector/gnn-wrapper.d.ts +20 -0
  86. package/dist/integrations/ruvector/gnn-wrapper.js +40 -0
  87. package/dist/integrations/ruvector/hnsw-health-monitor.d.ts +237 -0
  88. package/dist/integrations/ruvector/hnsw-health-monitor.js +394 -0
  89. package/dist/integrations/ruvector/index.d.ts +8 -2
  90. package/dist/integrations/ruvector/index.js +18 -2
  91. package/dist/integrations/ruvector/interfaces.d.ts +40 -0
  92. package/dist/integrations/ruvector/sona-persistence.d.ts +54 -0
  93. package/dist/integrations/ruvector/sona-persistence.js +162 -0
  94. package/dist/integrations/ruvector/sona-three-loop.d.ts +392 -0
  95. package/dist/integrations/ruvector/sona-three-loop.js +814 -0
  96. package/dist/integrations/ruvector/sona-wrapper.d.ts +97 -0
  97. package/dist/integrations/ruvector/sona-wrapper.js +147 -3
  98. package/dist/integrations/ruvector/spectral-math.d.ts +101 -0
  99. package/dist/integrations/ruvector/spectral-math.js +254 -0
  100. package/dist/integrations/ruvector/temporal-compression.d.ts +163 -0
  101. package/dist/integrations/ruvector/temporal-compression.js +318 -0
  102. package/dist/integrations/ruvector/thompson-sampler.d.ts +61 -0
  103. package/dist/integrations/ruvector/thompson-sampler.js +118 -0
  104. package/dist/integrations/ruvector/transfer-coherence-stub.d.ts +80 -0
  105. package/dist/integrations/ruvector/transfer-coherence-stub.js +63 -0
  106. package/dist/integrations/ruvector/transfer-verification.d.ts +119 -0
  107. package/dist/integrations/ruvector/transfer-verification.js +115 -0
  108. package/dist/kernel/hnsw-adapter.d.ts +52 -1
  109. package/dist/kernel/hnsw-adapter.js +139 -4
  110. package/dist/kernel/hnsw-index-provider.d.ts +5 -0
  111. package/dist/kernel/native-hnsw-backend.d.ts +110 -0
  112. package/dist/kernel/native-hnsw-backend.js +408 -0
  113. package/dist/kernel/unified-memory.js +5 -6
  114. package/dist/learning/aqe-learning-engine.d.ts +2 -0
  115. package/dist/learning/aqe-learning-engine.js +65 -0
  116. package/dist/learning/experience-capture-middleware.js +20 -0
  117. package/dist/learning/experience-capture.d.ts +10 -0
  118. package/dist/learning/experience-capture.js +34 -0
  119. package/dist/learning/index.d.ts +2 -2
  120. package/dist/learning/index.js +4 -4
  121. package/dist/learning/metrics-tracker.d.ts +11 -0
  122. package/dist/learning/metrics-tracker.js +29 -13
  123. package/dist/learning/pattern-lifecycle.d.ts +30 -1
  124. package/dist/learning/pattern-lifecycle.js +92 -20
  125. package/dist/learning/pattern-store.d.ts +8 -0
  126. package/dist/learning/pattern-store.js +8 -2
  127. package/dist/learning/qe-unified-memory.js +1 -28
  128. package/dist/learning/regret-tracker.d.ts +201 -0
  129. package/dist/learning/regret-tracker.js +361 -0
  130. package/dist/mcp/bundle.js +5915 -474
  131. package/dist/routing/index.d.ts +4 -2
  132. package/dist/routing/index.js +3 -1
  133. package/dist/routing/neural-tiny-dancer-router.d.ts +268 -0
  134. package/dist/routing/neural-tiny-dancer-router.js +514 -0
  135. package/dist/routing/queen-integration.js +5 -5
  136. package/dist/routing/routing-config.d.ts +6 -0
  137. package/dist/routing/routing-config.js +1 -0
  138. package/dist/routing/simple-neural-router.d.ts +76 -0
  139. package/dist/routing/simple-neural-router.js +202 -0
  140. package/dist/routing/tiny-dancer-router.d.ts +20 -1
  141. package/dist/routing/tiny-dancer-router.js +21 -2
  142. package/dist/test-scheduling/dag-attention-scheduler.d.ts +81 -0
  143. package/dist/test-scheduling/dag-attention-scheduler.js +358 -0
  144. package/dist/test-scheduling/dag-attention-types.d.ts +81 -0
  145. package/dist/test-scheduling/dag-attention-types.js +10 -0
  146. package/dist/test-scheduling/index.d.ts +1 -0
  147. package/dist/test-scheduling/index.js +4 -0
  148. package/dist/test-scheduling/pipeline.d.ts +8 -0
  149. package/dist/test-scheduling/pipeline.js +28 -0
  150. package/package.json +6 -2
  151. package/dist/cli/commands/migrate.d.ts +0 -9
  152. package/dist/cli/commands/migrate.js +0 -566
  153. package/dist/init/init-wizard-migration.d.ts +0 -52
  154. package/dist/init/init-wizard-migration.js +0 -345
  155. package/dist/init/migration/config-migrator.d.ts +0 -31
  156. package/dist/init/migration/config-migrator.js +0 -149
  157. package/dist/init/migration/data-migrator.d.ts +0 -72
  158. package/dist/init/migration/data-migrator.js +0 -232
  159. package/dist/init/migration/detector.d.ts +0 -44
  160. package/dist/init/migration/detector.js +0 -105
  161. package/dist/init/migration/index.d.ts +0 -8
  162. package/dist/init/migration/index.js +0 -8
  163. package/dist/learning/v2-to-v3-migration.d.ts +0 -86
  164. package/dist/learning/v2-to-v3-migration.js +0 -529
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Agentic QE v3 - RuVector Metadata Filtering Adapter
3
+ * Task 1.2: Metadata Filtering Layer (ruvector-filter)
4
+ *
5
+ * Provides composable filter expressions (AND/OR/NOT/FIELD) that can be
6
+ * applied to pattern search results for rich post-search filtering.
7
+ *
8
+ * TypeScript in-memory implementation (no native package exists).
9
+ * Backward compatible: no filter = no change to search results.
10
+ *
11
+ * @module integrations/ruvector/filter-adapter
12
+ */
13
+ import { getRuVectorFeatureFlags } from './feature-flags.js';
14
+ let nativeEngine = null;
15
+ let nativeChecked = false;
16
+ /**
17
+ * Check for native filter engine.
18
+ * No native package exists — always returns null.
19
+ * The TypeScript implementation is the production implementation.
20
+ */
21
+ async function loadNativeEngine() {
22
+ if (nativeChecked)
23
+ return nativeEngine;
24
+ nativeChecked = true;
25
+ nativeEngine = null;
26
+ return null;
27
+ }
28
+ // ============================================================================
29
+ // Filter Builder Helpers
30
+ // ============================================================================
31
+ /**
32
+ * Create an AND filter combining multiple sub-expressions
33
+ */
34
+ export function and(...children) {
35
+ return { type: 'AND', children };
36
+ }
37
+ /**
38
+ * Create an OR filter combining multiple sub-expressions
39
+ */
40
+ export function or(...children) {
41
+ return { type: 'OR', children };
42
+ }
43
+ /**
44
+ * Create a NOT filter inverting a sub-expression
45
+ */
46
+ export function not(child) {
47
+ return { type: 'NOT', child };
48
+ }
49
+ /**
50
+ * Create a field-level filter expression
51
+ */
52
+ export function field(fieldName, operator, value) {
53
+ return { type: 'FIELD', field: fieldName, operator, value };
54
+ }
55
+ // ============================================================================
56
+ // TypeScript Fallback Filter Engine
57
+ // ============================================================================
58
+ /**
59
+ * Resolve a nested field path (e.g., "context.tags") on a PatternSearchResult.
60
+ * Looks first on the pattern object, then on the result itself.
61
+ */
62
+ function resolveField(result, fieldPath) {
63
+ const pattern = result.pattern;
64
+ // Try pattern first, then result-level fields
65
+ const targets = [pattern, result];
66
+ for (const target of targets) {
67
+ const parts = fieldPath.split('.');
68
+ let current = target;
69
+ for (const part of parts) {
70
+ if (current === null || current === undefined)
71
+ break;
72
+ if (typeof current === 'object') {
73
+ current = current[part];
74
+ }
75
+ else {
76
+ current = undefined;
77
+ break;
78
+ }
79
+ }
80
+ if (current !== undefined)
81
+ return current;
82
+ }
83
+ return undefined;
84
+ }
85
+ /**
86
+ * Evaluate a single FIELD filter against a resolved value
87
+ */
88
+ function evaluateFieldFilter(resolvedValue, operator, filterValue) {
89
+ switch (operator) {
90
+ case 'eq':
91
+ return resolvedValue === filterValue;
92
+ case 'gt':
93
+ return (typeof resolvedValue === 'number' &&
94
+ typeof filterValue === 'number' &&
95
+ resolvedValue > filterValue);
96
+ case 'lt':
97
+ return (typeof resolvedValue === 'number' &&
98
+ typeof filterValue === 'number' &&
99
+ resolvedValue < filterValue);
100
+ case 'gte':
101
+ return (typeof resolvedValue === 'number' &&
102
+ typeof filterValue === 'number' &&
103
+ resolvedValue >= filterValue);
104
+ case 'lte':
105
+ return (typeof resolvedValue === 'number' &&
106
+ typeof filterValue === 'number' &&
107
+ resolvedValue <= filterValue);
108
+ case 'in': {
109
+ if (!Array.isArray(filterValue))
110
+ return false;
111
+ return filterValue.includes(resolvedValue);
112
+ }
113
+ case 'contains': {
114
+ // Array.includes or string.includes
115
+ if (Array.isArray(resolvedValue)) {
116
+ return resolvedValue.includes(filterValue);
117
+ }
118
+ if (typeof resolvedValue === 'string' && typeof filterValue === 'string') {
119
+ return resolvedValue.includes(filterValue);
120
+ }
121
+ return false;
122
+ }
123
+ case 'between': {
124
+ if (typeof resolvedValue !== 'number' ||
125
+ !Array.isArray(filterValue) ||
126
+ filterValue.length !== 2) {
127
+ // Also support Date-based between
128
+ if (resolvedValue instanceof Date && Array.isArray(filterValue) && filterValue.length === 2) {
129
+ const ts = resolvedValue.getTime();
130
+ const lo = filterValue[0] instanceof Date ? filterValue[0].getTime() : Number(filterValue[0]);
131
+ const hi = filterValue[1] instanceof Date ? filterValue[1].getTime() : Number(filterValue[1]);
132
+ return ts >= lo && ts <= hi;
133
+ }
134
+ return false;
135
+ }
136
+ const [lo, hi] = filterValue;
137
+ return resolvedValue >= lo && resolvedValue <= hi;
138
+ }
139
+ default:
140
+ return false;
141
+ }
142
+ }
143
+ /**
144
+ * Evaluate a filter expression against a single search result.
145
+ * Returns true if the result passes the filter.
146
+ */
147
+ export function evaluateFilter(result, filter) {
148
+ switch (filter.type) {
149
+ case 'AND': {
150
+ const children = filter.children ?? [];
151
+ return children.every((child) => evaluateFilter(result, child));
152
+ }
153
+ case 'OR': {
154
+ const children = filter.children ?? [];
155
+ if (children.length === 0)
156
+ return true;
157
+ return children.some((child) => evaluateFilter(result, child));
158
+ }
159
+ case 'NOT': {
160
+ if (!filter.child)
161
+ return true;
162
+ return !evaluateFilter(result, filter.child);
163
+ }
164
+ case 'FIELD': {
165
+ if (!filter.field || !filter.operator)
166
+ return true;
167
+ const resolved = resolveField(result, filter.field);
168
+ return evaluateFieldFilter(resolved, filter.operator, filter.value);
169
+ }
170
+ default:
171
+ return true;
172
+ }
173
+ }
174
+ // ============================================================================
175
+ // Public API
176
+ // ============================================================================
177
+ /**
178
+ * Apply a filter expression to pattern search results.
179
+ *
180
+ * If the `useMetadataFiltering` feature flag is disabled, returns results unchanged.
181
+ * If the native `ruvector-filter` engine is available, delegates to it.
182
+ * Otherwise, applies the TypeScript fallback engine.
183
+ *
184
+ * @param results - Pattern search results to filter
185
+ * @param filter - Composable filter expression
186
+ * @returns Filtered results (subset of input, order preserved)
187
+ */
188
+ export async function applyFilter(results, filter) {
189
+ // No filter = passthrough
190
+ if (!filter)
191
+ return results;
192
+ // Check feature flag
193
+ const flags = getRuVectorFeatureFlags();
194
+ if (!flags.useMetadataFiltering)
195
+ return results;
196
+ // Try native engine first
197
+ const native = await loadNativeEngine();
198
+ if (native) {
199
+ return native.applyFilter(results, filter);
200
+ }
201
+ // TypeScript fallback: in-memory filtering
202
+ return applyFilterSync(results, filter);
203
+ }
204
+ /**
205
+ * Synchronous version of applyFilter using the TypeScript fallback engine.
206
+ * Useful when native engine availability is already known to be absent.
207
+ *
208
+ * @param results - Pattern search results to filter
209
+ * @param filter - Composable filter expression
210
+ * @returns Filtered results (subset of input, order preserved)
211
+ */
212
+ export function applyFilterSync(results, filter) {
213
+ if (!filter)
214
+ return results;
215
+ return results.filter((result) => evaluateFilter(result, filter));
216
+ }
217
+ /**
218
+ * Validate a filter expression for structural correctness.
219
+ *
220
+ * @param filter - Filter expression to validate
221
+ * @returns Validation result with error messages
222
+ */
223
+ export function validateFilter(filter) {
224
+ const errors = [];
225
+ if (!filter.type) {
226
+ errors.push('Filter must have a type');
227
+ return { valid: false, errors };
228
+ }
229
+ const validTypes = ['AND', 'OR', 'NOT', 'FIELD'];
230
+ if (!validTypes.includes(filter.type)) {
231
+ errors.push(`Invalid filter type: ${filter.type}. Must be one of: ${validTypes.join(', ')}`);
232
+ }
233
+ if (filter.type === 'AND' || filter.type === 'OR') {
234
+ if (!filter.children || !Array.isArray(filter.children)) {
235
+ errors.push(`${filter.type} filter must have a 'children' array`);
236
+ }
237
+ else {
238
+ for (let i = 0; i < filter.children.length; i++) {
239
+ const childResult = validateFilter(filter.children[i]);
240
+ if (!childResult.valid) {
241
+ errors.push(...childResult.errors.map((e) => `${filter.type}.children[${i}]: ${e}`));
242
+ }
243
+ }
244
+ }
245
+ }
246
+ if (filter.type === 'NOT') {
247
+ if (!filter.child) {
248
+ errors.push("NOT filter must have a 'child' expression");
249
+ }
250
+ else {
251
+ const childResult = validateFilter(filter.child);
252
+ if (!childResult.valid) {
253
+ errors.push(...childResult.errors.map((e) => `NOT.child: ${e}`));
254
+ }
255
+ }
256
+ }
257
+ if (filter.type === 'FIELD') {
258
+ if (!filter.field) {
259
+ errors.push("FIELD filter must have a 'field' property");
260
+ }
261
+ if (!filter.operator) {
262
+ errors.push("FIELD filter must have an 'operator' property");
263
+ }
264
+ else {
265
+ const validOps = [
266
+ 'eq', 'gt', 'lt', 'gte', 'lte', 'in', 'contains', 'between',
267
+ ];
268
+ if (!validOps.includes(filter.operator)) {
269
+ errors.push(`Invalid operator: ${filter.operator}. Must be one of: ${validOps.join(', ')}`);
270
+ }
271
+ }
272
+ }
273
+ return { valid: errors.length === 0, errors };
274
+ }
275
+ // ============================================================================
276
+ // Reset (for testing)
277
+ // ============================================================================
278
+ /**
279
+ * Reset native engine state (for testing only)
280
+ */
281
+ export function resetNativeEngine() {
282
+ nativeEngine = null;
283
+ nativeChecked = false;
284
+ }
285
+ //# sourceMappingURL=filter-adapter.js.map
@@ -8,6 +8,7 @@
8
8
  * @module integrations/ruvector/gnn-wrapper
9
9
  */
10
10
  import type { IEmbedding, IHNSWConfig, EmbeddingNamespace, ISearchOptions } from '../embeddings/base/types';
11
+ import type { DitheredResult, DitherOptions } from './dither-adapter.js';
11
12
  /** Check if native GNN module is available */
12
13
  export declare function isGNNAvailable(): boolean;
13
14
  /** CompressionLevelConfig type compatible with @ruvector/gnn */
@@ -239,6 +240,25 @@ export declare class TensorCompressionFactory {
239
240
  * Get compression level for frequency
240
241
  */
241
242
  static getLevel(accessFreq: number): QECompressionLevel;
243
+ /**
244
+ * Compress tensor with optional deterministic dithering (Task 1.4)
245
+ *
246
+ * When the `useDeterministicDither` feature flag is enabled, applies
247
+ * golden-ratio dithered quantization as a post-processing step before
248
+ * passing to the native compressor. This improves reconstruction quality
249
+ * at low bit depths while guaranteeing cross-platform reproducibility.
250
+ *
251
+ * When the flag is disabled, behaves identically to `compressWithLevel`.
252
+ *
253
+ * @param embedding - Raw embedding vector
254
+ * @param level - Compression level
255
+ * @param ditherOptions - Optional dither configuration (seed, bitDepth override)
256
+ * @returns Compressed data string, optionally with dither metadata
257
+ */
258
+ static compressWithDither(embedding: number[] | Float32Array, level: QECompressionLevel, ditherOptions?: Partial<DitherOptions>): {
259
+ compressed: string;
260
+ ditherResult?: DitheredResult;
261
+ };
242
262
  }
243
263
  export declare function getRuvectorLayer(): any;
244
264
  export declare function getTensorCompress(): any;
@@ -8,6 +8,8 @@
8
8
  * @module integrations/ruvector/gnn-wrapper
9
9
  */
10
10
  import { safeJsonParse } from '../../shared/safe-json.js';
11
+ import { isDeterministicDitherEnabled } from './feature-flags.js';
12
+ import { applyDither } from './dither-adapter.js';
11
13
  // Lazy-load @ruvector/gnn native bindings (may not be available on all platforms)
12
14
  // Follows the pattern in kernel/unified-memory-hnsw.ts (lines 22-35)
13
15
  let _RuvectorLayer = null;
@@ -483,6 +485,44 @@ export class TensorCompressionFactory {
483
485
  requireGNN();
484
486
  return _getCompressionLevel(accessFreq);
485
487
  }
488
+ /**
489
+ * Compress tensor with optional deterministic dithering (Task 1.4)
490
+ *
491
+ * When the `useDeterministicDither` feature flag is enabled, applies
492
+ * golden-ratio dithered quantization as a post-processing step before
493
+ * passing to the native compressor. This improves reconstruction quality
494
+ * at low bit depths while guaranteeing cross-platform reproducibility.
495
+ *
496
+ * When the flag is disabled, behaves identically to `compressWithLevel`.
497
+ *
498
+ * @param embedding - Raw embedding vector
499
+ * @param level - Compression level
500
+ * @param ditherOptions - Optional dither configuration (seed, bitDepth override)
501
+ * @returns Compressed data string, optionally with dither metadata
502
+ */
503
+ static compressWithDither(embedding, level, ditherOptions) {
504
+ const embeddingFloat32 = embedding instanceof Float32Array
505
+ ? embedding
506
+ : new Float32Array(embedding);
507
+ // Apply dithering if feature flag is enabled
508
+ let ditherResult;
509
+ if (isDeterministicDitherEnabled()) {
510
+ // Map compression level to a default bit depth
511
+ const bitDepthMap = {
512
+ 'none': 32,
513
+ 'half': 16,
514
+ 'pq8': 8,
515
+ 'pq4': 4,
516
+ 'binary': 1,
517
+ };
518
+ const bitDepth = ditherOptions?.bitDepth ?? bitDepthMap[level] ?? 8;
519
+ const seed = ditherOptions?.seed ?? 0;
520
+ ditherResult = applyDither(embeddingFloat32, bitDepth, seed);
521
+ }
522
+ // Compress using the standard path (native compressor)
523
+ const compressed = this.compressWithLevel(ditherResult ? ditherResult.dequantized : embedding, level);
524
+ return { compressed, ditherResult };
525
+ }
486
526
  }
487
527
  // ============================================================================
488
528
  // Re-exports from @ruvector/gnn for advanced users
@@ -0,0 +1,237 @@
1
+ /**
2
+ * HNSW Health Monitor - Spectral Health Monitoring
3
+ *
4
+ * Monitors the structural health of HNSW indexes using spectral graph
5
+ * theory metrics. Computes Fiedler value (algebraic connectivity),
6
+ * spectral gap, effective resistance, and a combined coherence score.
7
+ *
8
+ * Uses TypeScript power iteration and sample-based estimation for
9
+ * spectral computation. No native package exists for this — the
10
+ * TypeScript implementation is the production implementation.
11
+ *
12
+ * @see Task 3.4: HNSW Health Monitoring
13
+ * @module integrations/ruvector/hnsw-health-monitor
14
+ */
15
+ import type { IHnswIndexProvider } from '../../kernel/hnsw-index-provider.js';
16
+ export { buildLaplacian, laplacianMultiply, vectorNorm, normalizeInPlace, deflateVector, approximateFiedlerValue, approximateSpectralGap, estimateEffectiveResistance, computeCoherenceScore, } from './spectral-math.js';
17
+ /**
18
+ * Alert types generated when health metrics exceed thresholds.
19
+ */
20
+ export type HealthAlertType = 'FragileIndex' | 'PoorExpansion' | 'HighResistance' | 'LowCoherence';
21
+ /**
22
+ * A single health alert with context.
23
+ */
24
+ export interface HealthAlert {
25
+ /** Alert classification */
26
+ readonly type: HealthAlertType;
27
+ /** Human-readable description */
28
+ readonly message: string;
29
+ /** The metric value that triggered the alert */
30
+ readonly value: number;
31
+ /** The threshold that was exceeded */
32
+ readonly threshold: number;
33
+ /** When the alert was generated */
34
+ readonly timestamp: Date;
35
+ }
36
+ /**
37
+ * Spectral health metrics for an HNSW index.
38
+ */
39
+ export interface SpectralMetrics {
40
+ /** Second smallest eigenvalue of graph Laplacian (algebraic connectivity) */
41
+ readonly fiedlerValue: number;
42
+ /** Difference between 2nd and 1st eigenvalues (expansion quality) */
43
+ readonly spectralGap: number;
44
+ /** Average resistance distance between sampled node pairs */
45
+ readonly effectiveResistance: number;
46
+ /** Combined health metric (0-1, higher = healthier) */
47
+ readonly coherenceScore: number;
48
+ }
49
+ /**
50
+ * Full health report for an HNSW index.
51
+ */
52
+ export interface HnswHealthReport {
53
+ /** Whether the index is considered healthy */
54
+ readonly healthy: boolean;
55
+ /** Spectral health metrics */
56
+ readonly metrics: SpectralMetrics;
57
+ /** Active alerts (empty if healthy) */
58
+ readonly alerts: HealthAlert[];
59
+ /** Number of vectors in the index */
60
+ readonly indexSize: number;
61
+ /** Whether native ruvector-coherence was used */
62
+ readonly usedNativeBackend: boolean;
63
+ /** Whether adjacency was built from actual search or circular approximation */
64
+ readonly adjacencySource: 'actual-search' | 'approximate';
65
+ /** Time taken for the health check in ms */
66
+ readonly checkDurationMs: number;
67
+ /** When the check was performed */
68
+ readonly checkedAt: Date;
69
+ }
70
+ /**
71
+ * A timestamped health metric point for history tracking.
72
+ */
73
+ export interface HealthMetricPoint {
74
+ /** Coherence score at this point */
75
+ readonly coherenceScore: number;
76
+ /** Fiedler value at this point */
77
+ readonly fiedlerValue: number;
78
+ /** Index size at measurement time */
79
+ readonly indexSize: number;
80
+ /** Whether the index was healthy */
81
+ readonly healthy: boolean;
82
+ /** Timestamp of measurement */
83
+ readonly timestamp: Date;
84
+ }
85
+ /**
86
+ * Configuration for the HNSW health monitor.
87
+ */
88
+ export interface HnswHealthMonitorConfig {
89
+ /** Fiedler value threshold for FragileIndex alert (default: 0.01) */
90
+ readonly fiedlerThreshold: number;
91
+ /** Spectral gap threshold for PoorExpansion alert (default: 0.1) */
92
+ readonly spectralGapThreshold: number;
93
+ /** Effective resistance threshold for HighResistance alert (default: 10.0) */
94
+ readonly resistanceThreshold: number;
95
+ /** Coherence score threshold for LowCoherence alert (default: 0.3) */
96
+ readonly coherenceThreshold: number;
97
+ /** Maximum iterations for power iteration (default: 100) */
98
+ readonly maxPowerIterations: number;
99
+ /** Convergence tolerance for power iteration (default: 1e-6) */
100
+ readonly convergenceTolerance: number;
101
+ /** Number of node pairs to sample for resistance estimation (default: 50) */
102
+ readonly resistanceSampleSize: number;
103
+ /** Maximum history entries to retain (default: 200) */
104
+ readonly maxHistoryEntries: number;
105
+ /** Minimum index size for meaningful spectral analysis (default: 3) */
106
+ readonly minIndexSize: number;
107
+ }
108
+ /**
109
+ * Default health monitor configuration.
110
+ */
111
+ export declare const DEFAULT_HNSW_HEALTH_CONFIG: HnswHealthMonitorConfig;
112
+ export declare const ALERT_THRESHOLDS: {
113
+ readonly FragileIndex: 0.01;
114
+ readonly PoorExpansion: 0.1;
115
+ readonly HighResistance: 10;
116
+ readonly LowCoherence: 0.3;
117
+ };
118
+ /** Reset native loader state (for testing) */
119
+ export declare function _resetNativeLoader(): void;
120
+ /**
121
+ * Result from building adjacency from an HNSW index.
122
+ */
123
+ export interface AdjacencyResult {
124
+ /** Adjacency list for the graph */
125
+ adjacency: number[][];
126
+ /** Number of nodes in the graph */
127
+ nodeCount: number;
128
+ /** Whether adjacency was built from actual search or circular approximation */
129
+ adjacencySource: 'actual-search' | 'approximate';
130
+ }
131
+ /**
132
+ * Build an adjacency list from an HNSW-like index by using similarity
133
+ * between stored vectors. When stored vectors are provided, each vector
134
+ * is searched against the index to discover real neighbors. Otherwise,
135
+ * falls back to a circular approximation.
136
+ *
137
+ * @param index - The HNSW index provider
138
+ * @param maxNeighbors - Maximum neighbors per node to consider
139
+ * @param storedVectors - Optional map of id to vector for real neighbor discovery
140
+ * @returns Adjacency list, node count, and adjacency source
141
+ */
142
+ export declare function buildAdjacencyFromIndex(index: IHnswIndexProvider, maxNeighbors?: number, storedVectors?: Map<number, Float32Array>): AdjacencyResult;
143
+ /**
144
+ * HNSW Health Monitor
145
+ *
146
+ * Monitors the spectral health of HNSW indexes by computing graph-theoretic
147
+ * metrics. Uses ruvector-coherence for native computation when available,
148
+ * falling back to TypeScript approximations.
149
+ *
150
+ * Health checks are designed to be lightweight enough for periodic use
151
+ * without blocking search operations.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const monitor = new HnswHealthMonitor();
156
+ * const report = monitor.checkHealth(hnswIndex);
157
+ * if (!report.healthy) {
158
+ * console.warn('HNSW index unhealthy:', report.alerts);
159
+ * }
160
+ * ```
161
+ */
162
+ export declare class HnswHealthMonitor {
163
+ private readonly config;
164
+ private readonly alerts;
165
+ private readonly history;
166
+ private lastReport;
167
+ private useNative;
168
+ private nativeChecked;
169
+ constructor(config?: Partial<HnswHealthMonitorConfig>);
170
+ /**
171
+ * Perform a health check on an HNSW index.
172
+ *
173
+ * Computes spectral metrics and generates alerts if thresholds are
174
+ * exceeded. Results are recorded in the metrics history.
175
+ *
176
+ * @param index - The HNSW index to check
177
+ * @returns Health report with metrics and alerts
178
+ */
179
+ checkHealth(index: IHnswIndexProvider): HnswHealthReport;
180
+ /**
181
+ * Get current active alerts.
182
+ *
183
+ * @returns Array of active health alerts
184
+ */
185
+ getAlerts(): HealthAlert[];
186
+ /**
187
+ * Get health metrics history.
188
+ *
189
+ * @param limit - Maximum entries to return (most recent)
190
+ * @returns Array of metric points, most recent last
191
+ */
192
+ getMetricsHistory(limit?: number): HealthMetricPoint[];
193
+ /**
194
+ * Check whether the index is currently healthy (no alerts).
195
+ *
196
+ * If no health check has been performed yet, returns true (optimistic).
197
+ *
198
+ * @returns true if the last health check found no alerts
199
+ */
200
+ isHealthy(): boolean;
201
+ /**
202
+ * Get the last health report, or null if no check has been performed.
203
+ */
204
+ getLastReport(): HnswHealthReport | null;
205
+ /**
206
+ * Clear all history and alerts.
207
+ */
208
+ clearHistory(): void;
209
+ /**
210
+ * Compute metrics using the native ruvector-coherence module.
211
+ */
212
+ private computeNativeMetrics;
213
+ /**
214
+ * Compute metrics using TypeScript approximations.
215
+ */
216
+ private computeApproximateMetrics;
217
+ /**
218
+ * Generate alerts based on metric thresholds.
219
+ */
220
+ private generateAlerts;
221
+ /**
222
+ * Create a report for indexes too small for spectral analysis.
223
+ */
224
+ private createSmallIndexReport;
225
+ /**
226
+ * Add a history point, trimming if over limit.
227
+ */
228
+ private addHistoryPoint;
229
+ }
230
+ /**
231
+ * Create an HnswHealthMonitor instance.
232
+ *
233
+ * @param config - Optional configuration overrides
234
+ * @returns A new HnswHealthMonitor
235
+ */
236
+ export declare function createHnswHealthMonitor(config?: Partial<HnswHealthMonitorConfig>): HnswHealthMonitor;
237
+ //# sourceMappingURL=hnsw-health-monitor.d.ts.map