@holoscript/framework 6.0.3
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/ALL-test-results.json +1 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/ROADMAP.md +175 -0
- package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
- package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
- package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
- package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
- package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
- package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
- package/dist/agents/index.cjs +4790 -0
- package/dist/agents/index.d.cts +1788 -0
- package/dist/agents/index.d.ts +1788 -0
- package/dist/agents/index.js +4695 -0
- package/dist/ai/index.cjs +5347 -0
- package/dist/ai/index.d.cts +1753 -0
- package/dist/ai/index.d.ts +1753 -0
- package/dist/ai/index.js +5244 -0
- package/dist/behavior.cjs +449 -0
- package/dist/behavior.d.cts +130 -0
- package/dist/behavior.d.ts +130 -0
- package/dist/behavior.js +407 -0
- package/dist/economy/index.cjs +3659 -0
- package/dist/economy/index.d.cts +747 -0
- package/dist/economy/index.d.ts +747 -0
- package/dist/economy/index.js +3617 -0
- package/dist/implementations-D9T3un9D.d.cts +236 -0
- package/dist/implementations-D9T3un9D.d.ts +236 -0
- package/dist/index.cjs +24550 -0
- package/dist/index.d.cts +1729 -0
- package/dist/index.d.ts +1729 -0
- package/dist/index.js +24277 -0
- package/dist/learning/index.cjs +219 -0
- package/dist/learning/index.d.cts +104 -0
- package/dist/learning/index.d.ts +104 -0
- package/dist/learning/index.js +189 -0
- package/dist/negotiation/index.cjs +970 -0
- package/dist/negotiation/index.d.cts +610 -0
- package/dist/negotiation/index.d.ts +610 -0
- package/dist/negotiation/index.js +931 -0
- package/dist/skills/index.cjs +1118 -0
- package/dist/skills/index.d.cts +289 -0
- package/dist/skills/index.d.ts +289 -0
- package/dist/skills/index.js +1079 -0
- package/dist/swarm/index.cjs +5268 -0
- package/dist/swarm/index.d.cts +2433 -0
- package/dist/swarm/index.d.ts +2433 -0
- package/dist/swarm/index.js +5221 -0
- package/dist/training/index.cjs +2745 -0
- package/dist/training/index.d.cts +1734 -0
- package/dist/training/index.d.ts +1734 -0
- package/dist/training/index.js +2687 -0
- package/extract-failures.js +10 -0
- package/package.json +82 -0
- package/src/__tests__/bounty-marketplace.test.ts +374 -0
- package/src/__tests__/delegation.test.ts +144 -0
- package/src/__tests__/distributed-claimer.test.ts +147 -0
- package/src/__tests__/done-log-audit.test.ts +342 -0
- package/src/__tests__/framework.test.ts +865 -0
- package/src/__tests__/goal-synthesizer.test.ts +236 -0
- package/src/__tests__/presence.test.ts +223 -0
- package/src/__tests__/protocol-agent.test.ts +254 -0
- package/src/__tests__/revenue-splitter.test.ts +114 -0
- package/src/__tests__/scenario-driven-todo.test.ts +197 -0
- package/src/__tests__/self-improve.test.ts +349 -0
- package/src/__tests__/service-lifecycle.test.ts +237 -0
- package/src/__tests__/skill-router.test.ts +121 -0
- package/src/agents/AgentManifest.ts +493 -0
- package/src/agents/AgentRegistry.ts +475 -0
- package/src/agents/AgentTypes.ts +585 -0
- package/src/agents/AgentWalletRegistry.ts +83 -0
- package/src/agents/AuthenticatedCRDT.ts +388 -0
- package/src/agents/CapabilityMatcher.ts +453 -0
- package/src/agents/CrossRealityHandoff.ts +305 -0
- package/src/agents/CulturalMemory.ts +454 -0
- package/src/agents/FederatedRegistryAdapter.ts +429 -0
- package/src/agents/NormEngine.ts +450 -0
- package/src/agents/OrchestratorAgent.ts +414 -0
- package/src/agents/SkillWorkflowEngine.ts +472 -0
- package/src/agents/TaskDelegationService.ts +551 -0
- package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
- package/src/agents/__tests__/AgentManifest.test.ts +182 -0
- package/src/agents/__tests__/AgentModule.test.ts +864 -0
- package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
- package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
- package/src/agents/__tests__/AgentTypes.test.ts +534 -0
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
- package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
- package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
- package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
- package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
- package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
- package/src/agents/__tests__/NormEngine.test.ts +276 -0
- package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
- package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
- package/src/agents/index.ts +107 -0
- package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
- package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
- package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
- package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
- package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
- package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
- package/src/agents/spatial-comms/index.ts +66 -0
- package/src/ai/AIAdapter.ts +313 -0
- package/src/ai/AICopilot.ts +331 -0
- package/src/ai/AIOutputValidator.ts +203 -0
- package/src/ai/BTNodes.ts +239 -0
- package/src/ai/BehaviorSelector.ts +135 -0
- package/src/ai/BehaviorTree.ts +153 -0
- package/src/ai/Blackboard.ts +165 -0
- package/src/ai/GenerationAnalytics.ts +461 -0
- package/src/ai/GenerationCache.ts +265 -0
- package/src/ai/GoalPlanner.ts +165 -0
- package/src/ai/HoloScriptGenerator.ts +580 -0
- package/src/ai/InfluenceMap.ts +180 -0
- package/src/ai/NavMesh.ts +168 -0
- package/src/ai/PerceptionSystem.ts +178 -0
- package/src/ai/PromptTemplates.ts +453 -0
- package/src/ai/SemanticSearchService.ts +80 -0
- package/src/ai/StateMachine.ts +196 -0
- package/src/ai/SteeringBehavior.ts +150 -0
- package/src/ai/SteeringBehaviors.ts +244 -0
- package/src/ai/TrainingDataGenerator.ts +1082 -0
- package/src/ai/UtilityAI.ts +145 -0
- package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
- package/src/ai/__tests__/AIAdapter.test.ts +109 -0
- package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
- package/src/ai/__tests__/AICopilot.test.ts +178 -0
- package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
- package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
- package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
- package/src/ai/__tests__/BTNodes.test.ts +263 -0
- package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
- package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
- package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
- package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
- package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
- package/src/ai/__tests__/Blackboard.test.ts +183 -0
- package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
- package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
- package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
- package/src/ai/__tests__/GenerationCache.test.ts +171 -0
- package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
- package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
- package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
- package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
- package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
- package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
- package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
- package/src/ai/__tests__/NavMesh.test.ts +159 -0
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
- package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
- package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
- package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
- package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
- package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
- package/src/ai/__tests__/StateMachine.test.ts +163 -0
- package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
- package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
- package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
- package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
- package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
- package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
- package/src/ai/__tests__/UtilityAI.test.ts +155 -0
- package/src/ai/__tests__/adapters.prod.test.ts +263 -0
- package/src/ai/__tests__/adapters.test.ts +320 -0
- package/src/ai/adapters.ts +1585 -0
- package/src/ai/index.ts +130 -0
- package/src/behavior/BehaviorPresets.ts +140 -0
- package/src/behavior/BehaviorTree.ts +236 -0
- package/src/behavior/StateMachine.ts +176 -0
- package/src/behavior/StateTrait.ts +67 -0
- package/src/behavior/index.ts +8 -0
- package/src/behavior.ts +8 -0
- package/src/board/audit.ts +284 -0
- package/src/board/board-ops.ts +336 -0
- package/src/board/board-types.ts +302 -0
- package/src/board/index.ts +69 -0
- package/src/define-agent.ts +46 -0
- package/src/define-team.ts +33 -0
- package/src/delegation.ts +265 -0
- package/src/distributed-claimer.ts +228 -0
- package/src/economy/AgentBudgetEnforcer.ts +464 -0
- package/src/economy/BountyManager.ts +185 -0
- package/src/economy/CreatorRevenueAggregator.ts +460 -0
- package/src/economy/InvisibleWallet.ts +82 -0
- package/src/economy/KnowledgeMarketplace.ts +193 -0
- package/src/economy/PaymentWebhookService.ts +512 -0
- package/src/economy/RevenueSplitter.ts +156 -0
- package/src/economy/SubscriptionManager.ts +546 -0
- package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
- package/src/economy/UsageMeter.ts +440 -0
- package/src/economy/_core-stubs.ts +219 -0
- package/src/economy/index.ts +100 -0
- package/src/economy/x402-facilitator.ts +1978 -0
- package/src/index.ts +348 -0
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
- package/src/knowledge/brain.ts +167 -0
- package/src/knowledge/consolidation.ts +581 -0
- package/src/knowledge/knowledge-consolidator.ts +510 -0
- package/src/knowledge/knowledge-store.ts +616 -0
- package/src/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/MemoryScorer.ts +69 -0
- package/src/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/SemanticClusterer.ts +66 -0
- package/src/learning/index.ts +8 -0
- package/src/llm/llm-adapter.ts +159 -0
- package/src/mesh/index.ts +309 -0
- package/src/negotiation/NegotiationProtocol.ts +694 -0
- package/src/negotiation/NegotiationTypes.ts +473 -0
- package/src/negotiation/VotingMechanisms.ts +691 -0
- package/src/negotiation/index.ts +49 -0
- package/src/protocol/goal-synthesizer.ts +317 -0
- package/src/protocol/implementations.ts +474 -0
- package/src/protocol/micro-phase-decomposer.ts +299 -0
- package/src/protocol/micro-step-decomposer.test.ts +306 -0
- package/src/protocol-agent.test.ts +353 -0
- package/src/protocol-agent.ts +670 -0
- package/src/self-improve/absorb-scanner.ts +252 -0
- package/src/self-improve/evolution-engine.ts +149 -0
- package/src/self-improve/framework-absorber.ts +214 -0
- package/src/self-improve/index.ts +50 -0
- package/src/self-improve/prompt-optimizer.ts +212 -0
- package/src/self-improve/test-generator.ts +175 -0
- package/src/skill-router.ts +186 -0
- package/src/skills/index.ts +5 -0
- package/src/skills/skill-md-bridge.ts +1699 -0
- package/src/swarm/ACOEngine.ts +261 -0
- package/src/swarm/CollectiveIntelligence.ts +383 -0
- package/src/swarm/ContributionSynthesizer.ts +481 -0
- package/src/swarm/LeaderElection.ts +393 -0
- package/src/swarm/PSOEngine.ts +206 -0
- package/src/swarm/QuorumPolicy.ts +173 -0
- package/src/swarm/SwarmCoordinator.ts +335 -0
- package/src/swarm/SwarmManager.ts +442 -0
- package/src/swarm/SwarmMembership.ts +456 -0
- package/src/swarm/VotingRound.ts +255 -0
- package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
- package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
- package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
- package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
- package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
- package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
- package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
- package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
- package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
- package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
- package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
- package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
- package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
- package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
- package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
- package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
- package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
- package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
- package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
- package/src/swarm/__tests__/VotingRound.test.ts +174 -0
- package/src/swarm/analytics/SwarmInspector.ts +476 -0
- package/src/swarm/analytics/SwarmMetrics.ts +449 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
- package/src/swarm/analytics/index.ts +7 -0
- package/src/swarm/index.ts +69 -0
- package/src/swarm/messaging/BroadcastChannel.ts +509 -0
- package/src/swarm/messaging/GossipProtocol.ts +565 -0
- package/src/swarm/messaging/SwarmEventBus.ts +443 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
- package/src/swarm/messaging/index.ts +8 -0
- package/src/swarm/spatial/FlockingBehavior.ts +462 -0
- package/src/swarm/spatial/FormationController.ts +500 -0
- package/src/swarm/spatial/Vector3.ts +170 -0
- package/src/swarm/spatial/ZoneClaiming.ts +509 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
- package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
- package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
- package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
- package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
- package/src/swarm/spatial/index.ts +28 -0
- package/src/team.ts +1245 -0
- package/src/training/LRScheduler.ts +377 -0
- package/src/training/QualityScoringPipeline.ts +139 -0
- package/src/training/SoftDedup.ts +461 -0
- package/src/training/SparsityMonitor.ts +685 -0
- package/src/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/constants.ts +94 -0
- package/src/training/index.ts +138 -0
- package/src/training/schema.ts +147 -0
- package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/data/novel-use-cases.jsonl +153 -0
- package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
- package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/trainingmonkey/index.ts +26 -0
- package/src/training/trait-mappings.ts +157 -0
- package/src/types/core-stubs.d.ts +113 -0
- package/src/types.ts +304 -0
- package/test-output.txt +0 -0
- package/test-result.json +1 -0
- package/tsc-errors.txt +4 -0
- package/tsc_output.txt +0 -0
- package/tsconfig.json +14 -0
- package/tsup-learning-esm.config.ts +12 -0
- package/tsup.config.ts +21 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +22 -0
- package/vitest-log-utf8.txt +268 -0
- package/vitest-log.txt +0 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consolidation Engine — Pure state machine for neuroscience-inspired memory consolidation.
|
|
3
|
+
*
|
|
4
|
+
* Absorbed from mcp-server/src/holomesh/crdt-sync.ts (V9 consolidation cycle).
|
|
5
|
+
* Extracts the hot buffer → cold store promotion pipeline as a standalone engine
|
|
6
|
+
* with no CRDT, HTTP, or persistence dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Algorithm (6-phase biological consolidation cycle):
|
|
9
|
+
* 1. REPLAY — Filter hot buffer by TTL + corroboration threshold
|
|
10
|
+
* 1.5 SANITIZE — Reject entries with injection patterns (defense-in-depth)
|
|
11
|
+
* 2. CLUSTER — Find duplicate/overlapping entries by content+type
|
|
12
|
+
* 3. MERGE — Combine corroborations from duplicates
|
|
13
|
+
* 4. DOWNSCALE — Reduce all cold store excitability (synaptic homeostasis)
|
|
14
|
+
* 5. PROMOTE — Move surviving hot entries to cold store with metadata
|
|
15
|
+
* 6. PRUNE — Evict lowest-excitability entries when over capacity
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
KNOWLEDGE_DOMAINS,
|
|
20
|
+
DOMAIN_CONSOLIDATION,
|
|
21
|
+
type KnowledgeDomain,
|
|
22
|
+
type HotBufferEntry,
|
|
23
|
+
type ExcitabilityMetadata,
|
|
24
|
+
type ConsolidationResult,
|
|
25
|
+
type DomainConsolidationConfig,
|
|
26
|
+
type ReconsolidationEvent,
|
|
27
|
+
computeExcitability,
|
|
28
|
+
RECONSOLIDATION_WINDOW_MS,
|
|
29
|
+
} from './brain';
|
|
30
|
+
|
|
31
|
+
// ── Cold Store Entry ──
|
|
32
|
+
|
|
33
|
+
export interface ColdStoreEntry {
|
|
34
|
+
id: string;
|
|
35
|
+
content: string;
|
|
36
|
+
type: string;
|
|
37
|
+
authorDid: string;
|
|
38
|
+
tags: string[];
|
|
39
|
+
timestamp: number;
|
|
40
|
+
accessCount: number;
|
|
41
|
+
lastAccessed: number;
|
|
42
|
+
_excitability: ExcitabilityMetadata;
|
|
43
|
+
_contradictions?: string[];
|
|
44
|
+
_deprecated?: boolean;
|
|
45
|
+
_deprecatedAt?: number;
|
|
46
|
+
_deprecationReason?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Helpers ──
|
|
50
|
+
|
|
51
|
+
function defaultExcitability(): ExcitabilityMetadata {
|
|
52
|
+
return {
|
|
53
|
+
queryCount: 0,
|
|
54
|
+
citationCount: 0,
|
|
55
|
+
corroborationCount: 0,
|
|
56
|
+
excitability: 0,
|
|
57
|
+
lastRetrievedAt: 0,
|
|
58
|
+
lastReconsolidatedAt: 0,
|
|
59
|
+
consolidationSurvivals: 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Detect injection patterns in knowledge entry content.
|
|
65
|
+
* Defense-in-depth: catches code-like payloads that could exploit
|
|
66
|
+
* downstream compilers (CWE-94) if they reach cold store.
|
|
67
|
+
*/
|
|
68
|
+
function containsInjectionPattern(content: string): boolean {
|
|
69
|
+
if (!content || typeof content !== 'string') return false;
|
|
70
|
+
|
|
71
|
+
if (/["'];?\s*(import|require|exec|system|Process|eval|Function)\s*[.(]/i.test(content)) return true;
|
|
72
|
+
if (/<script[\s>]/i.test(content)) return true;
|
|
73
|
+
if (/\b(os\.execute|os\.system|Runtime\.getRuntime|child_process|Process\.Start)\s*\(/i.test(content)) return true;
|
|
74
|
+
if (/#\s*(include|pragma|define)\b/i.test(content)) return true;
|
|
75
|
+
if (content.includes('\0')) return true;
|
|
76
|
+
if (/OS\.(execute|shell_open)\s*\(/i.test(content)) return true;
|
|
77
|
+
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get excitability score for an entry based on the domain's competition metric.
|
|
83
|
+
*/
|
|
84
|
+
function getEntryExcitability(
|
|
85
|
+
entry: ColdStoreEntry,
|
|
86
|
+
metric: DomainConsolidationConfig['competitionMetric']
|
|
87
|
+
): number {
|
|
88
|
+
const meta = entry._excitability || defaultExcitability();
|
|
89
|
+
switch (metric) {
|
|
90
|
+
case 'query_frequency':
|
|
91
|
+
return meta.queryCount;
|
|
92
|
+
case 'citation_count':
|
|
93
|
+
return meta.citationCount;
|
|
94
|
+
case 'peer_corroboration':
|
|
95
|
+
return meta.corroborationCount;
|
|
96
|
+
default:
|
|
97
|
+
return meta.excitability;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Consolidation Engine ──
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* ConsolidationEngine manages hot buffer + cold store per knowledge domain.
|
|
105
|
+
*
|
|
106
|
+
* Pure state machine — no HTTP, no CRDT, no persistence.
|
|
107
|
+
* Feed it entries via `ingest()`, run cycles via `runConsolidationCycle()`,
|
|
108
|
+
* and read results via `getHotBuffer()` / `getColdStore()`.
|
|
109
|
+
*/
|
|
110
|
+
export class ConsolidationEngine {
|
|
111
|
+
private hotBuffers: Map<KnowledgeDomain, HotBufferEntry[]> = new Map();
|
|
112
|
+
private coldStores: Map<KnowledgeDomain, Map<string, ColdStoreEntry>> = new Map();
|
|
113
|
+
private lastConsolidation: Map<KnowledgeDomain, number> = new Map();
|
|
114
|
+
private reconsolidationWindows: Map<string, ReconsolidationEvent> = new Map();
|
|
115
|
+
|
|
116
|
+
constructor() {
|
|
117
|
+
for (const domain of KNOWLEDGE_DOMAINS) {
|
|
118
|
+
this.hotBuffers.set(domain, []);
|
|
119
|
+
this.coldStores.set(domain, new Map());
|
|
120
|
+
this.lastConsolidation.set(domain, Date.now());
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Ingestion ──
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Ingest knowledge into the hot buffer (hippocampus).
|
|
128
|
+
* Entries stage here until a consolidation cycle promotes them.
|
|
129
|
+
*/
|
|
130
|
+
ingest(
|
|
131
|
+
domain: KnowledgeDomain,
|
|
132
|
+
entry: { content: string; type: string; authorDid: string; tags: string[] },
|
|
133
|
+
sourcePeerDid: string
|
|
134
|
+
): HotBufferEntry {
|
|
135
|
+
const buffer = this.hotBuffers.get(domain) || [];
|
|
136
|
+
const hotEntry: HotBufferEntry = {
|
|
137
|
+
id: `hot_${domain}_${Date.now()}_${buffer.length}`,
|
|
138
|
+
domain,
|
|
139
|
+
content: entry.content,
|
|
140
|
+
type: entry.type,
|
|
141
|
+
authorDid: entry.authorDid,
|
|
142
|
+
tags: entry.tags,
|
|
143
|
+
ingestedAt: Date.now(),
|
|
144
|
+
corroborations: [sourcePeerDid],
|
|
145
|
+
sourcePeerDid,
|
|
146
|
+
};
|
|
147
|
+
buffer.push(hotEntry);
|
|
148
|
+
this.hotBuffers.set(domain, buffer);
|
|
149
|
+
return hotEntry;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Corroborate a hot buffer entry (another peer independently confirms it).
|
|
154
|
+
* Increases promotion likelihood during consolidation.
|
|
155
|
+
*/
|
|
156
|
+
corroborate(domain: KnowledgeDomain, entryId: string, peerDid: string): boolean {
|
|
157
|
+
const buffer = this.hotBuffers.get(domain) || [];
|
|
158
|
+
const entry = buffer.find(e => e.id === entryId);
|
|
159
|
+
if (!entry) return false;
|
|
160
|
+
if (!entry.corroborations.includes(peerDid)) {
|
|
161
|
+
entry.corroborations.push(peerDid);
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── Cold Store Direct Operations ──
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Seed cold store directly (for loading persisted state).
|
|
170
|
+
*/
|
|
171
|
+
seedColdStore(domain: KnowledgeDomain, entries: ColdStoreEntry[]): void {
|
|
172
|
+
const store = this.coldStores.get(domain) || new Map();
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
store.set(entry.id, entry);
|
|
175
|
+
}
|
|
176
|
+
this.coldStores.set(domain, store);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ── Consolidation Cycle ──
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Run a consolidation (sleep) cycle for a specific domain.
|
|
183
|
+
*
|
|
184
|
+
* Implements the 6-phase biological consolidation cycle:
|
|
185
|
+
* 1. REPLAY — Filter hot buffer by TTL and corroboration threshold
|
|
186
|
+
* 1.5 SANITIZE — Reject entries with injection patterns
|
|
187
|
+
* 2. CLUSTER — Find duplicate/overlapping entries (content+type match)
|
|
188
|
+
* 3. MERGE — Combine corroborations from duplicates
|
|
189
|
+
* 4. DOWNSCALE — Reduce all cold store excitability (synaptic homeostasis)
|
|
190
|
+
* 5. PROMOTE — Move validated entries from hot buffer to cold store
|
|
191
|
+
* 6. PRUNE — Evict lowest-excitability entries if over capacity
|
|
192
|
+
*/
|
|
193
|
+
runConsolidationCycle(domain: KnowledgeDomain): ConsolidationResult {
|
|
194
|
+
const config = DOMAIN_CONSOLIDATION[domain];
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
const buffer = this.hotBuffers.get(domain) || [];
|
|
197
|
+
const coldStore = this.coldStores.get(domain) || new Map();
|
|
198
|
+
|
|
199
|
+
let promoted = 0;
|
|
200
|
+
let merged = 0;
|
|
201
|
+
let evicted = 0;
|
|
202
|
+
let dropped = 0;
|
|
203
|
+
|
|
204
|
+
// Phase 1: REPLAY — filter hot buffer by TTL and corroboration threshold
|
|
205
|
+
const eligible: HotBufferEntry[] = [];
|
|
206
|
+
const tooYoung: HotBufferEntry[] = [];
|
|
207
|
+
for (const entry of buffer) {
|
|
208
|
+
const age = now - entry.ingestedAt;
|
|
209
|
+
if (age < config.hotBufferTTL) {
|
|
210
|
+
tooYoung.push(entry); // Keep in hot buffer — not old enough
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (entry.corroborations.length >= config.minCorroborations) {
|
|
214
|
+
eligible.push(entry);
|
|
215
|
+
} else {
|
|
216
|
+
dropped++; // Failed corroboration check — forgotten
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Phase 1.5: SANITIZE — check content for injection patterns before promotion
|
|
221
|
+
const sanitized: HotBufferEntry[] = [];
|
|
222
|
+
for (const entry of eligible) {
|
|
223
|
+
if (containsInjectionPattern(entry.content)) {
|
|
224
|
+
dropped++; // Injection pattern detected — drop silently
|
|
225
|
+
} else {
|
|
226
|
+
sanitized.push(entry);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Phase 2 & 3: CLUSTER + MERGE — deduplicate by content+type equality
|
|
231
|
+
const uniqueEntries: HotBufferEntry[] = [];
|
|
232
|
+
for (const entry of sanitized) {
|
|
233
|
+
const duplicate = uniqueEntries.find(e =>
|
|
234
|
+
e.content === entry.content && e.type === entry.type
|
|
235
|
+
);
|
|
236
|
+
if (duplicate) {
|
|
237
|
+
// Merge corroborations from duplicate
|
|
238
|
+
for (const peer of entry.corroborations) {
|
|
239
|
+
if (!duplicate.corroborations.includes(peer)) {
|
|
240
|
+
duplicate.corroborations.push(peer);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
merged++;
|
|
244
|
+
} else {
|
|
245
|
+
uniqueEntries.push(entry);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Phase 4: DOWNSCALE — reduce all cold store excitability (synaptic homeostasis)
|
|
250
|
+
coldStore.forEach((entry) => {
|
|
251
|
+
const meta = entry._excitability;
|
|
252
|
+
meta.excitability = computeExcitability(meta) * config.downscaleFactor;
|
|
253
|
+
meta.consolidationSurvivals++;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Phase 5: PROMOTE — move surviving entries from hot buffer to cold store
|
|
257
|
+
for (const entry of uniqueEntries) {
|
|
258
|
+
const entryId = `${entry.type.charAt(0).toUpperCase()}.${domain.toUpperCase().slice(0, 3)}.${now}_${promoted}`;
|
|
259
|
+
const excitability = defaultExcitability();
|
|
260
|
+
excitability.corroborationCount = entry.corroborations.length;
|
|
261
|
+
excitability.excitability = computeExcitability(excitability);
|
|
262
|
+
|
|
263
|
+
const coldEntry: ColdStoreEntry = {
|
|
264
|
+
id: entryId,
|
|
265
|
+
content: entry.content,
|
|
266
|
+
type: entry.type,
|
|
267
|
+
authorDid: entry.authorDid,
|
|
268
|
+
tags: entry.tags,
|
|
269
|
+
timestamp: entry.ingestedAt,
|
|
270
|
+
accessCount: 0,
|
|
271
|
+
lastAccessed: 0,
|
|
272
|
+
_excitability: excitability,
|
|
273
|
+
};
|
|
274
|
+
coldStore.set(entryId, coldEntry);
|
|
275
|
+
promoted++;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Phase 6: PRUNE — engram competition if over capacity
|
|
279
|
+
if (coldStore.size > config.maxEntries) {
|
|
280
|
+
const sorted = Array.from(coldStore.entries())
|
|
281
|
+
.map(([id, entry]) => ({
|
|
282
|
+
id,
|
|
283
|
+
score: getEntryExcitability(entry, config.competitionMetric),
|
|
284
|
+
}))
|
|
285
|
+
.sort((a, b) => a.score - b.score);
|
|
286
|
+
|
|
287
|
+
const toEvict = sorted.slice(0, coldStore.size - config.maxEntries);
|
|
288
|
+
for (const { id } of toEvict) {
|
|
289
|
+
coldStore.delete(id);
|
|
290
|
+
evicted++;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Replace hot buffer with entries that were too young
|
|
295
|
+
this.hotBuffers.set(domain, tooYoung);
|
|
296
|
+
this.coldStores.set(domain, coldStore);
|
|
297
|
+
this.lastConsolidation.set(domain, now);
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
domain,
|
|
301
|
+
promoted,
|
|
302
|
+
merged,
|
|
303
|
+
evicted,
|
|
304
|
+
dropped,
|
|
305
|
+
downscaleFactor: config.downscaleFactor,
|
|
306
|
+
consolidatedAt: now,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Run consolidation across ALL domains (full sleep cycle).
|
|
312
|
+
* Only consolidates domains whose sleepFrequency has elapsed.
|
|
313
|
+
*/
|
|
314
|
+
sleepCycle(force: boolean = false): ConsolidationResult[] {
|
|
315
|
+
const now = Date.now();
|
|
316
|
+
const results: ConsolidationResult[] = [];
|
|
317
|
+
|
|
318
|
+
for (const domain of KNOWLEDGE_DOMAINS) {
|
|
319
|
+
const config = DOMAIN_CONSOLIDATION[domain];
|
|
320
|
+
const lastRun = this.lastConsolidation.get(domain) || 0;
|
|
321
|
+
const elapsed = now - lastRun;
|
|
322
|
+
|
|
323
|
+
if (force || elapsed >= config.sleepFrequencyMs) {
|
|
324
|
+
results.push(this.runConsolidationCycle(domain));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return results;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Check if any domain needs a consolidation cycle.
|
|
333
|
+
*/
|
|
334
|
+
needsConsolidation(): { domain: KnowledgeDomain; overdue: boolean; bufferSize: number }[] {
|
|
335
|
+
const now = Date.now();
|
|
336
|
+
return KNOWLEDGE_DOMAINS.map(domain => {
|
|
337
|
+
const config = DOMAIN_CONSOLIDATION[domain];
|
|
338
|
+
const lastRun = this.lastConsolidation.get(domain) || 0;
|
|
339
|
+
const elapsed = now - lastRun;
|
|
340
|
+
const buffer = this.hotBuffers.get(domain) || [];
|
|
341
|
+
return {
|
|
342
|
+
domain,
|
|
343
|
+
overdue: elapsed >= config.sleepFrequencyMs,
|
|
344
|
+
bufferSize: buffer.length,
|
|
345
|
+
};
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ── Reconsolidation (retrieval strengthening) ──
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Retrieve a cold store entry with excitability strengthening.
|
|
353
|
+
* Every retrieval is a read-modify-write that strengthens the entry
|
|
354
|
+
* and opens a reconsolidation window for updates.
|
|
355
|
+
*/
|
|
356
|
+
retrieveWithReconsolidation(
|
|
357
|
+
domain: KnowledgeDomain,
|
|
358
|
+
entryId: string
|
|
359
|
+
): { entry: ColdStoreEntry; reconsolidation: ReconsolidationEvent } | null {
|
|
360
|
+
const coldStore = this.coldStores.get(domain);
|
|
361
|
+
if (!coldStore) return null;
|
|
362
|
+
|
|
363
|
+
const entry = coldStore.get(entryId);
|
|
364
|
+
if (!entry) return null;
|
|
365
|
+
|
|
366
|
+
const now = Date.now();
|
|
367
|
+
const meta = entry._excitability;
|
|
368
|
+
|
|
369
|
+
// Retrieval practice effect: strengthen on access
|
|
370
|
+
meta.queryCount++;
|
|
371
|
+
meta.lastRetrievedAt = now;
|
|
372
|
+
meta.excitability = computeExcitability(meta);
|
|
373
|
+
|
|
374
|
+
entry.accessCount++;
|
|
375
|
+
entry.lastAccessed = now;
|
|
376
|
+
|
|
377
|
+
// Open reconsolidation window
|
|
378
|
+
const reconEvent: ReconsolidationEvent = {
|
|
379
|
+
entryId,
|
|
380
|
+
domain,
|
|
381
|
+
retrievedAt: now,
|
|
382
|
+
excitabilityDelta: 2,
|
|
383
|
+
windowOpen: true,
|
|
384
|
+
windowClosesAt: now + RECONSOLIDATION_WINDOW_MS,
|
|
385
|
+
};
|
|
386
|
+
this.reconsolidationWindows.set(entryId, reconEvent);
|
|
387
|
+
|
|
388
|
+
return { entry, reconsolidation: reconEvent };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Update an entry during its reconsolidation window.
|
|
393
|
+
* Returns false if the window is closed or entry not found.
|
|
394
|
+
*/
|
|
395
|
+
reconsolidateEntry(
|
|
396
|
+
domain: KnowledgeDomain,
|
|
397
|
+
entryId: string,
|
|
398
|
+
updatedContent: string
|
|
399
|
+
): boolean {
|
|
400
|
+
const window = this.reconsolidationWindows.get(entryId);
|
|
401
|
+
if (!window || !window.windowOpen || Date.now() > window.windowClosesAt) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const coldStore = this.coldStores.get(domain);
|
|
406
|
+
if (!coldStore) return false;
|
|
407
|
+
|
|
408
|
+
const entry = coldStore.get(entryId);
|
|
409
|
+
if (!entry) return false;
|
|
410
|
+
|
|
411
|
+
entry.content = updatedContent;
|
|
412
|
+
entry._excitability.lastReconsolidatedAt = Date.now();
|
|
413
|
+
|
|
414
|
+
// Close the window after reconsolidation
|
|
415
|
+
window.windowOpen = false;
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ── Active Forgetting ──
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Mark an entry as contradicted by a peer.
|
|
423
|
+
* 3+ contradictions → pruned (microglia-mediated removal).
|
|
424
|
+
*/
|
|
425
|
+
contradictEntry(
|
|
426
|
+
domain: KnowledgeDomain,
|
|
427
|
+
entryId: string,
|
|
428
|
+
contradictingPeerDid: string
|
|
429
|
+
): { contradicted: boolean; pruned: boolean } {
|
|
430
|
+
const coldStore = this.coldStores.get(domain);
|
|
431
|
+
if (!coldStore) return { contradicted: false, pruned: false };
|
|
432
|
+
|
|
433
|
+
const entry = coldStore.get(entryId);
|
|
434
|
+
if (!entry) return { contradicted: false, pruned: false };
|
|
435
|
+
|
|
436
|
+
if (!entry._contradictions) entry._contradictions = [];
|
|
437
|
+
if (!entry._contradictions.includes(contradictingPeerDid)) {
|
|
438
|
+
entry._contradictions.push(contradictingPeerDid);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// 3+ peer contradictions → prune
|
|
442
|
+
if (entry._contradictions.length >= 3) {
|
|
443
|
+
coldStore.delete(entryId);
|
|
444
|
+
return { contradicted: true, pruned: true };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Reduce excitability on contradiction
|
|
448
|
+
entry._excitability.excitability = Math.max(0, entry._excitability.excitability - 5);
|
|
449
|
+
return { contradicted: true, pruned: false };
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Deprecate an entry (self-superseding).
|
|
454
|
+
* Zeroes excitability — will be pruned in next consolidation cycle.
|
|
455
|
+
*/
|
|
456
|
+
deprecateEntry(domain: KnowledgeDomain, entryId: string, reason: string): boolean {
|
|
457
|
+
const coldStore = this.coldStores.get(domain);
|
|
458
|
+
if (!coldStore) return false;
|
|
459
|
+
|
|
460
|
+
const entry = coldStore.get(entryId);
|
|
461
|
+
if (!entry) return false;
|
|
462
|
+
|
|
463
|
+
entry._deprecated = true;
|
|
464
|
+
entry._deprecatedAt = Date.now();
|
|
465
|
+
entry._deprecationReason = reason;
|
|
466
|
+
entry._excitability.excitability = 0;
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// ── Inspection ──
|
|
471
|
+
|
|
472
|
+
/** Get hot buffer contents for a domain (copy). */
|
|
473
|
+
getHotBuffer(domain: KnowledgeDomain): HotBufferEntry[] {
|
|
474
|
+
return [...(this.hotBuffers.get(domain) || [])];
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** Get cold store entries for a domain (copy). */
|
|
478
|
+
getColdStore(domain: KnowledgeDomain): ColdStoreEntry[] {
|
|
479
|
+
const store = this.coldStores.get(domain);
|
|
480
|
+
if (!store) return [];
|
|
481
|
+
return Array.from(store.values());
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Get cold store entry by ID. */
|
|
485
|
+
getColdStoreEntry(domain: KnowledgeDomain, entryId: string): ColdStoreEntry | undefined {
|
|
486
|
+
return this.coldStores.get(domain)?.get(entryId);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Get hot buffer size across all domains. */
|
|
490
|
+
getHotBufferStats(): { domain: string; count: number }[] {
|
|
491
|
+
return KNOWLEDGE_DOMAINS.map(domain => ({
|
|
492
|
+
domain,
|
|
493
|
+
count: (this.hotBuffers.get(domain) || []).length,
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** Get cold store size across all domains. */
|
|
498
|
+
getColdStoreStats(): { domain: string; count: number }[] {
|
|
499
|
+
return KNOWLEDGE_DOMAINS.map(domain => ({
|
|
500
|
+
domain,
|
|
501
|
+
count: (this.coldStores.get(domain) || new Map()).size,
|
|
502
|
+
}));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** Get consolidation config for a domain. */
|
|
506
|
+
getDomainConfig(domain: KnowledgeDomain): DomainConsolidationConfig {
|
|
507
|
+
return { ...DOMAIN_CONSOLIDATION[domain] };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// ── Cross-Domain Pattern Surfacing (FW-0.5) ──
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Surface entries that appear across multiple domains, indicating cross-cutting patterns.
|
|
514
|
+
* Uses token overlap to find similar entries in different domains.
|
|
515
|
+
* Returns pairs of entries whose content overlaps above the threshold.
|
|
516
|
+
*/
|
|
517
|
+
surfaceCrossDomainPatterns(minOverlap: number = 0.3): CrossDomainMatch[] {
|
|
518
|
+
const matches: CrossDomainMatch[] = [];
|
|
519
|
+
const domainEntries: Array<{ domain: KnowledgeDomain; entries: ColdStoreEntry[] }> = [];
|
|
520
|
+
|
|
521
|
+
for (const domain of KNOWLEDGE_DOMAINS) {
|
|
522
|
+
const store = this.coldStores.get(domain);
|
|
523
|
+
if (store && store.size > 0) {
|
|
524
|
+
domainEntries.push({ domain, entries: Array.from(store.values()) });
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Compare entries across all domain pairs
|
|
529
|
+
for (let i = 0; i < domainEntries.length; i++) {
|
|
530
|
+
for (let j = i + 1; j < domainEntries.length; j++) {
|
|
531
|
+
const domA = domainEntries[i];
|
|
532
|
+
const domB = domainEntries[j];
|
|
533
|
+
|
|
534
|
+
for (const a of domA.entries) {
|
|
535
|
+
const tokensA = tokenize(a.content);
|
|
536
|
+
if (tokensA.size < 3) continue;
|
|
537
|
+
|
|
538
|
+
for (const b of domB.entries) {
|
|
539
|
+
const tokensB = tokenize(b.content);
|
|
540
|
+
if (tokensB.size < 3) continue;
|
|
541
|
+
|
|
542
|
+
const overlap = setOverlap(tokensA, tokensB);
|
|
543
|
+
if (overlap >= minOverlap) {
|
|
544
|
+
matches.push({
|
|
545
|
+
entryA: { id: a.id, domain: domA.domain, content: a.content },
|
|
546
|
+
entryB: { id: b.id, domain: domB.domain, content: b.content },
|
|
547
|
+
overlap,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return matches.sort((a, b) => b.overlap - a.overlap);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// ── Cross-Domain Types ──
|
|
560
|
+
|
|
561
|
+
export interface CrossDomainMatch {
|
|
562
|
+
entryA: { id: string; domain: KnowledgeDomain; content: string };
|
|
563
|
+
entryB: { id: string; domain: KnowledgeDomain; content: string };
|
|
564
|
+
overlap: number;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** Tokenize content into a set of lowercase words (3+ chars). */
|
|
568
|
+
function tokenize(content: string): Set<string> {
|
|
569
|
+
return new Set(
|
|
570
|
+
content.toLowerCase().match(/[a-z0-9]{3,}/g) || []
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** Jaccard overlap between two sets. */
|
|
575
|
+
function setOverlap(a: Set<string>, b: Set<string>): number {
|
|
576
|
+
let intersection = 0;
|
|
577
|
+
for (const token of a) {
|
|
578
|
+
if (b.has(token)) intersection++;
|
|
579
|
+
}
|
|
580
|
+
return intersection / (a.size + b.size - intersection);
|
|
581
|
+
}
|