@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,147 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { DistributedClaimer } from '../distributed-claimer';
3
+ import { MeshDiscovery, GossipProtocol } from '../mesh';
4
+ import type { GossipPacket } from '../mesh';
5
+
6
+ describe('DistributedClaimer', () => {
7
+ let mesh: MeshDiscovery;
8
+ let gossip: GossipProtocol;
9
+ let claimer: DistributedClaimer;
10
+
11
+ beforeEach(() => {
12
+ mesh = new MeshDiscovery('node-1');
13
+ gossip = new GossipProtocol();
14
+ claimer = new DistributedClaimer(mesh, gossip, { claimTtlMs: 5000 });
15
+ });
16
+
17
+ it('claims an unclaimed task', () => {
18
+ const result = claimer.claim('task-1', 'agent-a');
19
+ expect(result.success).toBe(true);
20
+ expect(result.claimedBy).toBe('agent-a');
21
+ expect(result.taskId).toBe('task-1');
22
+ });
23
+
24
+ it('allows the same agent to re-claim (refresh)', () => {
25
+ claimer.claim('task-1', 'agent-a');
26
+ const result = claimer.claim('task-1', 'agent-a');
27
+ expect(result.success).toBe(true);
28
+ expect(result.claimedBy).toBe('agent-a');
29
+ });
30
+
31
+ it('rejects lower-priority agent on conflict', () => {
32
+ claimer.claim('task-1', 'agent-a', 3);
33
+ const result = claimer.claim('task-1', 'agent-b', 5); // higher number = lower priority
34
+ expect(result.success).toBe(false);
35
+ expect(result.claimedBy).toBe('agent-a');
36
+ });
37
+
38
+ it('higher-priority agent wins conflict', () => {
39
+ claimer.claim('task-1', 'agent-a', 5);
40
+ const result = claimer.claim('task-1', 'agent-b', 2); // lower number = higher priority
41
+ expect(result.success).toBe(true);
42
+ expect(result.claimedBy).toBe('agent-b');
43
+ expect(result.contested).toEqual(['agent-a']);
44
+ });
45
+
46
+ it('releases a claim', () => {
47
+ claimer.claim('task-1', 'agent-a');
48
+ const released = claimer.release('task-1', 'agent-a');
49
+ expect(released).toBe(true);
50
+ expect(claimer.getClaimHolder('task-1')).toBeUndefined();
51
+ });
52
+
53
+ it('cannot release another agent claim', () => {
54
+ claimer.claim('task-1', 'agent-a');
55
+ const released = claimer.release('task-1', 'agent-b');
56
+ expect(released).toBe(false);
57
+ expect(claimer.getClaimHolder('task-1')?.agentId).toBe('agent-a');
58
+ });
59
+
60
+ it('confirms a claim (extends TTL)', () => {
61
+ claimer.claim('task-1', 'agent-a');
62
+ const confirmed = claimer.confirm('task-1', 'agent-a');
63
+ expect(confirmed).toBe(true);
64
+ const record = claimer.getClaimHolder('task-1');
65
+ expect(record).toBeDefined();
66
+ // Confirmed claims have extended TTL (10x)
67
+ expect(record!.expiresAt).toBeGreaterThan(Date.now() + 40_000);
68
+ });
69
+
70
+ it('tracks multiple active claims', () => {
71
+ claimer.claim('task-1', 'agent-a');
72
+ claimer.claim('task-2', 'agent-b');
73
+ claimer.claim('task-3', 'agent-a');
74
+ const active = claimer.getActiveClaims();
75
+ expect(active).toHaveLength(3);
76
+ });
77
+
78
+ it('broadcasts claims via gossip', () => {
79
+ claimer.claim('task-1', 'agent-a');
80
+ expect(gossip.getPoolSize()).toBeGreaterThan(0);
81
+ });
82
+
83
+ it('ingests gossip claim packets', () => {
84
+ // Simulate a remote claim arriving via gossip
85
+ const packet: GossipPacket = {
86
+ id: 'pkt-remote-1',
87
+ source: 'claimer:node-2',
88
+ version: 1,
89
+ payload: {
90
+ type: 'claim',
91
+ record: {
92
+ taskId: 'task-remote',
93
+ agentId: 'remote-agent',
94
+ timestamp: Date.now() * 1000,
95
+ priority: 3,
96
+ expiresAt: Date.now() + 30_000,
97
+ },
98
+ },
99
+ timestamp: Date.now(),
100
+ };
101
+
102
+ claimer.ingestGossip(packet);
103
+ const holder = claimer.getClaimHolder('task-remote');
104
+ expect(holder).toBeDefined();
105
+ expect(holder!.agentId).toBe('remote-agent');
106
+ });
107
+
108
+ it('ingests gossip release packets', () => {
109
+ claimer.claim('task-1', 'agent-a');
110
+
111
+ const record = claimer.getClaimHolder('task-1')!;
112
+ const packet: GossipPacket = {
113
+ id: 'pkt-release',
114
+ source: 'claimer:node-2',
115
+ version: 1,
116
+ payload: { type: 'release', record },
117
+ timestamp: Date.now(),
118
+ };
119
+
120
+ claimer.ingestGossip(packet);
121
+ expect(claimer.getClaimHolder('task-1')).toBeUndefined();
122
+ });
123
+
124
+ it('resolves gossip conflicts by priority', () => {
125
+ claimer.claim('task-1', 'agent-a', 5);
126
+
127
+ const packet: GossipPacket = {
128
+ id: 'pkt-conflict',
129
+ source: 'claimer:node-2',
130
+ version: 1,
131
+ payload: {
132
+ type: 'claim',
133
+ record: {
134
+ taskId: 'task-1',
135
+ agentId: 'agent-remote',
136
+ timestamp: Date.now() * 1000,
137
+ priority: 2, // Higher priority (lower number)
138
+ expiresAt: Date.now() + 30_000,
139
+ },
140
+ },
141
+ timestamp: Date.now(),
142
+ };
143
+
144
+ claimer.ingestGossip(packet);
145
+ expect(claimer.getClaimHolder('task-1')?.agentId).toBe('agent-remote');
146
+ });
147
+ });
@@ -0,0 +1,342 @@
1
+ /**
2
+ * DoneLogAuditor tests (FW-0.3)
3
+ *
4
+ * Tests the done-log audit logic: violations, stats, and Team.audit() integration.
5
+ */
6
+ import { describe, it, expect, vi } from 'vitest';
7
+ import {
8
+ DoneLogAuditor,
9
+ auditDoneLog,
10
+ isLikelyReportEntry,
11
+ isCommitProof,
12
+ } from '../board/audit';
13
+ import type { DoneLogEntry } from '../board/board-types';
14
+ import { Team } from '../team';
15
+
16
+ // ── Helpers ──
17
+
18
+ function makeEntry(overrides: Partial<DoneLogEntry> = {}): DoneLogEntry {
19
+ return {
20
+ taskId: `task_${Math.random().toString(36).slice(2, 6)}`,
21
+ title: 'Fix the widget',
22
+ completedBy: 'agent-a',
23
+ commitHash: 'abc1234',
24
+ timestamp: '2026-04-05T10:00:00Z',
25
+ summary: 'Fixed the widget by refactoring X',
26
+ ...overrides,
27
+ };
28
+ }
29
+
30
+ // ── isLikelyReportEntry ──
31
+
32
+ describe('isLikelyReportEntry', () => {
33
+ it('detects [report] prefix in title', () => {
34
+ expect(isLikelyReportEntry({ title: '[report] Session summary' })).toBe(true);
35
+ });
36
+
37
+ it('detects "session end" prefix in summary', () => {
38
+ expect(isLikelyReportEntry({ summary: 'session end — 5 tasks done' })).toBe(true);
39
+ });
40
+
41
+ it('returns false for normal entries', () => {
42
+ expect(isLikelyReportEntry({ title: 'Fix bug', summary: 'Refactored code' })).toBe(false);
43
+ });
44
+ });
45
+
46
+ // ── isCommitProof ──
47
+
48
+ describe('isCommitProof', () => {
49
+ it('accepts valid short hash', () => {
50
+ expect(isCommitProof('abc1234')).toBe(true);
51
+ });
52
+
53
+ it('accepts valid full hash', () => {
54
+ expect(isCommitProof('abc1234567890abc1234567890abc1234567890a')).toBe(true);
55
+ });
56
+
57
+ it('rejects undefined', () => {
58
+ expect(isCommitProof(undefined)).toBe(false);
59
+ });
60
+
61
+ it('rejects empty string', () => {
62
+ expect(isCommitProof('')).toBe(false);
63
+ });
64
+
65
+ it('rejects "none"', () => {
66
+ expect(isCommitProof('none')).toBe(false);
67
+ });
68
+
69
+ it('rejects "local-uncommitted"', () => {
70
+ expect(isCommitProof('local-uncommitted')).toBe(false);
71
+ });
72
+
73
+ it('rejects non-hex strings', () => {
74
+ expect(isCommitProof('not-a-hash!')).toBe(false);
75
+ });
76
+ });
77
+
78
+ // ── auditDoneLog (backward compat) ──
79
+
80
+ describe('auditDoneLog', () => {
81
+ it('returns 100% verification for empty log', () => {
82
+ const result = auditDoneLog([]);
83
+ expect(result.total).toBe(0);
84
+ expect(result.health.verificationRate).toBe(100);
85
+ });
86
+
87
+ it('counts verified and unverified', () => {
88
+ const entries = [
89
+ makeEntry({ commitHash: 'abc1234' }),
90
+ makeEntry({ commitHash: undefined }),
91
+ ];
92
+ const result = auditDoneLog(entries);
93
+ expect(result.verified).toBe(1);
94
+ expect(result.unverified).toBe(1);
95
+ expect(result.health.verificationRate).toBe(50);
96
+ });
97
+
98
+ it('detects duplicate titles', () => {
99
+ const entries = [
100
+ makeEntry({ taskId: 't1', title: 'Same title' }),
101
+ makeEntry({ taskId: 't2', title: 'Same title' }),
102
+ ];
103
+ const result = auditDoneLog(entries);
104
+ expect(result.duplicates).toBe(1);
105
+ expect(result.duplicateTasks[0].title).toBe('Same title');
106
+ expect(result.duplicateTasks[0].count).toBe(2);
107
+ });
108
+
109
+ it('excludes report entries from proof requirement', () => {
110
+ const entries = [
111
+ makeEntry({ title: '[report] Session end', commitHash: undefined }),
112
+ makeEntry({ commitHash: 'abc1234' }),
113
+ ];
114
+ const result = auditDoneLog(entries);
115
+ expect(result.nonProofEntries).toBe(1);
116
+ expect(result.proofRequiredTotal).toBe(1);
117
+ expect(result.health.verificationRate).toBe(100);
118
+ });
119
+ });
120
+
121
+ // ── DoneLogAuditor.audit() ──
122
+
123
+ describe('DoneLogAuditor.audit()', () => {
124
+ it('returns no violations for well-formed entries', () => {
125
+ const entries = [
126
+ makeEntry({ timestamp: '2026-04-05T10:00:00Z' }),
127
+ makeEntry({ timestamp: '2026-04-05T11:00:00Z' }),
128
+ ];
129
+ const auditor = new DoneLogAuditor(entries);
130
+ const violations = auditor.audit();
131
+ expect(violations).toHaveLength(0);
132
+ });
133
+
134
+ it('detects missing completedBy', () => {
135
+ const entries = [makeEntry({ completedBy: '' })];
136
+ const auditor = new DoneLogAuditor(entries);
137
+ const violations = auditor.audit();
138
+ expect(violations.some(v => v.rule === 'missing-completedBy')).toBe(true);
139
+ });
140
+
141
+ it('detects missing summary', () => {
142
+ const entries = [makeEntry({ summary: '' })];
143
+ const auditor = new DoneLogAuditor(entries);
144
+ const violations = auditor.audit();
145
+ expect(violations.some(v => v.rule === 'missing-summary')).toBe(true);
146
+ });
147
+
148
+ it('detects missing commit proof', () => {
149
+ const entries = [makeEntry({ commitHash: undefined })];
150
+ const auditor = new DoneLogAuditor(entries);
151
+ const violations = auditor.audit();
152
+ expect(violations.some(v => v.rule === 'missing-commit')).toBe(true);
153
+ });
154
+
155
+ it('detects duplicate taskId entries', () => {
156
+ const entries = [
157
+ makeEntry({ taskId: 'dup-1', timestamp: '2026-04-05T10:00:00Z' }),
158
+ makeEntry({ taskId: 'dup-1', timestamp: '2026-04-05T11:00:00Z' }),
159
+ ];
160
+ const auditor = new DoneLogAuditor(entries);
161
+ const violations = auditor.audit();
162
+ expect(violations.some(v => v.rule === 'duplicate-entry')).toBe(true);
163
+ });
164
+
165
+ it('detects non-monotonic timestamps', () => {
166
+ const entries = [
167
+ makeEntry({ taskId: 't1', timestamp: '2026-04-05T12:00:00Z' }),
168
+ makeEntry({ taskId: 't2', timestamp: '2026-04-05T10:00:00Z' }),
169
+ ];
170
+ const auditor = new DoneLogAuditor(entries);
171
+ const violations = auditor.audit();
172
+ expect(violations.some(v => v.rule === 'non-monotonic-timestamp')).toBe(true);
173
+ });
174
+
175
+ it('skips report entries from field checks', () => {
176
+ const entries = [
177
+ makeEntry({ title: '[report] Session summary', commitHash: undefined, summary: '' }),
178
+ ];
179
+ const auditor = new DoneLogAuditor(entries);
180
+ const violations = auditor.audit();
181
+ // Report entries should not trigger missing-commit or missing-summary
182
+ expect(violations).toHaveLength(0);
183
+ });
184
+ });
185
+
186
+ // ── DoneLogAuditor.stats() ──
187
+
188
+ describe('DoneLogAuditor.stats()', () => {
189
+ it('returns zero stats for empty log', () => {
190
+ const auditor = new DoneLogAuditor([]);
191
+ const stats = auditor.stats();
192
+ expect(stats.total).toBe(0);
193
+ expect(stats.byAgent).toHaveLength(0);
194
+ expect(stats.bySource).toHaveLength(0);
195
+ expect(stats.completionOverTime).toHaveLength(0);
196
+ });
197
+
198
+ it('groups by agent', () => {
199
+ const entries = [
200
+ makeEntry({ taskId: 't1', completedBy: 'alice' }),
201
+ makeEntry({ taskId: 't2', completedBy: 'alice' }),
202
+ makeEntry({ taskId: 't3', completedBy: 'bob' }),
203
+ ];
204
+ const auditor = new DoneLogAuditor(entries);
205
+ const stats = auditor.stats();
206
+ expect(stats.byAgent).toHaveLength(2);
207
+ const alice = stats.byAgent.find(a => a.agent === 'alice');
208
+ expect(alice?.completed).toBe(2);
209
+ const bob = stats.byAgent.find(a => a.agent === 'bob');
210
+ expect(bob?.completed).toBe(1);
211
+ });
212
+
213
+ it('tracks verified vs unverified per agent', () => {
214
+ const entries = [
215
+ makeEntry({ taskId: 't1', completedBy: 'alice', commitHash: 'abc1234' }),
216
+ makeEntry({ taskId: 't2', completedBy: 'alice', commitHash: undefined }),
217
+ ];
218
+ const auditor = new DoneLogAuditor(entries);
219
+ const stats = auditor.stats();
220
+ const alice = stats.byAgent.find(a => a.agent === 'alice');
221
+ expect(alice?.verified).toBe(1);
222
+ expect(alice?.unverified).toBe(1);
223
+ });
224
+
225
+ it('detects synthesizer source from taskId', () => {
226
+ const entries = [
227
+ makeEntry({ taskId: 'task_synth_001' }),
228
+ ];
229
+ const auditor = new DoneLogAuditor(entries);
230
+ const stats = auditor.stats();
231
+ expect(stats.bySource.some(s => s.source === 'synthesizer')).toBe(true);
232
+ });
233
+
234
+ it('groups completion over time by date', () => {
235
+ const entries = [
236
+ makeEntry({ taskId: 't1', timestamp: '2026-04-05T10:00:00Z' }),
237
+ makeEntry({ taskId: 't2', timestamp: '2026-04-05T14:00:00Z' }),
238
+ makeEntry({ taskId: 't3', timestamp: '2026-04-06T10:00:00Z' }),
239
+ ];
240
+ const auditor = new DoneLogAuditor(entries);
241
+ const stats = auditor.stats();
242
+ expect(stats.completionOverTime).toHaveLength(2);
243
+ expect(stats.completionOverTime[0]).toEqual({ date: '2026-04-05', completed: 2 });
244
+ expect(stats.completionOverTime[1]).toEqual({ date: '2026-04-06', completed: 1 });
245
+ });
246
+
247
+ it('sorts agents by completed count descending', () => {
248
+ const entries = [
249
+ makeEntry({ taskId: 't1', completedBy: 'low' }),
250
+ makeEntry({ taskId: 't2', completedBy: 'high' }),
251
+ makeEntry({ taskId: 't3', completedBy: 'high' }),
252
+ makeEntry({ taskId: 't4', completedBy: 'high' }),
253
+ ];
254
+ const auditor = new DoneLogAuditor(entries);
255
+ const stats = auditor.stats();
256
+ expect(stats.byAgent[0].agent).toBe('high');
257
+ expect(stats.byAgent[1].agent).toBe('low');
258
+ });
259
+ });
260
+
261
+ // ── DoneLogAuditor.fullAudit() ──
262
+
263
+ describe('DoneLogAuditor.fullAudit()', () => {
264
+ it('returns combined audit, violations, and stats', () => {
265
+ const entries = [
266
+ makeEntry({ taskId: 't1', timestamp: '2026-04-05T10:00:00Z' }),
267
+ makeEntry({ taskId: 't2', timestamp: '2026-04-05T11:00:00Z', commitHash: undefined }),
268
+ ];
269
+ const auditor = new DoneLogAuditor(entries);
270
+ const result = auditor.fullAudit();
271
+
272
+ // audit (backward compat)
273
+ expect(result.audit.total).toBe(2);
274
+ expect(result.audit.verified).toBe(1);
275
+ expect(result.audit.unverified).toBe(1);
276
+
277
+ // violations
278
+ expect(result.violations.some(v => v.rule === 'missing-commit')).toBe(true);
279
+
280
+ // stats
281
+ expect(result.stats.total).toBe(2);
282
+ });
283
+ });
284
+
285
+ // ── Team.audit() integration ──
286
+
287
+ describe('Team.audit()', () => {
288
+ it('audits local done log (empty)', async () => {
289
+ const team = new Team({
290
+ name: 'test-team',
291
+ agents: [],
292
+ });
293
+ const result = await team.audit();
294
+ expect(result.audit.total).toBe(0);
295
+ expect(result.violations).toHaveLength(0);
296
+ expect(result.stats.total).toBe(0);
297
+ });
298
+
299
+ it('audits remote done log via listBoard', async () => {
300
+ const team = new Team({
301
+ name: 'remote-team',
302
+ agents: [],
303
+ boardUrl: 'https://example.com',
304
+ boardApiKey: 'test-key',
305
+ });
306
+
307
+ // Mock fetch for the remote board call
308
+ const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(
309
+ new Response(JSON.stringify({
310
+ board: {
311
+ open: [],
312
+ claimed: [],
313
+ done_log: [
314
+ {
315
+ taskId: 't1',
316
+ title: 'Remote task',
317
+ completedBy: 'remote-agent',
318
+ commitHash: 'abcdef1',
319
+ timestamp: '2026-04-05T10:00:00Z',
320
+ summary: 'Done remotely',
321
+ },
322
+ {
323
+ taskId: 't2',
324
+ title: 'Another remote task',
325
+ completedBy: 'remote-agent',
326
+ timestamp: '2026-04-05T11:00:00Z',
327
+ summary: 'Also done',
328
+ },
329
+ ],
330
+ },
331
+ })),
332
+ );
333
+
334
+ const result = await team.audit();
335
+ expect(result.audit.total).toBe(2);
336
+ expect(result.audit.verified).toBe(1);
337
+ expect(result.stats.byAgent).toHaveLength(1);
338
+ expect(result.stats.byAgent[0].agent).toBe('remote-agent');
339
+
340
+ fetchSpy.mockRestore();
341
+ });
342
+ });