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,176 @@
1
+ /**
2
+ * Compressed HNSW Integration
3
+ * ADR-085: Temporal Tensor Pattern Compression + HNSW Backend
4
+ *
5
+ * Wraps an IHnswIndexProvider to transparently handle compressed vectors.
6
+ * On add(), the original vector is passed to the underlying HNSW index for
7
+ * accurate search, while a compressed copy is stored for memory savings.
8
+ * On search(), results come from the HNSW index normally.
9
+ *
10
+ * The compressIndex() method bulk-compresses cold/warm vectors, and
11
+ * getMemoryStats() reports the savings achieved.
12
+ *
13
+ * Activation is controlled by the `useTemporalCompression` feature flag.
14
+ *
15
+ * @module integrations/ruvector/compressed-hnsw-integration
16
+ */
17
+ import type { IHnswIndexProvider, SearchResult } from '../../kernel/hnsw-index-provider.js';
18
+ import type { CompressionTier } from './temporal-compression.js';
19
+ import { TemporalCompressionService } from './temporal-compression.js';
20
+ /**
21
+ * Memory statistics for the compressed HNSW index.
22
+ */
23
+ export interface CompressedHnswMemoryStats {
24
+ /** Total vectors in the index */
25
+ totalVectors: number;
26
+ /** Vectors that are still uncompressed */
27
+ uncompressedCount: number;
28
+ /** Vectors that have been compressed */
29
+ compressedCount: number;
30
+ /** Breakdown of compressed vectors by tier */
31
+ compressedByTier: Record<CompressionTier, number>;
32
+ /** Total bytes used by original (uncompressed) vectors */
33
+ originalBytes: number;
34
+ /** Total bytes used by compressed vectors (effective) */
35
+ compressedBytes: number;
36
+ /** Total bytes saved through compression */
37
+ bytesSaved: number;
38
+ /** Savings as a percentage (0-100) */
39
+ savingsPercent: number;
40
+ /** Whether temporal compression is enabled via feature flag */
41
+ compressionEnabled: boolean;
42
+ }
43
+ /**
44
+ * Wrapper around IHnswIndexProvider that transparently manages compressed
45
+ * vector storage alongside the HNSW index.
46
+ *
47
+ * The HNSW index always receives full-precision vectors for accurate search.
48
+ * Compression is a separate memory-optimization layer that stores compact
49
+ * representations of vectors that can be decompressed on demand.
50
+ *
51
+ * Usage:
52
+ * ```typescript
53
+ * const baseIndex = new ProgressiveHnswBackend({ dimensions: 384 });
54
+ * const compressed = new CompressedHnswIntegration(baseIndex);
55
+ *
56
+ * compressed.add(1, embedding, { domain: 'auth' });
57
+ * const results = compressed.search(queryEmbedding, 10);
58
+ *
59
+ * // Compress cold vectors to save memory
60
+ * const stats = compressed.compressIndex();
61
+ * console.log(`Compressed ${stats.compressedCount} vectors`);
62
+ * ```
63
+ */
64
+ export declare class CompressedHnswIntegration implements IHnswIndexProvider {
65
+ private readonly backend;
66
+ private readonly compressionService;
67
+ private readonly vectorEntries;
68
+ /**
69
+ * Create a CompressedHnswIntegration.
70
+ *
71
+ * @param backend - The underlying HNSW index provider to delegate to
72
+ * @param compressionService - Optional compression service (defaults to new instance)
73
+ */
74
+ constructor(backend: IHnswIndexProvider, compressionService?: TemporalCompressionService);
75
+ /**
76
+ * Add a vector to the index.
77
+ *
78
+ * The full-precision vector is passed to the HNSW backend for search.
79
+ * A copy is stored locally for potential future compression.
80
+ * If temporal compression is enabled, the vector is also compressed
81
+ * immediately and the compressed form is stored.
82
+ */
83
+ add(id: number, vector: Float32Array, metadata?: Record<string, unknown>): void;
84
+ /**
85
+ * Search for the k nearest neighbors.
86
+ *
87
+ * Delegates entirely to the HNSW backend which holds full-precision
88
+ * vectors. Updates access timestamps for returned results so they
89
+ * stay in the hot tier.
90
+ */
91
+ search(query: Float32Array, k: number): SearchResult[];
92
+ /**
93
+ * Remove a vector from the index.
94
+ */
95
+ remove(id: number): boolean;
96
+ /**
97
+ * Get the number of vectors in the index.
98
+ */
99
+ size(): number;
100
+ /**
101
+ * Get the configured vector dimensions.
102
+ */
103
+ dimensions(): number;
104
+ /**
105
+ * Get estimated recall. Delegates to the underlying backend.
106
+ */
107
+ recall(): number;
108
+ /**
109
+ * Compress vectors in the index based on their access tier.
110
+ *
111
+ * Iterates over all stored vectors and compresses those classified as
112
+ * warm or cold. Hot vectors are left uncompressed for maximum fidelity.
113
+ * After compression, the original float32 data for warm/cold vectors
114
+ * is released to free memory (the HNSW backend still holds its own copy
115
+ * for search operations).
116
+ *
117
+ * @param options - Optional configuration
118
+ * @param options.compressHot - If true, also compress hot-tier vectors (default: false)
119
+ * @returns Statistics about the compression operation
120
+ */
121
+ compressIndex(options?: {
122
+ compressHot?: boolean;
123
+ }): CompressedHnswBulkResult;
124
+ /**
125
+ * Decompress and retrieve the vector for a given ID.
126
+ *
127
+ * Returns the original vector if still available, otherwise
128
+ * decompresses from the stored compressed form.
129
+ *
130
+ * @param id - The vector ID
131
+ * @returns The decompressed Float32Array, or null if not found
132
+ */
133
+ getVector(id: number): Float32Array | null;
134
+ /**
135
+ * Get the compression tier for a specific vector.
136
+ *
137
+ * @param id - The vector ID
138
+ * @returns The tier, or null if not found or not compressed
139
+ */
140
+ getVectorTier(id: number): CompressionTier | null;
141
+ /**
142
+ * Update the last-accessed timestamp for a vector.
143
+ * This affects which tier it falls into during the next compressIndex() call.
144
+ *
145
+ * @param id - The vector ID
146
+ * @param accessDate - The access date (defaults to now)
147
+ */
148
+ touchVector(id: number, accessDate?: Date): void;
149
+ /**
150
+ * Get memory usage statistics for the compressed index.
151
+ */
152
+ getMemoryStats(): CompressedHnswMemoryStats;
153
+ /**
154
+ * Get the underlying HNSW backend.
155
+ * Useful for accessing backend-specific methods (e.g., NativeHnswBackend.getMetrics()).
156
+ */
157
+ getBackend(): IHnswIndexProvider;
158
+ /**
159
+ * Get the compression service instance.
160
+ */
161
+ getCompressionService(): TemporalCompressionService;
162
+ }
163
+ /**
164
+ * Result of a bulk compression operation via compressIndex().
165
+ */
166
+ export interface CompressedHnswBulkResult {
167
+ /** Number of vectors compressed in this operation */
168
+ compressedCount: number;
169
+ /** Number of vectors skipped (already compressed or hot) */
170
+ skippedCount: number;
171
+ /** Bytes freed by releasing original vectors */
172
+ bytesFreed: number;
173
+ /** Breakdown of newly compressed vectors by tier */
174
+ byTier: Record<CompressionTier, number>;
175
+ }
176
+ //# sourceMappingURL=compressed-hnsw-integration.d.ts.map
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Compressed HNSW Integration
3
+ * ADR-085: Temporal Tensor Pattern Compression + HNSW Backend
4
+ *
5
+ * Wraps an IHnswIndexProvider to transparently handle compressed vectors.
6
+ * On add(), the original vector is passed to the underlying HNSW index for
7
+ * accurate search, while a compressed copy is stored for memory savings.
8
+ * On search(), results come from the HNSW index normally.
9
+ *
10
+ * The compressIndex() method bulk-compresses cold/warm vectors, and
11
+ * getMemoryStats() reports the savings achieved.
12
+ *
13
+ * Activation is controlled by the `useTemporalCompression` feature flag.
14
+ *
15
+ * @module integrations/ruvector/compressed-hnsw-integration
16
+ */
17
+ import { createTemporalCompressionService, } from './temporal-compression.js';
18
+ import { isTemporalCompressionEnabled } from './feature-flags.js';
19
+ import { LoggerFactory } from '../../logging/index.js';
20
+ const logger = LoggerFactory.create('compressed-hnsw');
21
+ // ============================================================================
22
+ // CompressedHnswIntegration
23
+ // ============================================================================
24
+ /**
25
+ * Wrapper around IHnswIndexProvider that transparently manages compressed
26
+ * vector storage alongside the HNSW index.
27
+ *
28
+ * The HNSW index always receives full-precision vectors for accurate search.
29
+ * Compression is a separate memory-optimization layer that stores compact
30
+ * representations of vectors that can be decompressed on demand.
31
+ *
32
+ * Usage:
33
+ * ```typescript
34
+ * const baseIndex = new ProgressiveHnswBackend({ dimensions: 384 });
35
+ * const compressed = new CompressedHnswIntegration(baseIndex);
36
+ *
37
+ * compressed.add(1, embedding, { domain: 'auth' });
38
+ * const results = compressed.search(queryEmbedding, 10);
39
+ *
40
+ * // Compress cold vectors to save memory
41
+ * const stats = compressed.compressIndex();
42
+ * console.log(`Compressed ${stats.compressedCount} vectors`);
43
+ * ```
44
+ */
45
+ export class CompressedHnswIntegration {
46
+ backend;
47
+ compressionService;
48
+ vectorEntries = new Map();
49
+ /**
50
+ * Create a CompressedHnswIntegration.
51
+ *
52
+ * @param backend - The underlying HNSW index provider to delegate to
53
+ * @param compressionService - Optional compression service (defaults to new instance)
54
+ */
55
+ constructor(backend, compressionService) {
56
+ this.backend = backend;
57
+ this.compressionService = compressionService ?? createTemporalCompressionService();
58
+ }
59
+ // ==========================================================================
60
+ // IHnswIndexProvider Implementation
61
+ // ==========================================================================
62
+ /**
63
+ * Add a vector to the index.
64
+ *
65
+ * The full-precision vector is passed to the HNSW backend for search.
66
+ * A copy is stored locally for potential future compression.
67
+ * If temporal compression is enabled, the vector is also compressed
68
+ * immediately and the compressed form is stored.
69
+ */
70
+ add(id, vector, metadata) {
71
+ // Always delegate the full-precision vector to the HNSW backend
72
+ this.backend.add(id, vector, metadata);
73
+ const now = new Date();
74
+ const entry = {
75
+ original: new Float32Array(vector),
76
+ compressed: null,
77
+ tier: null,
78
+ lastAccessedAt: now,
79
+ };
80
+ // If compression is enabled, compress immediately but keep the original
81
+ // in the HNSW index for accurate search
82
+ if (isTemporalCompressionEnabled()) {
83
+ const tier = this.compressionService.classifyTier(now);
84
+ entry.compressed = this.compressionService.compress(vector, tier);
85
+ entry.tier = tier;
86
+ }
87
+ this.vectorEntries.set(id, entry);
88
+ }
89
+ /**
90
+ * Search for the k nearest neighbors.
91
+ *
92
+ * Delegates entirely to the HNSW backend which holds full-precision
93
+ * vectors. Updates access timestamps for returned results so they
94
+ * stay in the hot tier.
95
+ */
96
+ search(query, k) {
97
+ const results = this.backend.search(query, k);
98
+ // Update last-accessed timestamps for returned results
99
+ const now = new Date();
100
+ for (const result of results) {
101
+ const entry = this.vectorEntries.get(result.id);
102
+ if (entry) {
103
+ entry.lastAccessedAt = now;
104
+ }
105
+ }
106
+ return results;
107
+ }
108
+ /**
109
+ * Remove a vector from the index.
110
+ */
111
+ remove(id) {
112
+ this.vectorEntries.delete(id);
113
+ return this.backend.remove(id);
114
+ }
115
+ /**
116
+ * Get the number of vectors in the index.
117
+ */
118
+ size() {
119
+ return this.backend.size();
120
+ }
121
+ /**
122
+ * Get the configured vector dimensions.
123
+ */
124
+ dimensions() {
125
+ return this.backend.dimensions();
126
+ }
127
+ /**
128
+ * Get estimated recall. Delegates to the underlying backend.
129
+ */
130
+ recall() {
131
+ return this.backend.recall();
132
+ }
133
+ // ==========================================================================
134
+ // Compression Operations
135
+ // ==========================================================================
136
+ /**
137
+ * Compress vectors in the index based on their access tier.
138
+ *
139
+ * Iterates over all stored vectors and compresses those classified as
140
+ * warm or cold. Hot vectors are left uncompressed for maximum fidelity.
141
+ * After compression, the original float32 data for warm/cold vectors
142
+ * is released to free memory (the HNSW backend still holds its own copy
143
+ * for search operations).
144
+ *
145
+ * @param options - Optional configuration
146
+ * @param options.compressHot - If true, also compress hot-tier vectors (default: false)
147
+ * @returns Statistics about the compression operation
148
+ */
149
+ compressIndex(options) {
150
+ const compressHot = options?.compressHot ?? false;
151
+ let compressedCount = 0;
152
+ let skippedCount = 0;
153
+ let bytesFreed = 0;
154
+ const byTier = { hot: 0, warm: 0, cold: 0 };
155
+ for (const [id, entry] of this.vectorEntries) {
156
+ const tier = this.compressionService.classifyTier(entry.lastAccessedAt);
157
+ // Skip hot vectors unless explicitly requested
158
+ if (tier === 'hot' && !compressHot) {
159
+ skippedCount++;
160
+ continue;
161
+ }
162
+ // Skip if already compressed at the same or more aggressive tier
163
+ if (entry.compressed && entry.tier === tier) {
164
+ skippedCount++;
165
+ continue;
166
+ }
167
+ // Need the original vector to compress. If we already freed it,
168
+ // we cannot re-compress (the HNSW backend doesn't expose vectors).
169
+ if (!entry.original) {
170
+ // If we have an existing compressed form at a less aggressive tier,
171
+ // we could decompress and recompress, but that adds error.
172
+ // For now, skip.
173
+ skippedCount++;
174
+ continue;
175
+ }
176
+ const compressed = this.compressionService.compress(entry.original, tier);
177
+ const originalSize = entry.original.byteLength;
178
+ entry.compressed = compressed;
179
+ entry.tier = tier;
180
+ // For warm and cold tiers, release the original to save memory.
181
+ // The HNSW backend still holds its own copy for search.
182
+ if (tier !== 'hot') {
183
+ entry.original = null;
184
+ bytesFreed += originalSize;
185
+ }
186
+ compressedCount++;
187
+ byTier[tier]++;
188
+ }
189
+ logger.debug(`compressIndex: compressed=${compressedCount}, skipped=${skippedCount}, freed=${bytesFreed} bytes`);
190
+ return {
191
+ compressedCount,
192
+ skippedCount,
193
+ bytesFreed,
194
+ byTier,
195
+ };
196
+ }
197
+ /**
198
+ * Decompress and retrieve the vector for a given ID.
199
+ *
200
+ * Returns the original vector if still available, otherwise
201
+ * decompresses from the stored compressed form.
202
+ *
203
+ * @param id - The vector ID
204
+ * @returns The decompressed Float32Array, or null if not found
205
+ */
206
+ getVector(id) {
207
+ const entry = this.vectorEntries.get(id);
208
+ if (!entry)
209
+ return null;
210
+ // Return original if still available
211
+ if (entry.original)
212
+ return entry.original;
213
+ // Decompress from compressed form
214
+ if (entry.compressed) {
215
+ return this.compressionService.decompress(entry.compressed);
216
+ }
217
+ return null;
218
+ }
219
+ /**
220
+ * Get the compression tier for a specific vector.
221
+ *
222
+ * @param id - The vector ID
223
+ * @returns The tier, or null if not found or not compressed
224
+ */
225
+ getVectorTier(id) {
226
+ const entry = this.vectorEntries.get(id);
227
+ return entry?.tier ?? null;
228
+ }
229
+ /**
230
+ * Update the last-accessed timestamp for a vector.
231
+ * This affects which tier it falls into during the next compressIndex() call.
232
+ *
233
+ * @param id - The vector ID
234
+ * @param accessDate - The access date (defaults to now)
235
+ */
236
+ touchVector(id, accessDate) {
237
+ const entry = this.vectorEntries.get(id);
238
+ if (entry) {
239
+ entry.lastAccessedAt = accessDate ?? new Date();
240
+ }
241
+ }
242
+ // ==========================================================================
243
+ // Memory Statistics
244
+ // ==========================================================================
245
+ /**
246
+ * Get memory usage statistics for the compressed index.
247
+ */
248
+ getMemoryStats() {
249
+ let uncompressedCount = 0;
250
+ let compressedCount = 0;
251
+ let originalBytes = 0;
252
+ let compressedBytes = 0;
253
+ const compressedByTier = { hot: 0, warm: 0, cold: 0 };
254
+ for (const entry of this.vectorEntries.values()) {
255
+ if (entry.compressed && entry.tier) {
256
+ compressedCount++;
257
+ compressedByTier[entry.tier]++;
258
+ compressedBytes += entry.compressed.compressedByteSize;
259
+ originalBytes += entry.compressed.originalByteSize;
260
+ }
261
+ else if (entry.original) {
262
+ uncompressedCount++;
263
+ const byteSize = entry.original.byteLength;
264
+ originalBytes += byteSize;
265
+ compressedBytes += byteSize; // Not compressed, so same size
266
+ }
267
+ }
268
+ const bytesSaved = originalBytes - compressedBytes;
269
+ const savingsPercent = originalBytes > 0
270
+ ? (bytesSaved / originalBytes) * 100
271
+ : 0;
272
+ return {
273
+ totalVectors: this.vectorEntries.size,
274
+ uncompressedCount,
275
+ compressedCount,
276
+ compressedByTier,
277
+ originalBytes,
278
+ compressedBytes,
279
+ bytesSaved,
280
+ savingsPercent,
281
+ compressionEnabled: isTemporalCompressionEnabled(),
282
+ };
283
+ }
284
+ // ==========================================================================
285
+ // Accessors
286
+ // ==========================================================================
287
+ /**
288
+ * Get the underlying HNSW backend.
289
+ * Useful for accessing backend-specific methods (e.g., NativeHnswBackend.getMetrics()).
290
+ */
291
+ getBackend() {
292
+ return this.backend;
293
+ }
294
+ /**
295
+ * Get the compression service instance.
296
+ */
297
+ getCompressionService() {
298
+ return this.compressionService;
299
+ }
300
+ }
301
+ //# sourceMappingURL=compressed-hnsw-integration.js.map
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Deterministic Dithering Adapter for Cross-Platform Reproducibility
3
+ *
4
+ * Provides golden-ratio quasi-random dithering for embedding quantization.
5
+ * Ensures identical quantization results across x86, ARM, and WASM platforms
6
+ * by using only deterministic integer and float arithmetic.
7
+ *
8
+ * The golden ratio sequence produces a low-discrepancy quasi-random sequence
9
+ * that distributes quantization error more evenly than truncation alone,
10
+ * improving reconstruction quality at low bit depths.
11
+ *
12
+ * @module integrations/ruvector/dither-adapter
13
+ */
14
+ /**
15
+ * Result of applying dithered quantization to a vector
16
+ */
17
+ export interface DitheredResult {
18
+ /** Quantized values as integers in [0, 2^bitDepth - 1] */
19
+ quantized: Int32Array;
20
+ /** Dequantized (reconstructed) float values */
21
+ dequantized: Float32Array;
22
+ /** Bit depth used for quantization */
23
+ bitDepth: number;
24
+ /** Seed used for dither generation */
25
+ seed: number;
26
+ /** Step size (quantization interval width) */
27
+ stepSize: number;
28
+ /** Min value of the original vector (used for dequantization) */
29
+ minValue: number;
30
+ /** Max value of the original vector (used for dequantization) */
31
+ maxValue: number;
32
+ }
33
+ /**
34
+ * Options for the dither adapter
35
+ */
36
+ export interface DitherOptions {
37
+ /** Bit depth for quantization (1-32, typical: 3, 5, 7, 8) */
38
+ bitDepth: number;
39
+ /** Seed for the dither sequence (default: 0) */
40
+ seed?: number;
41
+ }
42
+ /**
43
+ * Check if a native dither module is available.
44
+ * Always returns false — the TypeScript implementation is production-ready.
45
+ */
46
+ export declare function isNativeDitherAvailable(): boolean;
47
+ /**
48
+ * Create a deterministic quasi-random dither sequence using the golden ratio.
49
+ *
50
+ * The sequence d_n = frac((seed + (n+1) * phi)) produces values uniformly
51
+ * distributed in [0, 1) with low discrepancy (no clumping). This is a
52
+ * Weyl sequence / additive recurrence, which is deterministic and
53
+ * platform-independent since it uses only standard IEEE 754 arithmetic.
54
+ *
55
+ * @param length - Number of dither values to generate
56
+ * @param seed - Starting offset for the sequence (default: 0)
57
+ * @returns Float32Array of dither values in [0, 1)
58
+ */
59
+ export declare function createDitherSequence(length: number, seed?: number): Float32Array;
60
+ /**
61
+ * Apply deterministic dithered quantization to a float vector.
62
+ *
63
+ * The algorithm:
64
+ * 1. Compute the range [min, max] of the input vector.
65
+ * 2. Compute step_size = range / (2^bitDepth - 1).
66
+ * 3. Generate a golden-ratio dither sequence of the same length.
67
+ * 4. For each element: quantized[i] = clamp(round((value[i] - min) / stepSize + (dither[i] - 0.5)), 0, maxLevel)
68
+ * 5. Dequantize: dequantized[i] = quantized[i] * stepSize + min
69
+ *
70
+ * The dither offset (dither[i] - 0.5) centers the dither noise around zero,
71
+ * which reduces systematic bias compared to truncation-only quantization.
72
+ *
73
+ * @param vector - Input float vector to quantize
74
+ * @param bitDepth - Number of bits for quantization (1-32)
75
+ * @param seed - Seed for dither sequence reproducibility (default: 0)
76
+ * @returns DitheredResult with quantized and reconstructed values
77
+ */
78
+ export declare function applyDither(vector: Float32Array, bitDepth: number, seed?: number): DitheredResult;
79
+ /**
80
+ * Apply naive (non-dithered) quantization for comparison purposes.
81
+ *
82
+ * Uses simple rounding without dither noise. This tends to produce
83
+ * systematic quantization artifacts, especially at low bit depths.
84
+ *
85
+ * @param vector - Input float vector to quantize
86
+ * @param bitDepth - Number of bits for quantization (1-32)
87
+ * @returns DitheredResult with quantized and reconstructed values (seed = -1 to indicate no dither)
88
+ */
89
+ export declare function applyNaiveQuantization(vector: Float32Array, bitDepth: number): DitheredResult;
90
+ /**
91
+ * Verify that dithered quantization is deterministic for the given input.
92
+ *
93
+ * Runs the quantization twice with the same parameters and compares results.
94
+ * This guards against any non-determinism from floating point ordering,
95
+ * platform differences, or hidden state.
96
+ *
97
+ * @param vector - Input float vector to test
98
+ * @param bitDepth - Number of bits for quantization
99
+ * @returns true if both runs produce identical quantized values
100
+ */
101
+ export declare function verifyDeterminism(vector: Float32Array, bitDepth: number): boolean;
102
+ /**
103
+ * Compute mean squared error between original and reconstructed vectors.
104
+ *
105
+ * @param original - Original float vector
106
+ * @param reconstructed - Reconstructed (dequantized) float vector
107
+ * @returns Mean squared error
108
+ */
109
+ export declare function computeMSE(original: Float32Array, reconstructed: Float32Array): number;
110
+ /**
111
+ * Compute signal-to-noise ratio (SNR) in decibels.
112
+ *
113
+ * SNR = 10 * log10(signal_power / noise_power)
114
+ *
115
+ * Higher SNR means better reconstruction quality.
116
+ *
117
+ * @param original - Original float vector
118
+ * @param reconstructed - Reconstructed (dequantized) float vector
119
+ * @returns SNR in dB, or Infinity if reconstruction is perfect
120
+ */
121
+ export declare function computeSNR(original: Float32Array, reconstructed: Float32Array): number;
122
+ //# sourceMappingURL=dither-adapter.d.ts.map