noteconnection 1.7.0 → 1.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 (211) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +242 -62
  3. package/dist/src/agent_workspace.contract.parity.test.js +475 -0
  4. package/dist/src/agent_workspace.frontend.test.js +9989 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/copy.assets.contract.test.js +130 -0
  8. package/dist/src/core/PathBridge.js +28 -3
  9. package/dist/src/export/WorkspaceExportBundle.js +1130 -0
  10. package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
  11. package/dist/src/export/index.js +18 -0
  12. package/dist/src/export/types.js +2 -0
  13. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  14. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  15. package/dist/src/foundation.release.evidence.contract.test.js +406 -0
  16. package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
  17. package/dist/src/frontend/README.md +242 -62
  18. package/dist/src/frontend/agent_workspace.js +5353 -0
  19. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  20. package/dist/src/frontend/analysis.js +31 -4
  21. package/dist/src/frontend/app.js +2178 -62
  22. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  23. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  24. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  25. package/dist/src/frontend/graph_state.mjs +105 -0
  26. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  27. package/dist/src/frontend/i18n.mjs +186 -0
  28. package/dist/src/frontend/index.html +641 -266
  29. package/dist/src/frontend/layout_gpu.js +12 -4
  30. package/dist/src/frontend/locales/en.json +721 -5
  31. package/dist/src/frontend/locales/zh.json +721 -5
  32. package/dist/src/frontend/main.mjs +60 -0
  33. package/dist/src/frontend/markdown_runtime.js +827 -0
  34. package/dist/src/frontend/notemd.css +49 -0
  35. package/dist/src/frontend/notemd.html +7 -1
  36. package/dist/src/frontend/notemd.js +64 -0
  37. package/dist/src/frontend/path.html +107 -0
  38. package/dist/src/frontend/path_app.js +2108 -130
  39. package/dist/src/frontend/path_layout.mjs +143 -0
  40. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  41. package/dist/src/frontend/path_modules_bridge.js +486 -0
  42. package/dist/src/frontend/path_state.mjs +118 -0
  43. package/dist/src/frontend/path_styles.css +146 -0
  44. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  45. package/dist/src/frontend/reader.js +393 -33
  46. package/dist/src/frontend/runtime_bridge.js +67 -54
  47. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  48. package/dist/src/frontend/settings.js +130 -12
  49. package/dist/src/frontend/source_manager.js +190 -21
  50. package/dist/src/frontend/styles.css +2720 -72
  51. package/dist/src/frontend/workbench_state.mjs +101 -0
  52. package/dist/src/frontend/workspace_panes.js +10168 -0
  53. package/dist/src/frontend.locale.contract.test.js +62 -0
  54. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  55. package/dist/src/indexing/IndexLifecycle.js +195 -0
  56. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  57. package/dist/src/indexing/SegmentBuilder.js +64 -0
  58. package/dist/src/indexing/UnitBuilder.js +48 -0
  59. package/dist/src/indexing/types.js +2 -0
  60. package/dist/src/knowledge.api.contract.test.js +170 -0
  61. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  65. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  67. package/dist/src/learning/answerReleaseReview.js +4319 -0
  68. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  69. package/dist/src/learning/api.js +2 -0
  70. package/dist/src/learning/conversationComposer.js +1480 -0
  71. package/dist/src/learning/conversationComposer.test.js +1817 -0
  72. package/dist/src/learning/domains/ConversationManager.js +53 -0
  73. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  74. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  75. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  76. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  77. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  78. package/dist/src/learning/domains/TutorRouter.js +313 -0
  79. package/dist/src/learning/domains/index.js +33 -0
  80. package/dist/src/learning/domains/types.js +7 -0
  81. package/dist/src/learning/errors.js +29 -0
  82. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  83. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  84. package/dist/src/learning/graphContextAssembler.js +870 -0
  85. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  86. package/dist/src/learning/index.js +28 -0
  87. package/dist/src/learning/queryBackend.js +1898 -0
  88. package/dist/src/learning/queryBackend.test.js +955 -0
  89. package/dist/src/learning/ragContextPack.js +257 -0
  90. package/dist/src/learning/ragContextPack.test.js +160 -0
  91. package/dist/src/learning/ragPublicText.js +38 -0
  92. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  93. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  94. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  96. package/dist/src/learning/requestNormalization.js +198 -0
  97. package/dist/src/learning/runtimeCapability.js +4677 -0
  98. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  99. package/dist/src/learning/store.js +1240 -0
  100. package/dist/src/learning/store.test.js +1126 -0
  101. package/dist/src/learning/tutorAdapter.js +2 -0
  102. package/dist/src/learning/types.js +2 -0
  103. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  105. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  106. package/dist/src/license.policy.contract.test.js +66 -0
  107. package/dist/src/memory/MemoryGovernance.js +74 -0
  108. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  109. package/dist/src/memory/types.js +2 -0
  110. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  111. package/dist/src/middleware/auth.js +17 -0
  112. package/dist/src/middleware/body-parser.js +45 -0
  113. package/dist/src/middleware/cors.js +44 -0
  114. package/dist/src/middleware/index.js +21 -0
  115. package/dist/src/middleware/request-trace.js +96 -0
  116. package/dist/src/notemd/AppConfigToml.js +6 -4
  117. package/dist/src/notemd/MermaidProcessor.js +400 -50
  118. package/dist/src/notemd/NotemdService.js +498 -13
  119. package/dist/src/notemd/PromptManager.js +15 -0
  120. package/dist/src/notemd/cli/commands.js +357 -0
  121. package/dist/src/notemd/cli/dispatcher.js +225 -0
  122. package/dist/src/notemd/cli/index.js +169 -0
  123. package/dist/src/notemd/cli/parser.js +68 -0
  124. package/dist/src/notemd/cli/types.js +2 -0
  125. package/dist/src/notemd/constants.js +43 -0
  126. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  127. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  128. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  129. package/dist/src/notemd/diagram/intent.js +95 -0
  130. package/dist/src/notemd/diagram/planner.js +71 -0
  131. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  132. package/dist/src/notemd/diagram/types.js +18 -0
  133. package/dist/src/notemd/index.js +26 -0
  134. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  135. package/dist/src/notemd/operations/cliContracts.js +17 -0
  136. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  137. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  138. package/dist/src/notemd/operations/registry.js +991 -0
  139. package/dist/src/notemd/operations/types.js +2 -0
  140. package/dist/src/notemd/providerDiagnostics.js +220 -0
  141. package/dist/src/notemd/providerProfiles.js +42 -0
  142. package/dist/src/notemd/providerTemplates.js +231 -0
  143. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  144. package/dist/src/notemd/search/SearchManager.js +13 -0
  145. package/dist/src/notemd/search/SearchProvider.js +2 -0
  146. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  147. package/dist/src/notemd.agent.manifest.test.js +85 -0
  148. package/dist/src/notemd.api.contract.test.js +14 -1
  149. package/dist/src/notemd.app_config_toml.test.js +2 -1
  150. package/dist/src/notemd.batch.workflow.test.js +117 -0
  151. package/dist/src/notemd.cli.e2e.test.js +136 -0
  152. package/dist/src/notemd.core.test.js +51 -0
  153. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  154. package/dist/src/notemd.providerTemplates.test.js +34 -0
  155. package/dist/src/notemd.server.integration.test.js +143 -35
  156. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  157. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  158. package/dist/src/pathmode.background.contract.test.js +69 -0
  159. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  160. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  161. package/dist/src/platform/ExportProfile.js +58 -0
  162. package/dist/src/platform/PlatformCapabilities.js +45 -0
  163. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  164. package/dist/src/platform/RenderMaterializer.js +33 -0
  165. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  166. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  167. package/dist/src/reader_renderer.js +404 -3
  168. package/dist/src/reader_renderer.test.js +87 -0
  169. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  170. package/dist/src/resources/ResourceRegistry.js +223 -0
  171. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  172. package/dist/src/resources/types.js +2 -0
  173. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  174. package/dist/src/routes/data.js +267 -0
  175. package/dist/src/routes/diagnostics.js +51 -0
  176. package/dist/src/routes/index.js +23 -0
  177. package/dist/src/routes/knowledge.js +968 -0
  178. package/dist/src/routes/markdown.js +287 -0
  179. package/dist/src/routes/notemd.js +565 -0
  180. package/dist/src/routes/registry.contract.test.js +130 -0
  181. package/dist/src/routes/render.js +285 -0
  182. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  184. package/dist/src/routes/settings.js +6 -0
  185. package/dist/src/routes/staticFiles.js +94 -0
  186. package/dist/src/routes/types.js +2 -0
  187. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  188. package/dist/src/server.js +11090 -1549
  189. package/dist/src/server.migration.test.js +193 -21
  190. package/dist/src/server.port.fallback.contract.test.js +63 -0
  191. package/dist/src/session/SessionStateStore.js +81 -0
  192. package/dist/src/session/SessionStateStore.test.js +58 -0
  193. package/dist/src/session/types.js +2 -0
  194. package/dist/src/settings.runtime.contract.test.js +50 -0
  195. package/dist/src/shared/types.contract.test.js +107 -0
  196. package/dist/src/shared/types.js +22 -0
  197. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  198. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  199. package/dist/src/source_manager.loadflow.test.js +46 -0
  200. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  201. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  202. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  203. package/dist/src/utils/RuntimePaths.js +4 -13
  204. package/dist/src/utils/platform.js +153 -0
  205. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  207. package/dist/src/workflows/types.js +2 -0
  208. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  209. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  210. package/dist/src/workspace/types.js +2 -0
  211. package/package.json +53 -10
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryPolicyManager = void 0;
4
+ class MemoryPolicyManager {
5
+ constructor(platform) {
6
+ this.platform = platform;
7
+ this.policyApplicationCount = 0;
8
+ this.diagnosticsQueryCount = 0;
9
+ this.historyQueryCount = 0;
10
+ this.trendQueryCount = 0;
11
+ this.policyLayerCounts = {};
12
+ // Domain-level analysis state
13
+ this.evictionHistory = [];
14
+ this.writeHistory = [];
15
+ this.promotionHistory = [];
16
+ this.layerSizes = new Map();
17
+ // Domain budget constraints per layer
18
+ this.budgets = {
19
+ session: { maxEntries: 200, maxEntrySizeChars: 5000, maxTagsPerEntry: 8 },
20
+ unit: { maxEntries: 500, maxEntrySizeChars: 10000, maxTagsPerEntry: 12 },
21
+ long_term: { maxEntries: 2000, maxEntrySizeChars: 20000, maxTagsPerEntry: 16 },
22
+ };
23
+ // Promotion requirements
24
+ this.promotionThresholds = {
25
+ minConfidence: 0.6,
26
+ minAccessCount: 3,
27
+ minAgeDays: 1, // session → unit
28
+ minAgeDaysLongTerm: 7, // unit → long_term
29
+ };
30
+ // Health scoring weights
31
+ this.healthWeights = {
32
+ fragmentationRisk: 0.25,
33
+ stalenessRatio: 0.25,
34
+ confidenceDistribution: 0.25,
35
+ evictionPressure: 0.25,
36
+ };
37
+ }
38
+ // ─── Public API ─────────────────────────────────────────────────
39
+ async apply(r) {
40
+ this.validatePolicyRequest(r);
41
+ this.policyApplicationCount++;
42
+ const layer = String(r?.layer ?? 'unknown');
43
+ this.policyLayerCounts[layer] = (this.policyLayerCounts[layer] || 0) + 1;
44
+ // Domain-level budget validation BEFORE platform execution
45
+ this.validateLayerBudget(r, layer);
46
+ // Domain-level promotion validation
47
+ if (r?.operation === 'write' && r?.promoteFromLayer) {
48
+ const promotionResult = this.validatePromotion(r);
49
+ if (!promotionResult.valid) {
50
+ return {
51
+ _domain: {
52
+ layer,
53
+ applicationNumber: this.policyApplicationCount,
54
+ promotionBlocked: true,
55
+ promotionReason: promotionResult.reason,
56
+ },
57
+ error: promotionResult.reason,
58
+ };
59
+ }
60
+ }
61
+ const response = await this.platform.applyMemoryPolicy(r);
62
+ // Domain-level post-execution analysis
63
+ this.trackLayerSize(layer, response);
64
+ this.recordOperation(r, response);
65
+ this.trackEviction(layer, response);
66
+ return this.augmentPolicyResponse(response, layer);
67
+ }
68
+ async queryDiagnostics(r) {
69
+ this.diagnosticsQueryCount++;
70
+ const response = await this.platform.queryMemoryPolicyDiagnostics(r);
71
+ // Domain-level memory health scoring
72
+ const health = this.computeMemoryHealth(response);
73
+ return {
74
+ ...response,
75
+ _domain: {
76
+ diagnosticsNumber: this.diagnosticsQueryCount,
77
+ health,
78
+ },
79
+ };
80
+ }
81
+ async queryDiagnosticsHistory(r) {
82
+ this.historyQueryCount++;
83
+ const response = await this.platform.queryMemoryPolicyDiagnosticsHistory(r);
84
+ // Domain-level history aggregation
85
+ const aggregated = this.aggregateDiagnosticsHistory(response);
86
+ return { ...response, _domain: { aggregated } };
87
+ }
88
+ async queryDiagnosticsTrend(r) {
89
+ this.trendQueryCount++;
90
+ const response = await this.platform.queryMemoryPolicyDiagnosticsTrend(r);
91
+ // Domain-level eviction trend
92
+ const evictionTrend = this.computeEvictionTrend(10);
93
+ return { ...response, _domain: { evictionTrend } };
94
+ }
95
+ // ─── Public accessors ───────────────────────────────────────────
96
+ getPolicyApplicationCount() { return this.policyApplicationCount; }
97
+ getEvictionHistory() { return [...this.evictionHistory]; }
98
+ getPromotionHistory() { return [...this.promotionHistory]; }
99
+ getLayerSizes() {
100
+ return Object.fromEntries(this.layerSizes);
101
+ }
102
+ getDiagnosticsSummary() {
103
+ const evictionTrend = this.computeEvictionTrend(10);
104
+ const writePattern = this.analyzeWritePattern(20);
105
+ return {
106
+ policyApplicationCount: this.policyApplicationCount,
107
+ diagnosticsQueryCount: this.diagnosticsQueryCount,
108
+ historyQueryCount: this.historyQueryCount,
109
+ trendQueryCount: this.trendQueryCount,
110
+ policyLayerDistribution: { ...this.policyLayerCounts },
111
+ evictionTrend,
112
+ writePattern,
113
+ promotionCount: this.promotionHistory.length,
114
+ recentPromotions: this.promotionHistory.slice(-5),
115
+ totalEvicted: this.evictionHistory.reduce((s, e) => s + e.evictedCount, 0),
116
+ };
117
+ }
118
+ // ─── Private: validation ────────────────────────────────────────
119
+ validatePolicyRequest(r) {
120
+ if (!r)
121
+ throw new Error('Memory policy request is required.');
122
+ if (!r?.userId)
123
+ throw new Error('userId is required for memory policy operations.');
124
+ if (!r?.layer)
125
+ throw new Error('Memory layer (session/unit/long_term) is required.');
126
+ const validLayers = ['session', 'unit', 'long_term'];
127
+ if (!validLayers.includes(r.layer)) {
128
+ throw new Error(`Invalid memory layer "${r.layer}". Must be one of: ${validLayers.join(', ')}.`);
129
+ }
130
+ }
131
+ /**
132
+ * Validate that the operation won't exceed per-layer capacity budgets.
133
+ * Rejects writes that would push a layer beyond its max entry limit.
134
+ */
135
+ validateLayerBudget(r, layer) {
136
+ const budget = this.budgets[layer];
137
+ if (!budget || r?.operation !== 'write')
138
+ return;
139
+ const incomingEntries = Array.isArray(r?.entries) ? r.entries : [];
140
+ const currentSize = this.layerSizes.get(layer) || 0;
141
+ if (currentSize + incomingEntries.length > budget.maxEntries) {
142
+ throw new Error(`Layer "${layer}" capacity exceeded: ${currentSize + incomingEntries.length} > ${budget.maxEntries}. ` +
143
+ `Consider eviction or promoting entries to a higher layer.`);
144
+ }
145
+ // Validate individual entry sizes
146
+ for (const entry of incomingEntries) {
147
+ const valueSize = String(entry?.value || '').length;
148
+ if (valueSize > budget.maxEntrySizeChars) {
149
+ throw new Error(`Entry value (${valueSize} chars) exceeds layer "${layer}" limit (${budget.maxEntrySizeChars}).`);
150
+ }
151
+ const tagCount = Array.isArray(entry?.tags) ? entry.tags.length : 0;
152
+ if (tagCount > budget.maxTagsPerEntry) {
153
+ throw new Error(`Entry tag count (${tagCount}) exceeds layer "${layer}" limit (${budget.maxTagsPerEntry}).`);
154
+ }
155
+ }
156
+ }
157
+ /**
158
+ * Validate a layer promotion request (session → unit, unit → long_term).
159
+ * Checks confidence, access count, and age thresholds.
160
+ */
161
+ validatePromotion(r) {
162
+ const fromLayer = String(r?.promoteFromLayer || '');
163
+ const toLayer = String(r?.layer || '');
164
+ const validTransitions = {
165
+ session: 'unit',
166
+ unit: 'long_term',
167
+ };
168
+ const expectedTarget = validTransitions[fromLayer];
169
+ if (!expectedTarget) {
170
+ return { valid: false, reason: `Promotion from "${fromLayer}" is not supported.` };
171
+ }
172
+ if (toLayer !== expectedTarget) {
173
+ return { valid: false, reason: `Cannot promote directly from "${fromLayer}" to "${toLayer}". Expected target: "${expectedTarget}".` };
174
+ }
175
+ const minAgeDays = toLayer === 'long_term'
176
+ ? this.promotionThresholds.minAgeDaysLongTerm
177
+ : this.promotionThresholds.minAgeDays;
178
+ const entries = Array.isArray(r?.entries) ? r.entries : [];
179
+ const failingEntries = [];
180
+ for (const entry of entries) {
181
+ const confidence = Number(entry?.confidence || 0);
182
+ const accessCount = Number(entry?.accessCount || entry?._accessCount || 0);
183
+ if (confidence < this.promotionThresholds.minConfidence) {
184
+ failingEntries.push(`${entry.key}: confidence ${confidence} < ${this.promotionThresholds.minConfidence}`);
185
+ continue;
186
+ }
187
+ if (accessCount < this.promotionThresholds.minAccessCount) {
188
+ failingEntries.push(`${entry.key}: accessCount ${accessCount} < ${this.promotionThresholds.minAccessCount}`);
189
+ continue;
190
+ }
191
+ // Age check
192
+ const createdAt = entry?.createdAt;
193
+ if (createdAt) {
194
+ const ageMs = Date.now() - new Date(createdAt).getTime();
195
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
196
+ if (ageDays < minAgeDays) {
197
+ failingEntries.push(`${entry.key}: age ${ageDays.toFixed(1)} days < ${minAgeDays} days`);
198
+ }
199
+ }
200
+ }
201
+ if (failingEntries.length > 0) {
202
+ return { valid: false, reason: `Promotion requirements not met: ${failingEntries.join('; ')}` };
203
+ }
204
+ // Record promotion for governance
205
+ this.promotionHistory.push({
206
+ timestamp: new Date().toISOString(),
207
+ fromLayer,
208
+ toLayer,
209
+ entryKeys: entries.map((e) => String(e.key || '')),
210
+ accepted: true,
211
+ });
212
+ if (this.promotionHistory.length > 100)
213
+ this.promotionHistory.shift();
214
+ return { valid: true };
215
+ }
216
+ // ─── Private: augmentation ──────────────────────────────────────
217
+ augmentPolicyResponse(response, layer) {
218
+ const budget = this.budgets[layer];
219
+ const currentSize = this.layerSizes.get(layer) || 0;
220
+ const capacityUsedPct = budget
221
+ ? Number(((currentSize / budget.maxEntries) * 100).toFixed(1))
222
+ : 0;
223
+ return {
224
+ ...response,
225
+ _domain: {
226
+ layer,
227
+ applicationNumber: this.policyApplicationCount,
228
+ layerCount: this.policyLayerCounts[layer] || 1,
229
+ layers: Object.keys(this.policyLayerCounts),
230
+ capacityUsedPct,
231
+ capacityLimit: budget?.maxEntries ?? null,
232
+ withinBudget: capacityUsedPct <= 85,
233
+ },
234
+ };
235
+ }
236
+ // ─── Private: layer size tracking ───────────────────────────────
237
+ trackLayerSize(layer, response) {
238
+ const entries = Array.isArray(response?.entries) ? response.entries : [];
239
+ this.layerSizes.set(layer, entries.length);
240
+ }
241
+ // ─── Private: operation recording ───────────────────────────────
242
+ recordOperation(request, response) {
243
+ const layer = String(request?.layer || 'unknown');
244
+ const operation = String(request?.operation || 'unknown');
245
+ if (operation === 'write') {
246
+ const entries = Array.isArray(request?.entries) ? request.entries : [];
247
+ this.writeHistory.push({
248
+ timestamp: new Date().toISOString(),
249
+ layer,
250
+ entryCount: entries.length,
251
+ operation,
252
+ });
253
+ if (this.writeHistory.length > 200)
254
+ this.writeHistory.shift();
255
+ }
256
+ }
257
+ // ─── Private: eviction tracking ─────────────────────────────────
258
+ trackEviction(layer, response) {
259
+ const evictedCount = Number(response?.evictedCount || 0);
260
+ if (evictedCount === 0)
261
+ return;
262
+ const entries = Array.isArray(response?.entries) ? response.entries : [];
263
+ this.evictionHistory.push({
264
+ timestamp: new Date().toISOString(),
265
+ layer,
266
+ evictedCount,
267
+ remainingCount: entries.length,
268
+ });
269
+ if (this.evictionHistory.length > 100)
270
+ this.evictionHistory.shift();
271
+ }
272
+ computeEvictionTrend(n) {
273
+ const window = this.evictionHistory.slice(-n);
274
+ if (window.length === 0) {
275
+ return {
276
+ direction: 'none',
277
+ recentEvicted: 0,
278
+ windowTotalEvicted: 0,
279
+ averagePerEvent: 0,
280
+ snapshotCount: 0,
281
+ };
282
+ }
283
+ const totalEvicted = window.reduce((s, e) => s + e.evictedCount, 0);
284
+ const avgPerEvent = Number((totalEvicted / window.length).toFixed(1));
285
+ const recentEvicted = window[window.length - 1].evictedCount;
286
+ if (window.length < 2) {
287
+ return {
288
+ direction: 'insufficient_data',
289
+ recentEvicted,
290
+ windowTotalEvicted: totalEvicted,
291
+ averagePerEvent: avgPerEvent,
292
+ snapshotCount: window.length,
293
+ };
294
+ }
295
+ const mid = Math.floor(window.length / 2);
296
+ const recentAvg = window.slice(-mid).reduce((s, e) => s + e.evictedCount, 0) / mid;
297
+ const earlierAvg = window.slice(0, mid).reduce((s, e) => s + e.evictedCount, 0) / mid;
298
+ const delta = recentAvg - earlierAvg;
299
+ return {
300
+ direction: delta > 3 ? 'increasing' : delta < -3 ? 'decreasing' : 'stable',
301
+ recentEvicted,
302
+ windowTotalEvicted: totalEvicted,
303
+ averagePerEvent: avgPerEvent,
304
+ snapshotCount: window.length,
305
+ };
306
+ }
307
+ // ─── Private: write pattern analysis ────────────────────────────
308
+ analyzeWritePattern(n) {
309
+ const window = this.writeHistory.slice(-n);
310
+ const layerDist = {};
311
+ let totalEntries = 0;
312
+ for (const write of window) {
313
+ layerDist[write.layer] = (layerDist[write.layer] || 0) + 1;
314
+ totalEntries += write.entryCount;
315
+ }
316
+ const avgBatchSize = window.length > 0
317
+ ? Number((totalEntries / window.length).toFixed(1))
318
+ : 0;
319
+ // Estimate write rate per minute from timestamps
320
+ let writeRatePerMinute = 0;
321
+ if (window.length >= 2) {
322
+ const firstTs = new Date(window[0].timestamp).getTime();
323
+ const lastTs = new Date(window[window.length - 1].timestamp).getTime();
324
+ const elapsedMinutes = (lastTs - firstTs) / (1000 * 60);
325
+ writeRatePerMinute = elapsedMinutes > 0
326
+ ? Number((window.length / elapsedMinutes).toFixed(2))
327
+ : window.length;
328
+ }
329
+ return {
330
+ totalWrites: window.length,
331
+ layerDistribution: layerDist,
332
+ averageBatchSize: avgBatchSize,
333
+ writeRatePerMinute,
334
+ snapshotCount: window.length,
335
+ };
336
+ }
337
+ // ─── Private: memory health scoring ─────────────────────────────
338
+ /**
339
+ * Compute a composite memory health score (0-100) from:
340
+ * - Fragmentation risk (too many small entries per layer)
341
+ * - Staleness ratio (entries past expiry without eviction)
342
+ * - Confidence distribution (ratio of low-confidence entries)
343
+ * - Eviction pressure (how close layers are to capacity)
344
+ */
345
+ computeMemoryHealth(response) {
346
+ const stats = response?.stats || {};
347
+ const now = Date.now();
348
+ // Fragmentation risk: average entries per layer vs max
349
+ let fragmentationRisk = 0;
350
+ let totalLayers = 0;
351
+ for (const [layer, budget] of Object.entries(this.budgets)) {
352
+ const size = this.layerSizes.get(layer) || Number(stats[`${layer}Entries`] || 0);
353
+ if (size > 0) {
354
+ // Risk increases as entries approach budget limit
355
+ fragmentationRisk += size / budget.maxEntries;
356
+ totalLayers++;
357
+ }
358
+ }
359
+ fragmentationRisk = totalLayers > 0
360
+ ? Number(clamp(fragmentationRisk / totalLayers, 0, 1).toFixed(4))
361
+ : 0;
362
+ // Staleness ratio: stale entries count
363
+ const staleCount = Number(stats.staleEntryCount || stats.expiredEntryCount || 0);
364
+ const totalEntries = Number(stats.totalEntries || 0);
365
+ const stalenessRatio = totalEntries > 0
366
+ ? Number(clamp(staleCount / totalEntries, 0, 1).toFixed(4))
367
+ : 0;
368
+ // Confidence distribution: how many entries have low confidence
369
+ const lowConfidenceCount = Number(stats.lowConfidenceEntryCount || 0);
370
+ const confidenceDistribution = totalEntries > 0
371
+ ? Number(clamp(1 - lowConfidenceCount / totalEntries, 0, 1).toFixed(4))
372
+ : 1;
373
+ // Eviction pressure: recent eviction rate
374
+ const recentEvictions = this.evictionHistory.slice(-10);
375
+ const evictionPressure = recentEvictions.length > 0
376
+ ? Number(clamp(recentEvictions.reduce((s, e) => s + e.evictedCount, 0) / (recentEvictions.length * 20), 0, 1).toFixed(4))
377
+ : 0;
378
+ const score = Number(((1 - fragmentationRisk) * this.healthWeights.fragmentationRisk +
379
+ (1 - stalenessRatio) * this.healthWeights.stalenessRatio +
380
+ confidenceDistribution * this.healthWeights.confidenceDistribution +
381
+ (1 - evictionPressure) * this.healthWeights.evictionPressure).toFixed(4)) * 100;
382
+ return {
383
+ score: Number(score.toFixed(1)),
384
+ fragmentationRisk: Number((fragmentationRisk * 100).toFixed(1)),
385
+ stalenessRatio: Number((stalenessRatio * 100).toFixed(1)),
386
+ confidenceDistribution: Number((confidenceDistribution * 100).toFixed(1)),
387
+ evictionPressure: Number((evictionPressure * 100).toFixed(1)),
388
+ };
389
+ }
390
+ // ─── Private: diagnostics history aggregation ───────────────────
391
+ aggregateDiagnosticsHistory(response) {
392
+ const records = Array.isArray(response?.records) ? response.records : [];
393
+ const opCounts = {};
394
+ for (const record of records) {
395
+ const op = String(record?.operation || 'unknown');
396
+ opCounts[op] = (opCounts[op] || 0) + 1;
397
+ }
398
+ return {
399
+ totalRecords: records.length,
400
+ policyApplyRate: this.policyApplicationCount,
401
+ topOperations: opCounts,
402
+ };
403
+ }
404
+ }
405
+ exports.MemoryPolicyManager = MemoryPolicyManager;
406
+ function clamp(value, min, max) {
407
+ return value < min ? min : value > max ? max : value;
408
+ }