noteconnection 1.6.8 → 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.
- package/LICENSE +674 -21
- package/README.md +258 -64
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +258 -64
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +3597 -141
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2189 -150
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +522 -27
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/simulationWorker.js +241 -6
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2853 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +61 -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
|
+
}
|