@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.
Files changed (329) hide show
  1. package/ALL-test-results.json +1 -0
  2. package/CHANGELOG.md +8 -0
  3. package/LICENSE +21 -0
  4. package/ROADMAP.md +175 -0
  5. package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
  6. package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
  7. package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
  8. package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
  9. package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
  10. package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
  11. package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
  12. package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
  13. package/dist/agents/index.cjs +4790 -0
  14. package/dist/agents/index.d.cts +1788 -0
  15. package/dist/agents/index.d.ts +1788 -0
  16. package/dist/agents/index.js +4695 -0
  17. package/dist/ai/index.cjs +5347 -0
  18. package/dist/ai/index.d.cts +1753 -0
  19. package/dist/ai/index.d.ts +1753 -0
  20. package/dist/ai/index.js +5244 -0
  21. package/dist/behavior.cjs +449 -0
  22. package/dist/behavior.d.cts +130 -0
  23. package/dist/behavior.d.ts +130 -0
  24. package/dist/behavior.js +407 -0
  25. package/dist/economy/index.cjs +3659 -0
  26. package/dist/economy/index.d.cts +747 -0
  27. package/dist/economy/index.d.ts +747 -0
  28. package/dist/economy/index.js +3617 -0
  29. package/dist/implementations-D9T3un9D.d.cts +236 -0
  30. package/dist/implementations-D9T3un9D.d.ts +236 -0
  31. package/dist/index.cjs +24550 -0
  32. package/dist/index.d.cts +1729 -0
  33. package/dist/index.d.ts +1729 -0
  34. package/dist/index.js +24277 -0
  35. package/dist/learning/index.cjs +219 -0
  36. package/dist/learning/index.d.cts +104 -0
  37. package/dist/learning/index.d.ts +104 -0
  38. package/dist/learning/index.js +189 -0
  39. package/dist/negotiation/index.cjs +970 -0
  40. package/dist/negotiation/index.d.cts +610 -0
  41. package/dist/negotiation/index.d.ts +610 -0
  42. package/dist/negotiation/index.js +931 -0
  43. package/dist/skills/index.cjs +1118 -0
  44. package/dist/skills/index.d.cts +289 -0
  45. package/dist/skills/index.d.ts +289 -0
  46. package/dist/skills/index.js +1079 -0
  47. package/dist/swarm/index.cjs +5268 -0
  48. package/dist/swarm/index.d.cts +2433 -0
  49. package/dist/swarm/index.d.ts +2433 -0
  50. package/dist/swarm/index.js +5221 -0
  51. package/dist/training/index.cjs +2745 -0
  52. package/dist/training/index.d.cts +1734 -0
  53. package/dist/training/index.d.ts +1734 -0
  54. package/dist/training/index.js +2687 -0
  55. package/extract-failures.js +10 -0
  56. package/package.json +82 -0
  57. package/src/__tests__/bounty-marketplace.test.ts +374 -0
  58. package/src/__tests__/delegation.test.ts +144 -0
  59. package/src/__tests__/distributed-claimer.test.ts +147 -0
  60. package/src/__tests__/done-log-audit.test.ts +342 -0
  61. package/src/__tests__/framework.test.ts +865 -0
  62. package/src/__tests__/goal-synthesizer.test.ts +236 -0
  63. package/src/__tests__/presence.test.ts +223 -0
  64. package/src/__tests__/protocol-agent.test.ts +254 -0
  65. package/src/__tests__/revenue-splitter.test.ts +114 -0
  66. package/src/__tests__/scenario-driven-todo.test.ts +197 -0
  67. package/src/__tests__/self-improve.test.ts +349 -0
  68. package/src/__tests__/service-lifecycle.test.ts +237 -0
  69. package/src/__tests__/skill-router.test.ts +121 -0
  70. package/src/agents/AgentManifest.ts +493 -0
  71. package/src/agents/AgentRegistry.ts +475 -0
  72. package/src/agents/AgentTypes.ts +585 -0
  73. package/src/agents/AgentWalletRegistry.ts +83 -0
  74. package/src/agents/AuthenticatedCRDT.ts +388 -0
  75. package/src/agents/CapabilityMatcher.ts +453 -0
  76. package/src/agents/CrossRealityHandoff.ts +305 -0
  77. package/src/agents/CulturalMemory.ts +454 -0
  78. package/src/agents/FederatedRegistryAdapter.ts +429 -0
  79. package/src/agents/NormEngine.ts +450 -0
  80. package/src/agents/OrchestratorAgent.ts +414 -0
  81. package/src/agents/SkillWorkflowEngine.ts +472 -0
  82. package/src/agents/TaskDelegationService.ts +551 -0
  83. package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
  84. package/src/agents/__tests__/AgentManifest.test.ts +182 -0
  85. package/src/agents/__tests__/AgentModule.test.ts +864 -0
  86. package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
  87. package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
  88. package/src/agents/__tests__/AgentTypes.test.ts +534 -0
  89. package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
  90. package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
  91. package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
  92. package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
  93. package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
  94. package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
  95. package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
  96. package/src/agents/__tests__/NormEngine.test.ts +276 -0
  97. package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
  98. package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
  99. package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
  100. package/src/agents/index.ts +107 -0
  101. package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
  102. package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
  103. package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
  104. package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
  105. package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
  106. package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
  107. package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
  108. package/src/agents/spatial-comms/index.ts +66 -0
  109. package/src/ai/AIAdapter.ts +313 -0
  110. package/src/ai/AICopilot.ts +331 -0
  111. package/src/ai/AIOutputValidator.ts +203 -0
  112. package/src/ai/BTNodes.ts +239 -0
  113. package/src/ai/BehaviorSelector.ts +135 -0
  114. package/src/ai/BehaviorTree.ts +153 -0
  115. package/src/ai/Blackboard.ts +165 -0
  116. package/src/ai/GenerationAnalytics.ts +461 -0
  117. package/src/ai/GenerationCache.ts +265 -0
  118. package/src/ai/GoalPlanner.ts +165 -0
  119. package/src/ai/HoloScriptGenerator.ts +580 -0
  120. package/src/ai/InfluenceMap.ts +180 -0
  121. package/src/ai/NavMesh.ts +168 -0
  122. package/src/ai/PerceptionSystem.ts +178 -0
  123. package/src/ai/PromptTemplates.ts +453 -0
  124. package/src/ai/SemanticSearchService.ts +80 -0
  125. package/src/ai/StateMachine.ts +196 -0
  126. package/src/ai/SteeringBehavior.ts +150 -0
  127. package/src/ai/SteeringBehaviors.ts +244 -0
  128. package/src/ai/TrainingDataGenerator.ts +1082 -0
  129. package/src/ai/UtilityAI.ts +145 -0
  130. package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
  131. package/src/ai/__tests__/AIAdapter.test.ts +109 -0
  132. package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
  133. package/src/ai/__tests__/AICopilot.test.ts +178 -0
  134. package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
  135. package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
  136. package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
  137. package/src/ai/__tests__/BTNodes.test.ts +263 -0
  138. package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
  139. package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
  140. package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
  141. package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
  142. package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
  143. package/src/ai/__tests__/Blackboard.test.ts +183 -0
  144. package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
  145. package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
  146. package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
  147. package/src/ai/__tests__/GenerationCache.test.ts +171 -0
  148. package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
  149. package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
  150. package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
  151. package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
  152. package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
  153. package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
  154. package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
  155. package/src/ai/__tests__/NavMesh.test.ts +159 -0
  156. package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
  157. package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
  158. package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
  159. package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
  160. package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
  161. package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
  162. package/src/ai/__tests__/StateMachine.test.ts +163 -0
  163. package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
  164. package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
  165. package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
  166. package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
  167. package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
  168. package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
  169. package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
  170. package/src/ai/__tests__/UtilityAI.test.ts +155 -0
  171. package/src/ai/__tests__/adapters.prod.test.ts +263 -0
  172. package/src/ai/__tests__/adapters.test.ts +320 -0
  173. package/src/ai/adapters.ts +1585 -0
  174. package/src/ai/index.ts +130 -0
  175. package/src/behavior/BehaviorPresets.ts +140 -0
  176. package/src/behavior/BehaviorTree.ts +236 -0
  177. package/src/behavior/StateMachine.ts +176 -0
  178. package/src/behavior/StateTrait.ts +67 -0
  179. package/src/behavior/index.ts +8 -0
  180. package/src/behavior.ts +8 -0
  181. package/src/board/audit.ts +284 -0
  182. package/src/board/board-ops.ts +336 -0
  183. package/src/board/board-types.ts +302 -0
  184. package/src/board/index.ts +69 -0
  185. package/src/define-agent.ts +46 -0
  186. package/src/define-team.ts +33 -0
  187. package/src/delegation.ts +265 -0
  188. package/src/distributed-claimer.ts +228 -0
  189. package/src/economy/AgentBudgetEnforcer.ts +464 -0
  190. package/src/economy/BountyManager.ts +185 -0
  191. package/src/economy/CreatorRevenueAggregator.ts +460 -0
  192. package/src/economy/InvisibleWallet.ts +82 -0
  193. package/src/economy/KnowledgeMarketplace.ts +193 -0
  194. package/src/economy/PaymentWebhookService.ts +512 -0
  195. package/src/economy/RevenueSplitter.ts +156 -0
  196. package/src/economy/SubscriptionManager.ts +546 -0
  197. package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
  198. package/src/economy/UsageMeter.ts +440 -0
  199. package/src/economy/_core-stubs.ts +219 -0
  200. package/src/economy/index.ts +100 -0
  201. package/src/economy/x402-facilitator.ts +1978 -0
  202. package/src/index.ts +348 -0
  203. package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
  204. package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
  205. package/src/knowledge/brain.ts +167 -0
  206. package/src/knowledge/consolidation.ts +581 -0
  207. package/src/knowledge/knowledge-consolidator.ts +510 -0
  208. package/src/knowledge/knowledge-store.ts +616 -0
  209. package/src/learning/MemoryConsolidator.ts +102 -0
  210. package/src/learning/MemoryScorer.ts +69 -0
  211. package/src/learning/ProceduralCompiler.ts +45 -0
  212. package/src/learning/SemanticClusterer.ts +66 -0
  213. package/src/learning/index.ts +8 -0
  214. package/src/llm/llm-adapter.ts +159 -0
  215. package/src/mesh/index.ts +309 -0
  216. package/src/negotiation/NegotiationProtocol.ts +694 -0
  217. package/src/negotiation/NegotiationTypes.ts +473 -0
  218. package/src/negotiation/VotingMechanisms.ts +691 -0
  219. package/src/negotiation/index.ts +49 -0
  220. package/src/protocol/goal-synthesizer.ts +317 -0
  221. package/src/protocol/implementations.ts +474 -0
  222. package/src/protocol/micro-phase-decomposer.ts +299 -0
  223. package/src/protocol/micro-step-decomposer.test.ts +306 -0
  224. package/src/protocol-agent.test.ts +353 -0
  225. package/src/protocol-agent.ts +670 -0
  226. package/src/self-improve/absorb-scanner.ts +252 -0
  227. package/src/self-improve/evolution-engine.ts +149 -0
  228. package/src/self-improve/framework-absorber.ts +214 -0
  229. package/src/self-improve/index.ts +50 -0
  230. package/src/self-improve/prompt-optimizer.ts +212 -0
  231. package/src/self-improve/test-generator.ts +175 -0
  232. package/src/skill-router.ts +186 -0
  233. package/src/skills/index.ts +5 -0
  234. package/src/skills/skill-md-bridge.ts +1699 -0
  235. package/src/swarm/ACOEngine.ts +261 -0
  236. package/src/swarm/CollectiveIntelligence.ts +383 -0
  237. package/src/swarm/ContributionSynthesizer.ts +481 -0
  238. package/src/swarm/LeaderElection.ts +393 -0
  239. package/src/swarm/PSOEngine.ts +206 -0
  240. package/src/swarm/QuorumPolicy.ts +173 -0
  241. package/src/swarm/SwarmCoordinator.ts +335 -0
  242. package/src/swarm/SwarmManager.ts +442 -0
  243. package/src/swarm/SwarmMembership.ts +456 -0
  244. package/src/swarm/VotingRound.ts +255 -0
  245. package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
  246. package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
  247. package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
  248. package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
  249. package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
  250. package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
  251. package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
  252. package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
  253. package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
  254. package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
  255. package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
  256. package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
  257. package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
  258. package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
  259. package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
  260. package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
  261. package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
  262. package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
  263. package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
  264. package/src/swarm/__tests__/VotingRound.test.ts +174 -0
  265. package/src/swarm/analytics/SwarmInspector.ts +476 -0
  266. package/src/swarm/analytics/SwarmMetrics.ts +449 -0
  267. package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
  268. package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
  269. package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
  270. package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
  271. package/src/swarm/analytics/index.ts +7 -0
  272. package/src/swarm/index.ts +69 -0
  273. package/src/swarm/messaging/BroadcastChannel.ts +509 -0
  274. package/src/swarm/messaging/GossipProtocol.ts +565 -0
  275. package/src/swarm/messaging/SwarmEventBus.ts +443 -0
  276. package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
  277. package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
  278. package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
  279. package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
  280. package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
  281. package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
  282. package/src/swarm/messaging/index.ts +8 -0
  283. package/src/swarm/spatial/FlockingBehavior.ts +462 -0
  284. package/src/swarm/spatial/FormationController.ts +500 -0
  285. package/src/swarm/spatial/Vector3.ts +170 -0
  286. package/src/swarm/spatial/ZoneClaiming.ts +509 -0
  287. package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
  288. package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
  289. package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
  290. package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
  291. package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
  292. package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
  293. package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
  294. package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
  295. package/src/swarm/spatial/index.ts +28 -0
  296. package/src/team.ts +1245 -0
  297. package/src/training/LRScheduler.ts +377 -0
  298. package/src/training/QualityScoringPipeline.ts +139 -0
  299. package/src/training/SoftDedup.ts +461 -0
  300. package/src/training/SparsityMonitor.ts +685 -0
  301. package/src/training/SparsityMonitorTypes.ts +209 -0
  302. package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
  303. package/src/training/SpatialTrainingDataTypes.ts +216 -0
  304. package/src/training/TrainingPipelineConfig.ts +215 -0
  305. package/src/training/constants.ts +94 -0
  306. package/src/training/index.ts +138 -0
  307. package/src/training/schema.ts +147 -0
  308. package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
  309. package/src/training/scripts/generate-spatial-dataset.ts +521 -0
  310. package/src/training/training/data/novel-use-cases.jsonl +153 -0
  311. package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
  312. package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
  313. package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
  314. package/src/training/trainingmonkey/index.ts +26 -0
  315. package/src/training/trait-mappings.ts +157 -0
  316. package/src/types/core-stubs.d.ts +113 -0
  317. package/src/types.ts +304 -0
  318. package/test-output.txt +0 -0
  319. package/test-result.json +1 -0
  320. package/tsc-errors.txt +4 -0
  321. package/tsc_output.txt +0 -0
  322. package/tsconfig.json +14 -0
  323. package/tsup-learning-esm.config.ts +12 -0
  324. package/tsup.config.ts +21 -0
  325. package/typescript-errors-2.txt +0 -0
  326. package/typescript-errors.txt +22 -0
  327. package/vitest-log-utf8.txt +268 -0
  328. package/vitest-log.txt +0 -0
  329. package/vitest.config.ts +8 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * QuorumPolicy — Production Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { QuorumPolicy } from '../QuorumPolicy';
6
+
7
+ function make(cfg = {}) {
8
+ return new QuorumPolicy(cfg);
9
+ }
10
+
11
+ describe('QuorumPolicy — defaults', () => {
12
+ it('constructs with no args', () => expect(() => make()).not.toThrow());
13
+ it('default minimumSize=2', () => expect(make().getConfig().minimumSize).toBe(2));
14
+ it('default optimalSize=5', () => expect(make().getConfig().optimalSize).toBe(5));
15
+ it('default maximumSize=50', () => expect(make().getConfig().maximumSize).toBe(50));
16
+ it('default quorumPercentage=0.5', () => expect(make().getConfig().quorumPercentage).toBe(0.5));
17
+ it('default requireQuorumForOperations=true', () =>
18
+ expect(make().getConfig().requireQuorumForOperations).toBe(true));
19
+ });
20
+
21
+ describe('QuorumPolicy — config validation', () => {
22
+ it('throws if minimumSize > optimalSize', () =>
23
+ expect(() => make({ minimumSize: 10, optimalSize: 5 })).toThrow());
24
+ it('throws if optimalSize > maximumSize', () =>
25
+ expect(() => make({ optimalSize: 100, maximumSize: 50 })).toThrow());
26
+ it('throws if quorumPercentage < 0', () =>
27
+ expect(() => make({ quorumPercentage: -0.1 })).toThrow());
28
+ it('throws if quorumPercentage > 1', () =>
29
+ expect(() => make({ quorumPercentage: 1.1 })).toThrow());
30
+ it('quorumPercentage=0 is valid', () =>
31
+ expect(() => make({ quorumPercentage: 0 })).not.toThrow());
32
+ it('quorumPercentage=1 is valid', () =>
33
+ expect(() => make({ quorumPercentage: 1 })).not.toThrow());
34
+ });
35
+
36
+ describe('QuorumPolicy — setMemberCount / canJoin / canLeave', () => {
37
+ it('canJoin=true when below maximumSize', () => {
38
+ const p = make({ maximumSize: 5 });
39
+ p.setMemberCount(4);
40
+ expect(p.canJoin()).toBe(true);
41
+ });
42
+ it('canJoin=false when at maximumSize', () => {
43
+ const p = make({ maximumSize: 5 });
44
+ p.setMemberCount(5);
45
+ expect(p.canJoin()).toBe(false);
46
+ });
47
+ it('canLeave=true when above minimumSize', () => {
48
+ const p = make({ minimumSize: 2 });
49
+ p.setMemberCount(3);
50
+ expect(p.canLeave()).toBe(true);
51
+ });
52
+ it('canLeave=false when at minimumSize', () => {
53
+ const p = make({ minimumSize: 2 });
54
+ p.setMemberCount(2);
55
+ expect(p.canLeave()).toBe(false);
56
+ });
57
+ it('setMemberCount clamps negative to 0', () => {
58
+ const p = make();
59
+ p.setMemberCount(-5);
60
+ expect(p.getState().currentSize).toBe(0);
61
+ });
62
+ });
63
+
64
+ describe('QuorumPolicy — hasQuorum', () => {
65
+ // Default: optimal=5, quorumPct=0.5 → required = ceil(5*0.5)=3, effective=max(2,3)=3
66
+ it('false when below quorum threshold', () => {
67
+ const p = make();
68
+ p.setMemberCount(2);
69
+ expect(p.hasQuorum()).toBe(false);
70
+ });
71
+ it('true when at quorum threshold (3)', () => {
72
+ const p = make();
73
+ p.setMemberCount(3);
74
+ expect(p.hasQuorum()).toBe(true);
75
+ });
76
+ it('true at and above quorum threshold', () => {
77
+ const p = make();
78
+ p.setMemberCount(10);
79
+ expect(p.hasQuorum()).toBe(true);
80
+ });
81
+ it('quorumPct=0 → hasQuorum when at minimumSize', () => {
82
+ const p = make({ quorumPercentage: 0 });
83
+ p.setMemberCount(2);
84
+ expect(p.hasQuorum()).toBe(true);
85
+ });
86
+ });
87
+
88
+ describe('QuorumPolicy — canOperate', () => {
89
+ it('requires quorum when requireQuorumForOperations=true', () => {
90
+ const p = make({ requireQuorumForOperations: true });
91
+ p.setMemberCount(1);
92
+ expect(p.canOperate()).toBe(false);
93
+ });
94
+ it('only needs >0 when requireQuorumForOperations=false', () => {
95
+ const p = make({ requireQuorumForOperations: false });
96
+ p.setMemberCount(1);
97
+ expect(p.canOperate()).toBe(true);
98
+ });
99
+ it('0 members cannot operate regardless', () => {
100
+ const p = make({ requireQuorumForOperations: false });
101
+ p.setMemberCount(0);
102
+ expect(p.canOperate()).toBe(false);
103
+ });
104
+ });
105
+
106
+ describe('QuorumPolicy — getStatus', () => {
107
+ const cases: [number, string][] = [
108
+ [0, 'below-minimum'],
109
+ [1, 'below-minimum'],
110
+ [2, 'quorum'], // at minimumSize=2, below optimalSize=5
111
+ [4, 'quorum'],
112
+ [5, 'optimal'], // at optimalSize
113
+ [20, 'optimal'], // above but within maximumSize
114
+ [51, 'above-maximum'],
115
+ ];
116
+ for (const [count, status] of cases) {
117
+ it(`${count} members → ${status}`, () => {
118
+ const p = make();
119
+ p.setMemberCount(count);
120
+ expect(p.getStatus()).toBe(status);
121
+ });
122
+ }
123
+ });
124
+
125
+ describe('QuorumPolicy — getState', () => {
126
+ it('returns all required fields', () => {
127
+ const p = make();
128
+ p.setMemberCount(3);
129
+ const s = p.getState();
130
+ expect(s).toHaveProperty('currentSize', 3);
131
+ expect(s).toHaveProperty('status');
132
+ expect(s).toHaveProperty('hasQuorum');
133
+ expect(s).toHaveProperty('canOperate');
134
+ expect(s).toHaveProperty('requiredForQuorum');
135
+ expect(s).toHaveProperty('spotsAvailable');
136
+ });
137
+ it('spotsAvailable = maximumSize - currentSize', () => {
138
+ const p = make({ maximumSize: 50 });
139
+ p.setMemberCount(30);
140
+ expect(p.getState().spotsAvailable).toBe(20);
141
+ });
142
+ it('requiredForQuorum=0 when already has quorum', () => {
143
+ const p = make();
144
+ p.setMemberCount(10);
145
+ expect(p.getState().requiredForQuorum).toBe(0);
146
+ });
147
+ it('requiredForQuorum>0 when below quorum', () => {
148
+ const p = make();
149
+ p.setMemberCount(1);
150
+ expect(p.getState().requiredForQuorum).toBeGreaterThan(0);
151
+ });
152
+ });
153
+
154
+ describe('QuorumPolicy — shouldRecruit / shouldSplit', () => {
155
+ it('shouldRecruit=true below optimalSize', () => {
156
+ const p = make();
157
+ p.setMemberCount(3);
158
+ expect(p.shouldRecruit()).toBe(true);
159
+ });
160
+ it('shouldRecruit=false at optimalSize', () => {
161
+ const p = make();
162
+ p.setMemberCount(5);
163
+ expect(p.shouldRecruit()).toBe(false);
164
+ });
165
+ it('shouldSplit=false below maximumSize', () => {
166
+ const p = make({ maximumSize: 50 });
167
+ p.setMemberCount(49);
168
+ expect(p.shouldSplit()).toBe(false);
169
+ });
170
+ it('shouldSplit=true above maximumSize', () => {
171
+ const p = make({ maximumSize: 50 });
172
+ p.setMemberCount(51);
173
+ expect(p.shouldSplit()).toBe(true);
174
+ });
175
+ });
176
+
177
+ describe('QuorumPolicy — getHealthScore', () => {
178
+ it('0 members → health=0', () => {
179
+ const p = make();
180
+ p.setMemberCount(0);
181
+ expect(p.getHealthScore()).toBe(0);
182
+ });
183
+ it('at optimal → health=1', () => {
184
+ const p = make();
185
+ p.setMemberCount(5);
186
+ expect(p.getHealthScore()).toBe(1);
187
+ });
188
+ it('above optimal (within max) → health=1', () => {
189
+ const p = make();
190
+ p.setMemberCount(20);
191
+ expect(p.getHealthScore()).toBe(1);
192
+ });
193
+ it('between min and optimal → 0.5 < health < 1', () => {
194
+ const p = make();
195
+ p.setMemberCount(3);
196
+ expect(p.getHealthScore()).toBeGreaterThan(0.5);
197
+ expect(p.getHealthScore()).toBeLessThan(1);
198
+ });
199
+ it('below minimum → health < 0.5', () => {
200
+ const p = make({ minimumSize: 5 });
201
+ p.setMemberCount(2);
202
+ expect(p.getHealthScore()).toBeLessThan(0.5);
203
+ expect(p.getHealthScore()).toBeGreaterThan(0);
204
+ });
205
+ it('above maximum → health still >= 0.5 (degraded, not critical)', () => {
206
+ const p = make({ maximumSize: 10 });
207
+ p.setMemberCount(15);
208
+ expect(p.getHealthScore()).toBeGreaterThanOrEqual(0.5);
209
+ });
210
+ it('getConfig returns immutable copy', () => {
211
+ const p = make();
212
+ const c = p.getConfig();
213
+ c.minimumSize = 99;
214
+ expect(p.getConfig().minimumSize).toBe(2);
215
+ });
216
+ });
@@ -0,0 +1,177 @@
1
+ /**
2
+ * QuorumPolicy Tests
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach } from 'vitest';
6
+ import { QuorumPolicy } from '../QuorumPolicy';
7
+
8
+ describe('QuorumPolicy', () => {
9
+ let policy: QuorumPolicy;
10
+
11
+ beforeEach(() => {
12
+ policy = new QuorumPolicy({
13
+ minimumSize: 2,
14
+ optimalSize: 5,
15
+ maximumSize: 10,
16
+ quorumPercentage: 0.5,
17
+ });
18
+ });
19
+
20
+ describe('constructor', () => {
21
+ it('should create with default config', () => {
22
+ const p = new QuorumPolicy();
23
+ expect(p.getConfig().minimumSize).toBe(2);
24
+ });
25
+
26
+ it('should throw for invalid config', () => {
27
+ expect(() => new QuorumPolicy({ minimumSize: 10, optimalSize: 5 })).toThrow();
28
+ expect(() => new QuorumPolicy({ optimalSize: 20, maximumSize: 10 })).toThrow();
29
+ expect(() => new QuorumPolicy({ quorumPercentage: 1.5 })).toThrow();
30
+ });
31
+ });
32
+
33
+ describe('canJoin', () => {
34
+ it('should allow joining below max', () => {
35
+ policy.setMemberCount(5);
36
+ expect(policy.canJoin()).toBe(true);
37
+ });
38
+
39
+ it('should disallow joining at max', () => {
40
+ policy.setMemberCount(10);
41
+ expect(policy.canJoin()).toBe(false);
42
+ });
43
+ });
44
+
45
+ describe('canLeave', () => {
46
+ it('should allow leaving above minimum', () => {
47
+ policy.setMemberCount(5);
48
+ expect(policy.canLeave()).toBe(true);
49
+ });
50
+
51
+ it('should disallow leaving at minimum', () => {
52
+ policy.setMemberCount(2);
53
+ expect(policy.canLeave()).toBe(false);
54
+ });
55
+ });
56
+
57
+ describe('hasQuorum', () => {
58
+ it('should not have quorum below minimum', () => {
59
+ policy.setMemberCount(1);
60
+ expect(policy.hasQuorum()).toBe(false);
61
+ });
62
+
63
+ it('should have quorum at minimum if meets percentage', () => {
64
+ // quorumPercentage 0.5 of 5 = 2.5 -> 3, but min is 2
65
+ // So need max(2, 3) = 3
66
+ policy.setMemberCount(3);
67
+ expect(policy.hasQuorum()).toBe(true);
68
+ });
69
+
70
+ it('should have quorum at optimal', () => {
71
+ policy.setMemberCount(5);
72
+ expect(policy.hasQuorum()).toBe(true);
73
+ });
74
+ });
75
+
76
+ describe('canOperate', () => {
77
+ it('should not operate without quorum when required', () => {
78
+ policy.setMemberCount(1);
79
+ expect(policy.canOperate()).toBe(false);
80
+ });
81
+
82
+ it('should operate with quorum', () => {
83
+ policy.setMemberCount(3);
84
+ expect(policy.canOperate()).toBe(true);
85
+ });
86
+
87
+ it('should operate without quorum when not required', () => {
88
+ const p = new QuorumPolicy({ requireQuorumForOperations: false });
89
+ p.setMemberCount(1);
90
+ expect(p.canOperate()).toBe(true);
91
+ });
92
+ });
93
+
94
+ describe('getStatus', () => {
95
+ it('should return below-minimum for too few', () => {
96
+ policy.setMemberCount(1);
97
+ expect(policy.getStatus()).toBe('below-minimum');
98
+ });
99
+
100
+ it('should return quorum for sufficient members', () => {
101
+ policy.setMemberCount(3);
102
+ expect(policy.getStatus()).toBe('quorum');
103
+ });
104
+
105
+ it('should return optimal at optimal size', () => {
106
+ policy.setMemberCount(5);
107
+ expect(policy.getStatus()).toBe('optimal');
108
+ });
109
+
110
+ it('should return above-maximum when exceeded', () => {
111
+ policy.setMemberCount(15);
112
+ expect(policy.getStatus()).toBe('above-maximum');
113
+ });
114
+ });
115
+
116
+ describe('getState', () => {
117
+ it('should return full state object', () => {
118
+ policy.setMemberCount(3);
119
+ const state = policy.getState();
120
+
121
+ expect(state.currentSize).toBe(3);
122
+ expect(state.status).toBe('quorum');
123
+ expect(state.hasQuorum).toBe(true);
124
+ expect(state.canOperate).toBe(true);
125
+ expect(state.requiredForQuorum).toBe(0);
126
+ expect(state.spotsAvailable).toBe(7);
127
+ });
128
+ });
129
+
130
+ describe('shouldRecruit', () => {
131
+ it('should recruit below optimal', () => {
132
+ policy.setMemberCount(3);
133
+ expect(policy.shouldRecruit()).toBe(true);
134
+ });
135
+
136
+ it('should not recruit at optimal', () => {
137
+ policy.setMemberCount(5);
138
+ expect(policy.shouldRecruit()).toBe(false);
139
+ });
140
+ });
141
+
142
+ describe('shouldSplit', () => {
143
+ it('should not split below maximum', () => {
144
+ policy.setMemberCount(8);
145
+ expect(policy.shouldSplit()).toBe(false);
146
+ });
147
+
148
+ it('should split above maximum', () => {
149
+ policy.setMemberCount(12);
150
+ expect(policy.shouldSplit()).toBe(true);
151
+ });
152
+ });
153
+
154
+ describe('getHealthScore', () => {
155
+ it('should return 0 for empty', () => {
156
+ policy.setMemberCount(0);
157
+ expect(policy.getHealthScore()).toBe(0);
158
+ });
159
+
160
+ it('should return low score below minimum', () => {
161
+ policy.setMemberCount(1);
162
+ expect(policy.getHealthScore()).toBeLessThan(0.5);
163
+ });
164
+
165
+ it('should return 1 at optimal', () => {
166
+ policy.setMemberCount(5);
167
+ expect(policy.getHealthScore()).toBe(1);
168
+ });
169
+
170
+ it('should return partial score between min and optimal', () => {
171
+ policy.setMemberCount(3);
172
+ const score = policy.getHealthScore();
173
+ expect(score).toBeGreaterThan(0.5);
174
+ expect(score).toBeLessThan(1);
175
+ });
176
+ });
177
+ });
@@ -0,0 +1,186 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { SwarmCoordinator, type AgentInfo, type TaskInfo } from '../SwarmCoordinator';
3
+
4
+ // ─── helpers ────────────────────────────────────────────────────────────────
5
+
6
+ function mkCoord(cfg?: ConstructorParameters<typeof SwarmCoordinator>[0]) {
7
+ return new SwarmCoordinator(cfg);
8
+ }
9
+
10
+ function mkAgents(n: number): AgentInfo[] {
11
+ return Array.from({ length: n }, (_, i) => ({
12
+ id: `agent-${i}`,
13
+ capacity: 100,
14
+ load: 0,
15
+ }));
16
+ }
17
+
18
+ function mkTasks(n: number): TaskInfo[] {
19
+ return Array.from({ length: n }, (_, i) => ({
20
+ id: `task-${i}`,
21
+ complexity: 10,
22
+ priority: i + 1,
23
+ }));
24
+ }
25
+
26
+ // ─── tests ───────────────────────────────────────────────────────────────────
27
+
28
+ describe('SwarmCoordinator — construction', () => {
29
+ it('creates without config', () => {
30
+ expect(() => mkCoord()).not.toThrow();
31
+ });
32
+ it('creates with partial config', () => {
33
+ expect(() => mkCoord({ algorithm: 'pso', populationSize: 10 })).not.toThrow();
34
+ });
35
+ });
36
+
37
+ describe('SwarmCoordinator — getRecommendedPopulation', () => {
38
+ const coord = mkCoord();
39
+
40
+ it('returns at least 15 for tiny problems', () => {
41
+ expect(coord.getRecommendedPopulation(1)).toBeGreaterThanOrEqual(15);
42
+ });
43
+ it('returns at most 100 for huge problems', () => {
44
+ expect(coord.getRecommendedPopulation(1_000_000)).toBeLessThanOrEqual(100);
45
+ });
46
+ it('scales logarithmically (10 > 1)', () => {
47
+ expect(coord.getRecommendedPopulation(100)).toBeGreaterThanOrEqual(
48
+ coord.getRecommendedPopulation(10)
49
+ );
50
+ });
51
+ it('returns number', () => {
52
+ expect(typeof coord.getRecommendedPopulation(4)).toBe('number');
53
+ });
54
+ it('result is integer-like (ceil)', () => {
55
+ const r = coord.getRecommendedPopulation(8);
56
+ expect(r).toBe(Math.round(r));
57
+ });
58
+ });
59
+
60
+ describe('SwarmCoordinator — optimize (pso)', () => {
61
+ it('returns a valid result object', async () => {
62
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
63
+ const result = await coord.optimize(mkAgents(2), mkTasks(3));
64
+ expect(result).toHaveProperty('bestSolution');
65
+ expect(result).toHaveProperty('bestFitness');
66
+ expect(result).toHaveProperty('converged');
67
+ expect(result).toHaveProperty('iterations');
68
+ });
69
+ it('bestSolution has length = number of tasks', async () => {
70
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
71
+ const result = await coord.optimize(mkAgents(3), mkTasks(4));
72
+ expect(result.bestSolution).toHaveLength(4);
73
+ });
74
+ it('each assignment index is within agent count', async () => {
75
+ const agents = mkAgents(3);
76
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
77
+ const result = await coord.optimize(agents, mkTasks(5));
78
+ result.bestSolution.forEach((agentIdx: any) => {
79
+ expect(agentIdx).toBeGreaterThanOrEqual(0);
80
+ expect(agentIdx).toBeLessThan(agents.length);
81
+ });
82
+ });
83
+ it('iterations > 0', async () => {
84
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
85
+ const result = await coord.optimize(mkAgents(2), mkTasks(2));
86
+ expect(result.iterations).toBeGreaterThan(0);
87
+ });
88
+ it('improvementPercent >= 0', async () => {
89
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
90
+ const result = await coord.optimize(mkAgents(2), mkTasks(2));
91
+ expect(result.improvementPercent).toBeGreaterThanOrEqual(0);
92
+ });
93
+ });
94
+
95
+ describe('SwarmCoordinator — optimize (aco)', () => {
96
+ it('returns valid result with aco algorithm', async () => {
97
+ const coord = mkCoord({ algorithm: 'aco', populationSize: 5, maxIterations: 5 });
98
+ const result = await coord.optimize(mkAgents(2), mkTasks(3));
99
+ expect(result).toHaveProperty('bestSolution');
100
+ });
101
+ it('aco solution length = task count', async () => {
102
+ const coord = mkCoord({ algorithm: 'aco', populationSize: 5, maxIterations: 5 });
103
+ const result = await coord.optimize(mkAgents(2), mkTasks(4));
104
+ expect(result.bestSolution).toHaveLength(4);
105
+ });
106
+ it('aco bestFitness is a number', async () => {
107
+ const coord = mkCoord({ algorithm: 'aco', populationSize: 5, maxIterations: 5 });
108
+ const result = await coord.optimize(mkAgents(2), mkTasks(2));
109
+ expect(typeof result.bestFitness).toBe('number');
110
+ });
111
+ });
112
+
113
+ describe('SwarmCoordinator — optimize (hybrid)', () => {
114
+ it('returns valid result for hybrid algorithm', async () => {
115
+ const coord = mkCoord({ algorithm: 'hybrid', populationSize: 5, maxIterations: 5 });
116
+ const result = await coord.optimize(mkAgents(2), mkTasks(3));
117
+ expect(result).toHaveProperty('converged');
118
+ });
119
+ it('hybrid solution length = tasks', async () => {
120
+ const coord = mkCoord({ algorithm: 'hybrid', populationSize: 5, maxIterations: 5 });
121
+ const result = await coord.optimize(mkAgents(2), mkTasks(3));
122
+ expect(result.bestSolution).toHaveLength(3);
123
+ });
124
+ });
125
+
126
+ describe('SwarmCoordinator — optimize (bees)', () => {
127
+ it('returns valid result for bees algorithm', async () => {
128
+ const coord = mkCoord({ algorithm: 'bees', populationSize: 10, maxIterations: 5 });
129
+ const result = await coord.optimize(mkAgents(2), mkTasks(3));
130
+ expect(result).toHaveProperty('bestSolution');
131
+ });
132
+ });
133
+
134
+ describe('SwarmCoordinator — adaptiveSizing', () => {
135
+ it('adaptiveSizing=true respects bounds', async () => {
136
+ const coord = mkCoord({ adaptiveSizing: true, algorithm: 'pso', maxIterations: 5 });
137
+ // Should not throw regardless of problem size
138
+ await expect(coord.optimize(mkAgents(5), mkTasks(5))).resolves.toBeDefined();
139
+ });
140
+ it('adaptiveSizing=false uses configured populationSize', async () => {
141
+ const coord = mkCoord({
142
+ adaptiveSizing: false,
143
+ populationSize: 5,
144
+ maxIterations: 5,
145
+ algorithm: 'pso',
146
+ });
147
+ await expect(coord.optimize(mkAgents(2), mkTasks(2))).resolves.toBeDefined();
148
+ });
149
+ });
150
+
151
+ describe('SwarmCoordinator — per-call config override', () => {
152
+ it('optimize accepts per-call config', async () => {
153
+ const coord = mkCoord({ algorithm: 'pso', maxIterations: 100 });
154
+ // Override maxIterations to be very small — allow +1 buffer for initial eval
155
+ const maxIter = 2;
156
+ const result = await coord.optimize(mkAgents(2), mkTasks(2), { maxIterations: maxIter });
157
+ expect(result.iterations).toBeLessThanOrEqual(maxIter + 1);
158
+ });
159
+ it('per-call algorithm override is respected', async () => {
160
+ const coord = mkCoord({ algorithm: 'hybrid', maxIterations: 5 });
161
+ // Override to pso
162
+ const result = await coord.optimize(mkAgents(2), mkTasks(2), { algorithm: 'pso' });
163
+ expect(result).toHaveProperty('bestSolution');
164
+ });
165
+ });
166
+
167
+ describe('SwarmCoordinator — edge cases', () => {
168
+ it('single agent, single task', async () => {
169
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
170
+ const result = await coord.optimize(mkAgents(1), mkTasks(1));
171
+ expect(result.bestSolution).toHaveLength(1);
172
+ expect(result.bestSolution[0]).toBe(0); // Only one agent
173
+ });
174
+ it('many tasks, few agents', async () => {
175
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
176
+ const result = await coord.optimize(mkAgents(2), mkTasks(10));
177
+ expect(result.bestSolution).toHaveLength(10);
178
+ });
179
+ it('high-capacity agents accept all tasks', async () => {
180
+ const agents: AgentInfo[] = [{ id: 'big', capacity: 9999, load: 0 }];
181
+ const tasks = mkTasks(5);
182
+ const coord = mkCoord({ algorithm: 'pso', populationSize: 5, maxIterations: 5 });
183
+ const result = await coord.optimize(agents, tasks);
184
+ expect(result).toBeDefined();
185
+ });
186
+ });