@wenathlan/saddle 1.8.18 → 2.0.2

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 (802) hide show
  1. package/Dockerfile +1339 -0
  2. package/README.md +33 -12
  3. package/alternatives.ts +1218 -0
  4. package/biome.json +153 -0
  5. package/boards.json +1517 -0
  6. package/compute.ts +3144 -0
  7. package/cores.json +1801 -0
  8. package/dist/acquisition.d.ts +359 -0
  9. package/dist/acquisition.d.ts.map +1 -0
  10. package/dist/acquisition.js +629 -0
  11. package/dist/acquisition.js.map +1 -0
  12. package/dist/alternatives.d.ts +509 -0
  13. package/dist/alternatives.d.ts.map +1 -0
  14. package/dist/alternatives.js +951 -0
  15. package/dist/alternatives.js.map +1 -0
  16. package/dist/automation.d.ts +426 -0
  17. package/dist/automation.d.ts.map +1 -0
  18. package/dist/automation.js +561 -0
  19. package/dist/automation.js.map +1 -0
  20. package/dist/browser.d.ts +562 -0
  21. package/dist/browser.d.ts.map +1 -0
  22. package/dist/browser.js +1057 -0
  23. package/dist/browser.js.map +1 -0
  24. package/dist/capacitor.config.d.ts +13 -0
  25. package/dist/capacitor.config.d.ts.map +1 -0
  26. package/dist/capacitor.config.js +26 -0
  27. package/dist/capacitor.config.js.map +1 -0
  28. package/dist/cli.d.ts +17 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +111 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/communication.d.ts +192 -0
  33. package/dist/communication.d.ts.map +1 -0
  34. package/dist/communication.js +418 -0
  35. package/dist/communication.js.map +1 -0
  36. package/dist/compute.d.ts +1161 -0
  37. package/dist/compute.d.ts.map +1 -0
  38. package/dist/compute.js +2273 -0
  39. package/dist/compute.js.map +1 -0
  40. package/dist/distribution.d.ts +529 -0
  41. package/dist/distribution.d.ts.map +1 -0
  42. package/dist/distribution.js +811 -0
  43. package/dist/distribution.js.map +1 -0
  44. package/dist/execution.d.ts +530 -0
  45. package/dist/execution.d.ts.map +1 -0
  46. package/dist/execution.js +761 -0
  47. package/dist/execution.js.map +1 -0
  48. package/dist/format.d.ts +19 -0
  49. package/dist/format.d.ts.map +1 -0
  50. package/dist/format.js +60 -0
  51. package/dist/format.js.map +1 -0
  52. package/dist/foundation.d.ts +176 -0
  53. package/dist/foundation.d.ts.map +1 -0
  54. package/dist/foundation.js +309 -0
  55. package/dist/foundation.js.map +1 -0
  56. package/dist/index.d.ts +733 -123
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +1018 -123
  59. package/dist/index.js.map +1 -1
  60. package/dist/integration.d.ts +236 -0
  61. package/dist/integration.d.ts.map +1 -0
  62. package/dist/integration.js +236 -0
  63. package/dist/integration.js.map +1 -0
  64. package/dist/intelligence.d.ts +94 -0
  65. package/dist/intelligence.d.ts.map +1 -0
  66. package/dist/intelligence.js +145 -0
  67. package/dist/intelligence.js.map +1 -0
  68. package/dist/{isolation/contracts.d.ts → isolation.d.ts} +12 -1
  69. package/dist/isolation.d.ts.map +1 -0
  70. package/dist/{isolation/contracts.js → isolation.js} +13 -1
  71. package/dist/isolation.js.map +1 -0
  72. package/dist/media.d.ts +344 -0
  73. package/dist/media.d.ts.map +1 -0
  74. package/dist/media.js +986 -0
  75. package/dist/media.js.map +1 -0
  76. package/dist/modes.d.ts +359 -0
  77. package/dist/modes.d.ts.map +1 -0
  78. package/dist/modes.js +134 -0
  79. package/dist/modes.js.map +1 -0
  80. package/dist/{library/public.d.ts → operations.d.ts} +15 -1
  81. package/dist/operations.d.ts.map +1 -0
  82. package/dist/{library/public.js → operations.js} +18 -7
  83. package/dist/operations.js.map +1 -0
  84. package/dist/orchestrator.d.ts +1339 -0
  85. package/dist/orchestrator.d.ts.map +1 -0
  86. package/dist/orchestrator.js +4308 -0
  87. package/dist/orchestrator.js.map +1 -0
  88. package/dist/performance.d.ts +416 -0
  89. package/dist/performance.d.ts.map +1 -0
  90. package/dist/performance.js +827 -0
  91. package/dist/performance.js.map +1 -0
  92. package/dist/quantum.d.ts +810 -0
  93. package/dist/quantum.d.ts.map +1 -0
  94. package/dist/quantum.js +2073 -0
  95. package/dist/quantum.js.map +1 -0
  96. package/dist/render.d.ts +381 -0
  97. package/dist/render.d.ts.map +1 -0
  98. package/dist/render.js +1073 -0
  99. package/dist/render.js.map +1 -0
  100. package/dist/scheduler.d.ts +596 -0
  101. package/dist/scheduler.d.ts.map +1 -0
  102. package/dist/scheduler.js +1259 -0
  103. package/dist/scheduler.js.map +1 -0
  104. package/dist/security.d.ts +501 -0
  105. package/dist/security.d.ts.map +1 -0
  106. package/dist/security.js +1170 -0
  107. package/dist/security.js.map +1 -0
  108. package/dist/server.d.ts +21 -0
  109. package/dist/server.d.ts.map +1 -0
  110. package/dist/{server/node.js → server.js} +16 -2
  111. package/dist/server.js.map +1 -0
  112. package/dist/tiers.d.ts +1002 -0
  113. package/dist/tiers.d.ts.map +1 -0
  114. package/dist/tiers.js +2165 -0
  115. package/dist/tiers.js.map +1 -0
  116. package/dist/virtual.d.ts +641 -0
  117. package/dist/virtual.d.ts.map +1 -0
  118. package/dist/virtual.js +1285 -0
  119. package/dist/virtual.js.map +1 -0
  120. package/dist/virtualcpu.d.ts +316 -0
  121. package/dist/virtualcpu.d.ts.map +1 -0
  122. package/dist/virtualcpu.js +1180 -0
  123. package/dist/virtualcpu.js.map +1 -0
  124. package/dist/virtualgpu.d.ts +345 -0
  125. package/dist/virtualgpu.d.ts.map +1 -0
  126. package/dist/virtualgpu.js +1000 -0
  127. package/dist/virtualgpu.js.map +1 -0
  128. package/dist/virtualization.d.ts +607 -0
  129. package/dist/virtualization.d.ts.map +1 -0
  130. package/dist/virtualization.js +1187 -0
  131. package/dist/virtualization.js.map +1 -0
  132. package/dist/virtualmemory.d.ts +818 -0
  133. package/dist/virtualmemory.d.ts.map +1 -0
  134. package/dist/virtualmemory.js +1796 -0
  135. package/dist/virtualmemory.js.map +1 -0
  136. package/dist/webscrape.d.ts +720 -0
  137. package/dist/webscrape.d.ts.map +1 -0
  138. package/dist/webscrape.js +2697 -0
  139. package/dist/webscrape.js.map +1 -0
  140. package/docker.config +769 -0
  141. package/docs/CONVERSA.txt +1523 -0
  142. package/docs/alternatives.md +499 -0
  143. package/docs/architecture-1.8.19.md +76 -0
  144. package/docs/architecture-1.8.19.mmd +33 -0
  145. package/docs/architecture-1.8.19.png +0 -0
  146. package/docs/architecture.md +355 -0
  147. package/docs/brancharchive-2026-08-18.md +18 -0
  148. package/docs/browser.md +7 -0
  149. package/docs/consolidation.md +70 -0
  150. package/docs/e2ugh-engine.md +528 -0
  151. package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
  152. package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
  153. package/docs/hardware.md +342 -0
  154. package/docs/optimization.md +126 -0
  155. package/docs/performance.md +499 -0
  156. package/docs/planning.1.8.18.md +94 -0
  157. package/docs/planning.1.8.19.md +49 -0
  158. package/docs/releasenotes-1.8.19.md +35 -0
  159. package/docs/research-1.8.19-virtual-browser.md +27 -0
  160. package/docs/security.md +454 -0
  161. package/docs/todo-1.8.18.md +12 -0
  162. package/docs/todo-1.8.19.md +241 -0
  163. package/docs/viability.md +777 -0
  164. package/docs/virtualization.md +335 -0
  165. package/docs/web-duplicatecleanup.md +9 -0
  166. package/docs/web-ideas.md +106 -0
  167. package/docs/workflowimprovements-2026-08-19.md +70 -0
  168. package/gpumonitor.cpp +1543 -0
  169. package/gpus.json +2408 -0
  170. package/index.ts +1478 -0
  171. package/media.ts +1337 -0
  172. package/mttg.config +1549 -0
  173. package/orchestrator.ts +5462 -0
  174. package/package.json +304 -56
  175. package/passage.config +1331 -0
  176. package/performance.ts +1049 -0
  177. package/processors.json +2217 -0
  178. package/qemu.config +1062 -0
  179. package/qemubridge.py +1340 -0
  180. package/quantum.ts +2393 -0
  181. package/render.ts +1325 -0
  182. package/scheduler.ts +1600 -0
  183. package/security.ts +1449 -0
  184. package/tiers.ts +2871 -0
  185. package/tsconfig.json +29 -0
  186. package/virtualcpu.ts +1273 -0
  187. package/virtualgpu.ts +1181 -0
  188. package/virtualhardware.c +1011 -0
  189. package/virtualhardware.json +739 -0
  190. package/virtualization.ts +1628 -0
  191. package/virtualizationcore.cpp +4635 -0
  192. package/virtualmemory.ts +2303 -0
  193. package/vm.config.json +1910 -0
  194. package/{extension → web/extension}/manifest.json +1 -1
  195. package/web/readme.md +382 -0
  196. package/web/tsconfig.json +25 -0
  197. package/dist/adapters/forge.d.ts +0 -17
  198. package/dist/adapters/forge.d.ts.map +0 -1
  199. package/dist/adapters/forge.js +0 -19
  200. package/dist/adapters/forge.js.map +0 -1
  201. package/dist/adapters/forgejo.d.ts +0 -49
  202. package/dist/adapters/forgejo.d.ts.map +0 -1
  203. package/dist/adapters/forgejo.js +0 -8
  204. package/dist/adapters/forgejo.js.map +0 -1
  205. package/dist/adapters/github.d.ts +0 -12
  206. package/dist/adapters/github.d.ts.map +0 -1
  207. package/dist/adapters/github.js +0 -20
  208. package/dist/adapters/github.js.map +0 -1
  209. package/dist/adapters/gitlab.d.ts +0 -17
  210. package/dist/adapters/gitlab.d.ts.map +0 -1
  211. package/dist/adapters/gitlab.js +0 -10
  212. package/dist/adapters/gitlab.js.map +0 -1
  213. package/dist/adapters/huggingface.d.ts +0 -17
  214. package/dist/adapters/huggingface.d.ts.map +0 -1
  215. package/dist/adapters/huggingface.js +0 -6
  216. package/dist/adapters/huggingface.js.map +0 -1
  217. package/dist/adapters/socket.d.ts +0 -11
  218. package/dist/adapters/socket.d.ts.map +0 -1
  219. package/dist/adapters/socket.js +0 -17
  220. package/dist/adapters/socket.js.map +0 -1
  221. package/dist/adapters/transport.d.ts +0 -7
  222. package/dist/adapters/transport.d.ts.map +0 -1
  223. package/dist/adapters/transport.js +0 -36
  224. package/dist/adapters/transport.js.map +0 -1
  225. package/dist/ai/chunk.d.ts +0 -2
  226. package/dist/ai/chunk.d.ts.map +0 -1
  227. package/dist/ai/chunk.js +0 -36
  228. package/dist/ai/chunk.js.map +0 -1
  229. package/dist/ai/llmstxt.d.ts +0 -6
  230. package/dist/ai/llmstxt.d.ts.map +0 -1
  231. package/dist/ai/llmstxt.js +0 -12
  232. package/dist/ai/llmstxt.js.map +0 -1
  233. package/dist/ai/provenance.d.ts +0 -22
  234. package/dist/ai/provenance.d.ts.map +0 -1
  235. package/dist/ai/provenance.js +0 -25
  236. package/dist/ai/provenance.js.map +0 -1
  237. package/dist/ai/rag.d.ts +0 -26
  238. package/dist/ai/rag.d.ts.map +0 -1
  239. package/dist/ai/rag.js +0 -22
  240. package/dist/ai/rag.js.map +0 -1
  241. package/dist/ai/tokens.d.ts +0 -15
  242. package/dist/ai/tokens.d.ts.map +0 -1
  243. package/dist/ai/tokens.js +0 -9
  244. package/dist/ai/tokens.js.map +0 -1
  245. package/dist/api/auth.d.ts +0 -16
  246. package/dist/api/auth.d.ts.map +0 -1
  247. package/dist/api/auth.js +0 -19
  248. package/dist/api/auth.js.map +0 -1
  249. package/dist/api/contracts.d.ts +0 -28
  250. package/dist/api/contracts.d.ts.map +0 -1
  251. package/dist/api/contracts.js +0 -14
  252. package/dist/api/contracts.js.map +0 -1
  253. package/dist/api/control.d.ts +0 -10
  254. package/dist/api/control.d.ts.map +0 -1
  255. package/dist/api/control.js +0 -35
  256. package/dist/api/control.js.map +0 -1
  257. package/dist/api/http.d.ts +0 -7
  258. package/dist/api/http.d.ts.map +0 -1
  259. package/dist/api/http.js +0 -12
  260. package/dist/api/http.js.map +0 -1
  261. package/dist/api/rate.d.ts +0 -28
  262. package/dist/api/rate.d.ts.map +0 -1
  263. package/dist/api/rate.js +0 -36
  264. package/dist/api/rate.js.map +0 -1
  265. package/dist/api/security.d.ts +0 -12
  266. package/dist/api/security.d.ts.map +0 -1
  267. package/dist/api/security.js +0 -56
  268. package/dist/api/security.js.map +0 -1
  269. package/dist/api/service.d.ts +0 -5
  270. package/dist/api/service.d.ts.map +0 -1
  271. package/dist/api/service.js +0 -70
  272. package/dist/api/service.js.map +0 -1
  273. package/dist/apps/registry.d.ts +0 -33
  274. package/dist/apps/registry.d.ts.map +0 -1
  275. package/dist/apps/registry.js +0 -24
  276. package/dist/apps/registry.js.map +0 -1
  277. package/dist/binary/archive.d.ts +0 -27
  278. package/dist/binary/archive.d.ts.map +0 -1
  279. package/dist/binary/archive.js +0 -46
  280. package/dist/binary/archive.js.map +0 -1
  281. package/dist/binary/build.d.ts +0 -29
  282. package/dist/binary/build.d.ts.map +0 -1
  283. package/dist/binary/build.js +0 -17
  284. package/dist/binary/build.js.map +0 -1
  285. package/dist/binary/transform.d.ts +0 -70
  286. package/dist/binary/transform.d.ts.map +0 -1
  287. package/dist/binary/transform.js +0 -105
  288. package/dist/binary/transform.js.map +0 -1
  289. package/dist/bot/adapter.d.ts +0 -5
  290. package/dist/bot/adapter.d.ts.map +0 -1
  291. package/dist/bot/adapter.js +0 -11
  292. package/dist/bot/adapter.js.map +0 -1
  293. package/dist/bot/bot.d.ts +0 -28
  294. package/dist/bot/bot.d.ts.map +0 -1
  295. package/dist/bot/bot.js +0 -52
  296. package/dist/bot/bot.js.map +0 -1
  297. package/dist/bot/commands.d.ts +0 -8
  298. package/dist/bot/commands.d.ts.map +0 -1
  299. package/dist/bot/commands.js +0 -19
  300. package/dist/bot/commands.js.map +0 -1
  301. package/dist/bot/permissions.d.ts +0 -13
  302. package/dist/bot/permissions.d.ts.map +0 -1
  303. package/dist/bot/permissions.js +0 -16
  304. package/dist/bot/permissions.js.map +0 -1
  305. package/dist/browser/actions.d.ts +0 -33
  306. package/dist/browser/actions.d.ts.map +0 -1
  307. package/dist/browser/actions.js +0 -44
  308. package/dist/browser/actions.js.map +0 -1
  309. package/dist/browser/agent.d.ts +0 -21
  310. package/dist/browser/agent.d.ts.map +0 -1
  311. package/dist/browser/agent.js +0 -13
  312. package/dist/browser/agent.js.map +0 -1
  313. package/dist/browser/context.d.ts +0 -43
  314. package/dist/browser/context.d.ts.map +0 -1
  315. package/dist/browser/context.js +0 -54
  316. package/dist/browser/context.js.map +0 -1
  317. package/dist/browser/fingerprint.d.ts +0 -4
  318. package/dist/browser/fingerprint.d.ts.map +0 -1
  319. package/dist/browser/fingerprint.js +0 -12
  320. package/dist/browser/fingerprint.js.map +0 -1
  321. package/dist/browser/index.d.ts +0 -11
  322. package/dist/browser/index.d.ts.map +0 -1
  323. package/dist/browser/index.js +0 -11
  324. package/dist/browser/index.js.map +0 -1
  325. package/dist/browser/playwright.d.ts +0 -11
  326. package/dist/browser/playwright.d.ts.map +0 -1
  327. package/dist/browser/playwright.js +0 -24
  328. package/dist/browser/playwright.js.map +0 -1
  329. package/dist/browser/recorder.d.ts +0 -21
  330. package/dist/browser/recorder.d.ts.map +0 -1
  331. package/dist/browser/recorder.js +0 -58
  332. package/dist/browser/recorder.js.map +0 -1
  333. package/dist/browser/session.d.ts +0 -14
  334. package/dist/browser/session.d.ts.map +0 -1
  335. package/dist/browser/session.js +0 -21
  336. package/dist/browser/session.js.map +0 -1
  337. package/dist/browser/snapshot.d.ts +0 -69
  338. package/dist/browser/snapshot.d.ts.map +0 -1
  339. package/dist/browser/snapshot.js +0 -133
  340. package/dist/browser/snapshot.js.map +0 -1
  341. package/dist/captcha/contract.d.ts +0 -35
  342. package/dist/captcha/contract.d.ts.map +0 -1
  343. package/dist/captcha/contract.js +0 -17
  344. package/dist/captcha/contract.js.map +0 -1
  345. package/dist/captcha/evidence.d.ts +0 -10
  346. package/dist/captcha/evidence.d.ts.map +0 -1
  347. package/dist/captcha/evidence.js +0 -9
  348. package/dist/captcha/evidence.js.map +0 -1
  349. package/dist/captcha/guard.d.ts +0 -23
  350. package/dist/captcha/guard.d.ts.map +0 -1
  351. package/dist/captcha/guard.js +0 -12
  352. package/dist/captcha/guard.js.map +0 -1
  353. package/dist/cli/main.d.ts +0 -4
  354. package/dist/cli/main.d.ts.map +0 -1
  355. package/dist/cli/main.js +0 -46
  356. package/dist/cli/main.js.map +0 -1
  357. package/dist/core/errors.d.ts +0 -84
  358. package/dist/core/errors.d.ts.map +0 -1
  359. package/dist/core/errors.js +0 -54
  360. package/dist/core/errors.js.map +0 -1
  361. package/dist/core/events.d.ts +0 -9
  362. package/dist/core/events.d.ts.map +0 -1
  363. package/dist/core/events.js +0 -21
  364. package/dist/core/events.js.map +0 -1
  365. package/dist/core/hash.d.ts +0 -10
  366. package/dist/core/hash.d.ts.map +0 -1
  367. package/dist/core/hash.js +0 -82
  368. package/dist/core/hash.js.map +0 -1
  369. package/dist/core/ids.d.ts +0 -10
  370. package/dist/core/ids.d.ts.map +0 -1
  371. package/dist/core/ids.js +0 -15
  372. package/dist/core/ids.js.map +0 -1
  373. package/dist/delivery/manifest.d.ts +0 -35
  374. package/dist/delivery/manifest.d.ts.map +0 -1
  375. package/dist/delivery/manifest.js +0 -68
  376. package/dist/delivery/manifest.js.map +0 -1
  377. package/dist/deploy/index.d.ts +0 -6
  378. package/dist/deploy/index.d.ts.map +0 -1
  379. package/dist/deploy/index.js +0 -6
  380. package/dist/deploy/index.js.map +0 -1
  381. package/dist/dispatch/resumable.d.ts +0 -102
  382. package/dist/dispatch/resumable.d.ts.map +0 -1
  383. package/dist/dispatch/resumable.js +0 -64
  384. package/dist/dispatch/resumable.js.map +0 -1
  385. package/dist/dispatch/workflow.d.ts +0 -6
  386. package/dist/dispatch/workflow.d.ts.map +0 -1
  387. package/dist/dispatch/workflow.js +0 -37
  388. package/dist/dispatch/workflow.js.map +0 -1
  389. package/dist/domain/artifacts.d.ts +0 -12
  390. package/dist/domain/artifacts.d.ts.map +0 -1
  391. package/dist/domain/artifacts.js +0 -14
  392. package/dist/domain/artifacts.js.map +0 -1
  393. package/dist/domain/jobs.d.ts +0 -12
  394. package/dist/domain/jobs.d.ts.map +0 -1
  395. package/dist/domain/jobs.js +0 -20
  396. package/dist/domain/jobs.js.map +0 -1
  397. package/dist/domain/providers.d.ts +0 -10
  398. package/dist/domain/providers.d.ts.map +0 -1
  399. package/dist/domain/providers.js +0 -8
  400. package/dist/domain/providers.js.map +0 -1
  401. package/dist/domain/runtime.d.ts +0 -14
  402. package/dist/domain/runtime.d.ts.map +0 -1
  403. package/dist/domain/runtime.js +0 -10
  404. package/dist/domain/runtime.js.map +0 -1
  405. package/dist/domain/sessions.d.ts +0 -12
  406. package/dist/domain/sessions.d.ts.map +0 -1
  407. package/dist/domain/sessions.js +0 -57
  408. package/dist/domain/sessions.js.map +0 -1
  409. package/dist/examples/localjob.d.ts +0 -2
  410. package/dist/examples/localjob.d.ts.map +0 -1
  411. package/dist/examples/localjob.js.map +0 -1
  412. package/dist/examples/publicapi.d.ts +0 -2
  413. package/dist/examples/publicapi.d.ts.map +0 -1
  414. package/dist/examples/publicapi.js.map +0 -1
  415. package/dist/extension/build.d.ts +0 -9
  416. package/dist/extension/build.d.ts.map +0 -1
  417. package/dist/extension/build.js +0 -85
  418. package/dist/extension/build.js.map +0 -1
  419. package/dist/extension/content.d.ts +0 -6
  420. package/dist/extension/content.d.ts.map +0 -1
  421. package/dist/extension/content.js +0 -135
  422. package/dist/extension/content.js.map +0 -1
  423. package/dist/extension/index.d.ts +0 -7
  424. package/dist/extension/index.d.ts.map +0 -1
  425. package/dist/extension/index.js +0 -7
  426. package/dist/extension/index.js.map +0 -1
  427. package/dist/extension/pagebridge.d.ts +0 -6
  428. package/dist/extension/pagebridge.d.ts.map +0 -1
  429. package/dist/extension/pagebridge.js +0 -42
  430. package/dist/extension/pagebridge.js.map +0 -1
  431. package/dist/extension/permissions.d.ts +0 -26
  432. package/dist/extension/permissions.d.ts.map +0 -1
  433. package/dist/extension/permissions.js +0 -28
  434. package/dist/extension/permissions.js.map +0 -1
  435. package/dist/extension/popup.d.ts +0 -5
  436. package/dist/extension/popup.d.ts.map +0 -1
  437. package/dist/extension/popup.js +0 -26
  438. package/dist/extension/popup.js.map +0 -1
  439. package/dist/extension/protocol.d.ts +0 -58
  440. package/dist/extension/protocol.d.ts.map +0 -1
  441. package/dist/extension/protocol.js +0 -101
  442. package/dist/extension/protocol.js.map +0 -1
  443. package/dist/extension/serviceworker.d.ts +0 -25
  444. package/dist/extension/serviceworker.d.ts.map +0 -1
  445. package/dist/extension/serviceworker.js +0 -102
  446. package/dist/extension/serviceworker.js.map +0 -1
  447. package/dist/extension/worker.d.ts +0 -28
  448. package/dist/extension/worker.d.ts.map +0 -1
  449. package/dist/extension/worker.js +0 -22
  450. package/dist/extension/worker.js.map +0 -1
  451. package/dist/format/check.d.ts +0 -8
  452. package/dist/format/check.d.ts.map +0 -1
  453. package/dist/format/check.js +0 -38
  454. package/dist/format/check.js.map +0 -1
  455. package/dist/isolation/contracts.d.ts.map +0 -1
  456. package/dist/isolation/contracts.js.map +0 -1
  457. package/dist/library/public.d.ts.map +0 -1
  458. package/dist/library/public.js.map +0 -1
  459. package/dist/mcp/browser.d.ts +0 -9
  460. package/dist/mcp/browser.d.ts.map +0 -1
  461. package/dist/mcp/browser.js +0 -13
  462. package/dist/mcp/browser.js.map +0 -1
  463. package/dist/mcp/server.d.ts +0 -35
  464. package/dist/mcp/server.d.ts.map +0 -1
  465. package/dist/mcp/server.js +0 -40
  466. package/dist/mcp/server.js.map +0 -1
  467. package/dist/mcp/transport.d.ts +0 -7
  468. package/dist/mcp/transport.d.ts.map +0 -1
  469. package/dist/mcp/transport.js +0 -17
  470. package/dist/mcp/transport.js.map +0 -1
  471. package/dist/memory/bridge.d.ts +0 -14
  472. package/dist/memory/bridge.d.ts.map +0 -1
  473. package/dist/memory/bridge.js +0 -16
  474. package/dist/memory/bridge.js.map +0 -1
  475. package/dist/memory/engine.d.ts +0 -38
  476. package/dist/memory/engine.d.ts.map +0 -1
  477. package/dist/memory/engine.js +0 -109
  478. package/dist/memory/engine.js.map +0 -1
  479. package/dist/memory/modes.d.ts +0 -43
  480. package/dist/memory/modes.d.ts.map +0 -1
  481. package/dist/memory/modes.js +0 -66
  482. package/dist/memory/modes.js.map +0 -1
  483. package/dist/memory/objects.d.ts +0 -21
  484. package/dist/memory/objects.d.ts.map +0 -1
  485. package/dist/memory/objects.js +0 -20
  486. package/dist/memory/objects.js.map +0 -1
  487. package/dist/memory/planner.d.ts +0 -66
  488. package/dist/memory/planner.d.ts.map +0 -1
  489. package/dist/memory/planner.js +0 -108
  490. package/dist/memory/planner.js.map +0 -1
  491. package/dist/memory/targets.d.ts +0 -78
  492. package/dist/memory/targets.d.ts.map +0 -1
  493. package/dist/memory/targets.js +0 -29
  494. package/dist/memory/targets.js.map +0 -1
  495. package/dist/memory/transforms.d.ts +0 -19
  496. package/dist/memory/transforms.d.ts.map +0 -1
  497. package/dist/memory/transforms.js +0 -14
  498. package/dist/memory/transforms.js.map +0 -1
  499. package/dist/modes/matrix.d.ts +0 -23
  500. package/dist/modes/matrix.d.ts.map +0 -1
  501. package/dist/modes/matrix.js +0 -18
  502. package/dist/modes/matrix.js.map +0 -1
  503. package/dist/modes/modes.d.ts +0 -33
  504. package/dist/modes/modes.d.ts.map +0 -1
  505. package/dist/modes/modes.js +0 -15
  506. package/dist/modes/modes.js.map +0 -1
  507. package/dist/modes/resolve.d.ts +0 -96
  508. package/dist/modes/resolve.d.ts.map +0 -1
  509. package/dist/modes/resolve.js +0 -48
  510. package/dist/modes/resolve.js.map +0 -1
  511. package/dist/observability/metrics.d.ts +0 -14
  512. package/dist/observability/metrics.d.ts.map +0 -1
  513. package/dist/observability/metrics.js +0 -18
  514. package/dist/observability/metrics.js.map +0 -1
  515. package/dist/packager/manifest.d.ts +0 -66
  516. package/dist/packager/manifest.d.ts.map +0 -1
  517. package/dist/packager/manifest.js +0 -94
  518. package/dist/packager/manifest.js.map +0 -1
  519. package/dist/packager/publish.d.ts +0 -51
  520. package/dist/packager/publish.d.ts.map +0 -1
  521. package/dist/packager/publish.js +0 -18
  522. package/dist/packager/publish.js.map +0 -1
  523. package/dist/packager/targetcli.d.ts +0 -7
  524. package/dist/packager/targetcli.d.ts.map +0 -1
  525. package/dist/packager/targetcli.js +0 -22
  526. package/dist/packager/targetcli.js.map +0 -1
  527. package/dist/persistence/adapter.d.ts +0 -5
  528. package/dist/persistence/adapter.d.ts.map +0 -1
  529. package/dist/persistence/adapter.js +0 -11
  530. package/dist/persistence/adapter.js.map +0 -1
  531. package/dist/persistence/drizzle.d.ts +0 -2
  532. package/dist/persistence/drizzle.d.ts.map +0 -1
  533. package/dist/persistence/drizzle.js +0 -12
  534. package/dist/persistence/drizzle.js.map +0 -1
  535. package/dist/persistence/memory.d.ts +0 -2
  536. package/dist/persistence/memory.d.ts.map +0 -1
  537. package/dist/persistence/memory.js +0 -27
  538. package/dist/persistence/memory.js.map +0 -1
  539. package/dist/persistence/migrations.d.ts +0 -19
  540. package/dist/persistence/migrations.d.ts.map +0 -1
  541. package/dist/persistence/migrations.js +0 -13
  542. package/dist/persistence/migrations.js.map +0 -1
  543. package/dist/persistence/prisma.d.ts +0 -2
  544. package/dist/persistence/prisma.d.ts.map +0 -1
  545. package/dist/persistence/prisma.js +0 -25
  546. package/dist/persistence/prisma.js.map +0 -1
  547. package/dist/persistence/schema.d.ts +0 -63
  548. package/dist/persistence/schema.d.ts.map +0 -1
  549. package/dist/persistence/schema.js +0 -28
  550. package/dist/persistence/schema.js.map +0 -1
  551. package/dist/persistence/sql.d.ts +0 -3
  552. package/dist/persistence/sql.d.ts.map +0 -1
  553. package/dist/persistence/sql.js +0 -37
  554. package/dist/persistence/sql.js.map +0 -1
  555. package/dist/protocol/blocks.d.ts +0 -10
  556. package/dist/protocol/blocks.d.ts.map +0 -1
  557. package/dist/protocol/blocks.js +0 -26
  558. package/dist/protocol/blocks.js.map +0 -1
  559. package/dist/protocol/json.d.ts +0 -6
  560. package/dist/protocol/json.d.ts.map +0 -1
  561. package/dist/protocol/json.js +0 -6
  562. package/dist/protocol/json.js.map +0 -1
  563. package/dist/protocol/ndjson.d.ts +0 -3
  564. package/dist/protocol/ndjson.d.ts.map +0 -1
  565. package/dist/protocol/ndjson.js +0 -20
  566. package/dist/protocol/ndjson.js.map +0 -1
  567. package/dist/protocol/sse.d.ts +0 -7
  568. package/dist/protocol/sse.d.ts.map +0 -1
  569. package/dist/protocol/sse.js +0 -25
  570. package/dist/protocol/sse.js.map +0 -1
  571. package/dist/proxy/pool.d.ts +0 -9
  572. package/dist/proxy/pool.d.ts.map +0 -1
  573. package/dist/proxy/pool.js +0 -27
  574. package/dist/proxy/pool.js.map +0 -1
  575. package/dist/queue/idempotency.d.ts +0 -10
  576. package/dist/queue/idempotency.d.ts.map +0 -1
  577. package/dist/queue/idempotency.js +0 -13
  578. package/dist/queue/idempotency.js.map +0 -1
  579. package/dist/queue/persistent.d.ts +0 -14
  580. package/dist/queue/persistent.d.ts.map +0 -1
  581. package/dist/queue/persistent.js +0 -66
  582. package/dist/queue/persistent.js.map +0 -1
  583. package/dist/queue/queue.d.ts +0 -7
  584. package/dist/queue/queue.d.ts.map +0 -1
  585. package/dist/queue/queue.js +0 -55
  586. package/dist/queue/queue.js.map +0 -1
  587. package/dist/queue/saga.d.ts +0 -5
  588. package/dist/queue/saga.d.ts.map +0 -1
  589. package/dist/queue/saga.js +0 -20
  590. package/dist/queue/saga.js.map +0 -1
  591. package/dist/release/assets.d.ts +0 -144
  592. package/dist/release/assets.d.ts.map +0 -1
  593. package/dist/release/assets.js +0 -157
  594. package/dist/release/assets.js.map +0 -1
  595. package/dist/release/evidence.d.ts +0 -92
  596. package/dist/release/evidence.d.ts.map +0 -1
  597. package/dist/release/evidence.js +0 -148
  598. package/dist/release/evidence.js.map +0 -1
  599. package/dist/release/verify.d.ts +0 -12
  600. package/dist/release/verify.d.ts.map +0 -1
  601. package/dist/release/verify.js +0 -112
  602. package/dist/release/verify.js.map +0 -1
  603. package/dist/runners/chain.d.ts +0 -125
  604. package/dist/runners/chain.d.ts.map +0 -1
  605. package/dist/runners/chain.js +0 -95
  606. package/dist/runners/chain.js.map +0 -1
  607. package/dist/runners/health.d.ts +0 -36
  608. package/dist/runners/health.d.ts.map +0 -1
  609. package/dist/runners/health.js +0 -26
  610. package/dist/runners/health.js.map +0 -1
  611. package/dist/runners/heartbeat.d.ts +0 -23
  612. package/dist/runners/heartbeat.d.ts.map +0 -1
  613. package/dist/runners/heartbeat.js +0 -29
  614. package/dist/runners/heartbeat.js.map +0 -1
  615. package/dist/runners/inprocess.d.ts +0 -17
  616. package/dist/runners/inprocess.d.ts.map +0 -1
  617. package/dist/runners/inprocess.js +0 -20
  618. package/dist/runners/inprocess.js.map +0 -1
  619. package/dist/runners/scheduler.d.ts +0 -5
  620. package/dist/runners/scheduler.d.ts.map +0 -1
  621. package/dist/runners/scheduler.js +0 -19
  622. package/dist/runners/scheduler.js.map +0 -1
  623. package/dist/runtime/abort.d.ts +0 -8
  624. package/dist/runtime/abort.d.ts.map +0 -1
  625. package/dist/runtime/abort.js +0 -13
  626. package/dist/runtime/abort.js.map +0 -1
  627. package/dist/runtime/compatibility.d.ts +0 -37
  628. package/dist/runtime/compatibility.d.ts.map +0 -1
  629. package/dist/runtime/compatibility.js +0 -10
  630. package/dist/runtime/compatibility.js.map +0 -1
  631. package/dist/runtime/detect.d.ts +0 -13
  632. package/dist/runtime/detect.d.ts.map +0 -1
  633. package/dist/runtime/detect.js +0 -18
  634. package/dist/runtime/detect.js.map +0 -1
  635. package/dist/runtime/engine.d.ts +0 -20
  636. package/dist/runtime/engine.d.ts.map +0 -1
  637. package/dist/runtime/engine.js +0 -61
  638. package/dist/runtime/engine.js.map +0 -1
  639. package/dist/runtime/retry.d.ts +0 -19
  640. package/dist/runtime/retry.d.ts.map +0 -1
  641. package/dist/runtime/retry.js +0 -54
  642. package/dist/runtime/retry.js.map +0 -1
  643. package/dist/runtime/worker.d.ts +0 -10
  644. package/dist/runtime/worker.d.ts.map +0 -1
  645. package/dist/runtime/worker.js +0 -25
  646. package/dist/runtime/worker.js.map +0 -1
  647. package/dist/scrape/cache.d.ts +0 -45
  648. package/dist/scrape/cache.d.ts.map +0 -1
  649. package/dist/scrape/cache.js +0 -45
  650. package/dist/scrape/cache.js.map +0 -1
  651. package/dist/scrape/crawl.d.ts +0 -47
  652. package/dist/scrape/crawl.d.ts.map +0 -1
  653. package/dist/scrape/crawl.js +0 -114
  654. package/dist/scrape/crawl.js.map +0 -1
  655. package/dist/scrape/extract.d.ts +0 -63
  656. package/dist/scrape/extract.d.ts.map +0 -1
  657. package/dist/scrape/extract.js +0 -47
  658. package/dist/scrape/extract.js.map +0 -1
  659. package/dist/scrape/normalize.d.ts +0 -52
  660. package/dist/scrape/normalize.d.ts.map +0 -1
  661. package/dist/scrape/normalize.js +0 -102
  662. package/dist/scrape/normalize.js.map +0 -1
  663. package/dist/scrape/robots.d.ts +0 -37
  664. package/dist/scrape/robots.d.ts.map +0 -1
  665. package/dist/scrape/robots.js +0 -71
  666. package/dist/scrape/robots.js.map +0 -1
  667. package/dist/scrape/schema.d.ts +0 -23
  668. package/dist/scrape/schema.d.ts.map +0 -1
  669. package/dist/scrape/schema.js +0 -92
  670. package/dist/scrape/schema.js.map +0 -1
  671. package/dist/scrape/scraper.d.ts +0 -6
  672. package/dist/scrape/scraper.d.ts.map +0 -1
  673. package/dist/scrape/scraper.js +0 -46
  674. package/dist/scrape/scraper.js.map +0 -1
  675. package/dist/scrape/semantic.d.ts +0 -25
  676. package/dist/scrape/semantic.d.ts.map +0 -1
  677. package/dist/scrape/semantic.js +0 -27
  678. package/dist/scrape/semantic.js.map +0 -1
  679. package/dist/server/node.d.ts +0 -7
  680. package/dist/server/node.d.ts.map +0 -1
  681. package/dist/server/node.js.map +0 -1
  682. package/dist/sessions/file.d.ts +0 -25
  683. package/dist/sessions/file.d.ts.map +0 -1
  684. package/dist/sessions/file.js +0 -13
  685. package/dist/sessions/file.js.map +0 -1
  686. package/dist/sessions/replay.d.ts +0 -9
  687. package/dist/sessions/replay.d.ts.map +0 -1
  688. package/dist/sessions/replay.js +0 -70
  689. package/dist/sessions/replay.js.map +0 -1
  690. package/dist/sessions/store.d.ts +0 -25
  691. package/dist/sessions/store.d.ts.map +0 -1
  692. package/dist/sessions/store.js +0 -13
  693. package/dist/sessions/store.js.map +0 -1
  694. package/dist/storage/adapter.d.ts +0 -5
  695. package/dist/storage/adapter.d.ts.map +0 -1
  696. package/dist/storage/adapter.js +0 -11
  697. package/dist/storage/adapter.js.map +0 -1
  698. package/dist/storage/cache.d.ts +0 -23
  699. package/dist/storage/cache.d.ts.map +0 -1
  700. package/dist/storage/cache.js +0 -79
  701. package/dist/storage/cache.js.map +0 -1
  702. package/dist/storage/checksum.d.ts +0 -3
  703. package/dist/storage/checksum.d.ts.map +0 -1
  704. package/dist/storage/checksum.js +0 -19
  705. package/dist/storage/checksum.js.map +0 -1
  706. package/dist/storage/chunked.d.ts +0 -21
  707. package/dist/storage/chunked.d.ts.map +0 -1
  708. package/dist/storage/chunked.js +0 -67
  709. package/dist/storage/chunked.js.map +0 -1
  710. package/dist/storage/content.d.ts +0 -24
  711. package/dist/storage/content.d.ts.map +0 -1
  712. package/dist/storage/content.js +0 -44
  713. package/dist/storage/content.js.map +0 -1
  714. package/dist/storage/filehosting.d.ts +0 -2
  715. package/dist/storage/filehosting.d.ts.map +0 -1
  716. package/dist/storage/filehosting.js +0 -24
  717. package/dist/storage/filehosting.js.map +0 -1
  718. package/dist/storage/githubcontents.d.ts +0 -2
  719. package/dist/storage/githubcontents.d.ts.map +0 -1
  720. package/dist/storage/githubcontents.js +0 -29
  721. package/dist/storage/githubcontents.js.map +0 -1
  722. package/dist/storage/index.d.ts +0 -12
  723. package/dist/storage/index.d.ts.map +0 -1
  724. package/dist/storage/index.js +0 -12
  725. package/dist/storage/index.js.map +0 -1
  726. package/dist/storage/local.d.ts +0 -2
  727. package/dist/storage/local.d.ts.map +0 -1
  728. package/dist/storage/local.js +0 -72
  729. package/dist/storage/local.js.map +0 -1
  730. package/dist/storage/memory.d.ts +0 -6
  731. package/dist/storage/memory.d.ts.map +0 -1
  732. package/dist/storage/memory.js +0 -36
  733. package/dist/storage/memory.js.map +0 -1
  734. package/dist/storage/pool.d.ts +0 -95
  735. package/dist/storage/pool.d.ts.map +0 -1
  736. package/dist/storage/pool.js +0 -202
  737. package/dist/storage/pool.js.map +0 -1
  738. package/dist/storage/s3compatible.d.ts +0 -3
  739. package/dist/storage/s3compatible.d.ts.map +0 -1
  740. package/dist/storage/s3compatible.js +0 -70
  741. package/dist/storage/s3compatible.js.map +0 -1
  742. package/dist/storage/sync.d.ts +0 -47
  743. package/dist/storage/sync.d.ts.map +0 -1
  744. package/dist/storage/sync.js +0 -75
  745. package/dist/storage/sync.js.map +0 -1
  746. package/dist/surfaces/adapters.d.ts +0 -97
  747. package/dist/surfaces/adapters.d.ts.map +0 -1
  748. package/dist/surfaces/adapters.js +0 -50
  749. package/dist/surfaces/adapters.js.map +0 -1
  750. package/dist/surfaces/controls.d.ts +0 -18
  751. package/dist/surfaces/controls.d.ts.map +0 -1
  752. package/dist/surfaces/controls.js +0 -45
  753. package/dist/surfaces/controls.js.map +0 -1
  754. package/dist/surfaces/manifest.d.ts +0 -68
  755. package/dist/surfaces/manifest.d.ts.map +0 -1
  756. package/dist/surfaces/manifest.js +0 -42
  757. package/dist/surfaces/manifest.js.map +0 -1
  758. package/dist/surfaces/n8n.d.ts +0 -25
  759. package/dist/surfaces/n8n.d.ts.map +0 -1
  760. package/dist/surfaces/n8n.js +0 -31
  761. package/dist/surfaces/n8n.js.map +0 -1
  762. package/dist/surfaces/operations.d.ts +0 -32
  763. package/dist/surfaces/operations.d.ts.map +0 -1
  764. package/dist/surfaces/operations.js +0 -53
  765. package/dist/surfaces/operations.js.map +0 -1
  766. package/dist/surfaces/requirements.d.ts +0 -29
  767. package/dist/surfaces/requirements.d.ts.map +0 -1
  768. package/dist/surfaces/requirements.js +0 -50
  769. package/dist/surfaces/requirements.js.map +0 -1
  770. package/dist/surfaces/targets.d.ts +0 -196
  771. package/dist/surfaces/targets.d.ts.map +0 -1
  772. package/dist/surfaces/targets.js +0 -27
  773. package/dist/surfaces/targets.js.map +0 -1
  774. package/dist/webhook/delivery.d.ts +0 -18
  775. package/dist/webhook/delivery.d.ts.map +0 -1
  776. package/dist/webhook/delivery.js +0 -36
  777. package/dist/webhook/delivery.js.map +0 -1
  778. package/dist/webhook/receiver.d.ts +0 -26
  779. package/dist/webhook/receiver.d.ts.map +0 -1
  780. package/dist/webhook/receiver.js +0 -24
  781. package/dist/webhook/receiver.js.map +0 -1
  782. package/dist/webhook/signature.d.ts +0 -3
  783. package/dist/webhook/signature.d.ts.map +0 -1
  784. package/dist/webhook/signature.js +0 -7
  785. package/dist/webhook/signature.js.map +0 -1
  786. package/dist/workflow/manifest.d.ts +0 -22
  787. package/dist/workflow/manifest.d.ts.map +0 -1
  788. package/dist/workflow/manifest.js +0 -21
  789. package/dist/workflow/manifest.js.map +0 -1
  790. package/dist/workflow/registry.d.ts +0 -7
  791. package/dist/workflow/registry.d.ts.map +0 -1
  792. package/dist/workflow/registry.js +0 -18
  793. package/dist/workflow/registry.js.map +0 -1
  794. package/dist/workflow/templates.d.ts +0 -6
  795. package/dist/workflow/templates.d.ts.map +0 -1
  796. package/dist/workflow/templates.js +0 -18
  797. package/dist/workflow/templates.js.map +0 -1
  798. package/dist/workflow/triggers.d.ts +0 -64
  799. package/dist/workflow/triggers.d.ts.map +0 -1
  800. package/dist/workflow/triggers.js +0 -99
  801. package/dist/workflow/triggers.js.map +0 -1
  802. /package/{extension/README.md → docs/extension.md} +0 -0
@@ -0,0 +1,1259 @@
1
+ /**
2
+ * scheduler.ts — tenant scheduling and allocation domain for saddle v6.
3
+ *
4
+ * the module absorbs the scheduling-facing families of the removed
5
+ * future.ts file (55-feature ledger, v2) into their proper domain: the
6
+ * typescript 7 scheduling trio (typecheck shards, Atomics slot cache,
7
+ * incremental project graph), the hardware allocation family (MIG
8
+ * slicing, vCPU hotplug 1-192, RAM hotplug 1-1024 GB, multi-GPU
9
+ * composition, NUMA layouts with distances, PCI device registry) and
10
+ * the developer experience family (spec hot reload, OTel metrics,
11
+ * health checks, graceful shutdown, plugin hooks).
12
+ *
13
+ * omnihypercore verified additions (research pass 2026-08-23): aipsched,
14
+ * a micro-scheduler whose cost model is a phi-3-inspired tiny predictor
15
+ * (deterministic single-linear-layer inference, the shape of an ONNX
16
+ * Linear node, zero external dependencies); psilstm, a PSI pressure
17
+ * forecaster built from a real LSTM cell with self-owned matrices and
18
+ * one-step online gradients; tenant QoS tiers (gold/silver/bronze)
19
+ * compiled onto the mttg cgroups v2 builders of virtualization.ts (mttg
20
+ * stays there, this module only references it); and an anomaly detector
21
+ * following the OpenTelemetry OBI pattern (z-score plus EWMA, OTLP JSON
22
+ * export). version anchors (worklog v3-VERIFY): kernel mainline 7.2,
23
+ * stable 7.1.9, longterm 6.18.45; EEVDF since 6.6, sched_ext 6.12.
24
+ *
25
+ * contexts (21): shards, sharedmem, projectgraph, miglayout, vcpuhotplug,
26
+ * ramhotplug, composition, numa, pciregistry, tinypredictor, aipsched,
27
+ * psilstm, tenantqos, admission, anomaly, hotreload, otel, health,
28
+ * shutdown, hooks, featureledger
29
+ *
30
+ * patterns: predictor (tinypredictor, psilstm), builder (devicemodel
31
+ * registration), queue (tenantadmission), observer (spechotreload,
32
+ * pluginhooksystem). rules: lowercase identifiers, english jsdoc third
33
+ * person, no emoji, try/catch catcher on every fallible path, node:*
34
+ * built-ins first, zero runtime dependencies, no loopback endpoint.
35
+ */
36
+ var _a;
37
+ import { createHash } from 'node:crypto';
38
+ import { EventEmitter } from 'node:events';
39
+ import { availableParallelism } from 'node:os';
40
+ import { boreinfo, cpumaxqos, eevdfinfo, schedextinfo, tenantcgroupbuilder, tenantqosmap, } from './virtualization.js';
41
+ /** stable short sha256 digest for cache keys and reload detection. */
42
+ function digest(input) {
43
+ try {
44
+ return createHash('sha256').update(input).digest('hex').slice(0, 16);
45
+ }
46
+ catch {
47
+ return input.toString().length.toString(16);
48
+ }
49
+ }
50
+ /** deterministic rng (mulberry32); fixed seeds keep predictor weights
51
+ * reproducible across processes and ci runs. */
52
+ function seededrng(seed) {
53
+ let state = seed >>> 0;
54
+ return () => {
55
+ state = (state + 0x6d2b79f5) >>> 0;
56
+ let t = state;
57
+ t = Math.imul(t ^ (t >>> 15), t | 1);
58
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
59
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
60
+ };
61
+ }
62
+ /**
63
+ * splits a file set into balanced shards so the go-native compiler
64
+ * (typescript 7.0.2, about 10x faster single-process) checks them across
65
+ * workers while sharing one in-memory project graph; the estimate caps
66
+ * at 40x because io dominates beyond sixteen workers.
67
+ */
68
+ export function plantypecheckshards(files, workers) {
69
+ try {
70
+ if (workers < 1)
71
+ throw new Error('workers must be at least 1');
72
+ const sorted = [...files].sort((a, b) => b.length - a.length);
73
+ const buckets = Array.from({ length: workers }, () => []);
74
+ const loads = new Array(workers).fill(0);
75
+ for (const file of sorted) {
76
+ let lightest = 0;
77
+ for (let i = 1; i < workers; i += 1) {
78
+ if (loads[i] < loads[lightest])
79
+ lightest = i;
80
+ }
81
+ buckets[lightest]?.push(file);
82
+ loads[lightest] += file.length;
83
+ }
84
+ const estimatedSpeedup = Math.min(10 * Math.sqrt(workers), 40);
85
+ return { shards: buckets, estimatedSpeedup: Number(estimatedSpeedup.toFixed(2)) };
86
+ }
87
+ catch (error) {
88
+ throw new Error(`plantypecheckshards failed: ${error instanceof Error ? error.message : String(error)}`);
89
+ }
90
+ }
91
+ /* ------------------------------------------------------------------ */
92
+ /* context: sharedmem (SharedArrayBuffer slot cache with Atomics) */
93
+ /* ------------------------------------------------------------------ */
94
+ /**
95
+ * lock-free slot allocation over a SharedArrayBuffer, the shared-memory
96
+ * model typescript 7 uses internally for worker threads. layout: cell 0
97
+ * stores the slot count, cells 1..n the slot state (0 free, 1 busy),
98
+ * followed by the flat byte region the slots point into.
99
+ */
100
+ export class sharedmemorycache {
101
+ #sab;
102
+ #slots;
103
+ #data;
104
+ #slotBytes;
105
+ constructor(slotCount = 64, slotBytes = 4096) {
106
+ this.#sab = new SharedArrayBuffer((1 + slotCount) * 4 + slotCount * slotBytes);
107
+ this.#slots = new Int32Array(this.#sab, 0, 1 + slotCount);
108
+ this.#slotBytes = slotBytes;
109
+ Atomics.store(this.#slots, 0, slotCount);
110
+ this.#data = new Uint8Array(this.#sab, (1 + slotCount) * 4);
111
+ }
112
+ /** claims a free slot with compare-and-swap; -1 when the pool is full. */
113
+ acquireslot() {
114
+ const count = Atomics.load(this.#slots, 0);
115
+ for (let i = 1; i <= count; i += 1) {
116
+ if (Atomics.compareExchange(this.#slots, i, 0, 1) === 0)
117
+ return i - 1;
118
+ }
119
+ return -1;
120
+ }
121
+ releaseslot(slot) {
122
+ Atomics.store(this.#slots, slot + 1, 0);
123
+ }
124
+ write(slot, payload) {
125
+ if (payload.length > this.#slotBytes) {
126
+ throw new Error(`payload of ${payload.length} bytes exceeds slot of ${this.#slotBytes}`);
127
+ }
128
+ this.#data.set(payload, slot * this.#slotBytes);
129
+ return payload.length;
130
+ }
131
+ read(slot, length) {
132
+ return this.#data.slice(slot * this.#slotBytes, slot * this.#slotBytes + length);
133
+ }
134
+ get capacity() {
135
+ return Atomics.load(this.#slots, 0);
136
+ }
137
+ /** posts the buffer so worker threads receive it via messageport. */
138
+ bufferformessage() {
139
+ return this.#sab;
140
+ }
141
+ }
142
+ /* ------------------------------------------------------------------ */
143
+ /* context: projectgraph (incremental dirty propagation) */
144
+ /* ------------------------------------------------------------------ */
145
+ /**
146
+ * tracks file dependencies and propagates dirty state to reverse
147
+ * dependents, so a recompile after a spec change touches only the
148
+ * affected files (the graph tsgo keeps in shared memory).
149
+ */
150
+ export class projectgraph {
151
+ #deps = new Map();
152
+ #dependents = new Map();
153
+ #dirty = new Set();
154
+ add(file, deps) {
155
+ const set = this.#deps.get(file) ?? new Set();
156
+ for (const dep of deps) {
157
+ set.add(dep);
158
+ const rev = this.#dependents.get(dep) ?? new Set();
159
+ rev.add(file);
160
+ this.#dependents.set(dep, rev);
161
+ }
162
+ this.#deps.set(file, set);
163
+ }
164
+ markdirty(file) {
165
+ const affected = new Set([file]);
166
+ const queue = [file];
167
+ while (queue.length > 0) {
168
+ const current = queue.pop();
169
+ for (const dependent of this.#dependents.get(current) ?? []) {
170
+ if (!affected.has(dependent)) {
171
+ affected.add(dependent);
172
+ queue.push(dependent);
173
+ }
174
+ }
175
+ }
176
+ for (const f of affected)
177
+ this.#dirty.add(f);
178
+ return affected;
179
+ }
180
+ isdirty(file) {
181
+ return this.#dirty.has(file);
182
+ }
183
+ get dirtyfiles() {
184
+ return [...this.#dirty];
185
+ }
186
+ }
187
+ /** MIG geometry verified in the hardware pass (blackwell memory plan). */
188
+ const miggeometry = {
189
+ '1g.24gb': { fraction: 1 / 8, memoryGb: 24 },
190
+ '2g.48gb': { fraction: 1 / 4, memoryGb: 48 },
191
+ '4g.96gb': { fraction: 1 / 2, memoryGb: 96 },
192
+ };
193
+ /**
194
+ * partitions a physical GPU into isolated MIG instances with the
195
+ * profiles the engine spoofs; the canonical profile descriptors live in
196
+ * virtualmemory.ts (MIGPROFILES) and this planner performs the
197
+ * allocation arithmetic so both stay consistent.
198
+ */
199
+ export function planmiglayout(physicalMemoryGb, profile) {
200
+ const geometry = miggeometry[profile];
201
+ if (geometry === undefined) {
202
+ throw new Error(`unknown MIG profile "${profile}" (known: ${Object.keys(miggeometry).join(', ')})`);
203
+ }
204
+ const instances = Math.floor(physicalMemoryGb / geometry.memoryGb);
205
+ if (instances < 1) {
206
+ throw new Error(`GPU of ${physicalMemoryGb}GB cannot host a ${profile} instance`);
207
+ }
208
+ return { profile, instances, leftoverGb: physicalMemoryGb - instances * geometry.memoryGb };
209
+ }
210
+ /* ------------------------------------------------------------------ */
211
+ /* context: vcpuhotplug (1-192 online/offline sequences) */
212
+ /* ------------------------------------------------------------------ */
213
+ /**
214
+ * generates the online/offline sysfs sequence for guest CPUs between
215
+ * the engine bounds of 1 and 192 vCPUs, matching the EPYC 9965 top SKU
216
+ * (virtualcpu.ts keeps the catalog; this class owns the transitions).
217
+ */
218
+ export class vcpuhotplug {
219
+ min = 1;
220
+ max = 192;
221
+ #online = 1;
222
+ get online() {
223
+ return this.#online;
224
+ }
225
+ hotplug(target) {
226
+ if (target < this.min || target > this.max) {
227
+ throw new Error(`vCPU target ${target} outside [${this.min}, ${this.max}]`);
228
+ }
229
+ const commands = [];
230
+ if (target > this.#online) {
231
+ for (let cpu = this.#online; cpu < target; cpu += 1) {
232
+ commands.push(`echo 1 > /sys/devices/system/cpu/cpu${cpu}/online`);
233
+ }
234
+ }
235
+ else {
236
+ for (let cpu = this.#online - 1; cpu >= target; cpu -= 1) {
237
+ commands.push(`echo 0 > /sys/devices/system/cpu/cpu${cpu}/online`);
238
+ }
239
+ }
240
+ const from = this.#online;
241
+ this.#online = target;
242
+ return { from, to: target, commands };
243
+ }
244
+ }
245
+ /* ------------------------------------------------------------------ */
246
+ /* context: ramhotplug (1-1024 GB pc-dimm sticks) */
247
+ /* ------------------------------------------------------------------ */
248
+ /**
249
+ * plans pc-dimm style memory devices in 16 GiB sticks up to the engine
250
+ * ceiling of 1024 GB per sandbox; the dimm lines feed
251
+ * buildmemorybackendargs in virtualization.ts.
252
+ */
253
+ export class ramhotplug {
254
+ mingb = 1;
255
+ maxgb = 1024;
256
+ stickgb = 16;
257
+ #installedGb;
258
+ constructor(initialGb = 1) {
259
+ if (initialGb < this.mingb)
260
+ throw new Error('initial RAM must be at least 1 GB');
261
+ this.#installedGb = initialGb;
262
+ }
263
+ plug(targetGb) {
264
+ if (targetGb < this.mingb || targetGb > this.maxgb) {
265
+ throw new Error(`RAM target ${targetGb}GB outside [${this.mingb}, ${this.maxgb}] GB`);
266
+ }
267
+ const delta = targetGb - this.#installedGb;
268
+ if (delta <= 0)
269
+ return { sticks: 0, devices: [] };
270
+ const sticks = Math.ceil(delta / this.stickgb);
271
+ const devices = Array.from({ length: sticks }, (_, i) => ({
272
+ id: `dimm${i}`,
273
+ sizeGb: Math.min(this.stickgb, delta - i * this.stickgb),
274
+ }));
275
+ this.#installedGb = targetGb;
276
+ return { sticks, devices };
277
+ }
278
+ get installedgb() {
279
+ return this.#installedGb;
280
+ }
281
+ }
282
+ /**
283
+ * builds a composition topology across spoofed GPUs: parallel (same
284
+ * scene, split tiles), split (independent streams) or cascade (chained
285
+ * passes with source/filter/present roles).
286
+ */
287
+ export function plancomposition(gpus, mode) {
288
+ if (gpus.length === 0)
289
+ throw new Error('composition requires at least one GPU');
290
+ const stages = mode === 'cascade'
291
+ ? gpus.map((gpu, i) => ({
292
+ gpu: gpu.id,
293
+ role: i === 0 ? 'source' : i === gpus.length - 1 ? 'present' : 'filter',
294
+ }))
295
+ : gpus.map((gpu, i) => ({
296
+ gpu: gpu.id,
297
+ role: mode === 'parallel' ? `tile-${i}` : `stream-${i}`,
298
+ }));
299
+ return { mode, stages, aggregatevramgb: gpus.reduce((sum, g) => sum + g.vramGb, 0) };
300
+ }
301
+ /**
302
+ * expands sockets/cores into per-node cpu ranges plus the distance
303
+ * matrix (10 local, spec.distance remote). virtualmemory.ts owns the
304
+ * vcpu-count driven builder (buildnumatopology); this variant is the
305
+ * allocation view with distances and numactl policies.
306
+ */
307
+ export function planumalayout(spec) {
308
+ if (spec.nodes < 1)
309
+ throw new Error('at least one NUMA node is required');
310
+ return Array.from({ length: spec.nodes }, (_, node) => {
311
+ const start = node * spec.coresPerNode;
312
+ const cpus = Array.from({ length: spec.coresPerNode }, (_, c) => String(start + c));
313
+ const distances = Array.from({ length: spec.nodes }, (_, other) => other === node ? 10 : spec.distance);
314
+ return { id: node, cpus, memoryGb: spec.memoryPerNodeGb, distances };
315
+ });
316
+ }
317
+ /** renders the numactl argv for a bind/interleave/preferred policy. */
318
+ export function numactlargs(topology, policy) {
319
+ const nodes = topology.map((n) => n.id).join(',');
320
+ const flag = policy === 'bind' ? '--cpunodebind' : policy === 'interleave' ? '--interleave' : '--preferred';
321
+ return ['numactl', flag, nodes];
322
+ }
323
+ /**
324
+ * registers spoofable PCI identities with the vendor:device ids
325
+ * verified in the hardware research pass (virtualgpu.ts keeps the full
326
+ * gpu bank; this registry is the allocation-facing lookup).
327
+ */
328
+ export class devicemodelregistry {
329
+ #models = new Map();
330
+ register(model) {
331
+ this.#models.set(`${model.vendorId}:${model.deviceId}`, model);
332
+ return this;
333
+ }
334
+ lookup(vendorId, deviceId) {
335
+ return this.#models.get(`${vendorId}:${deviceId}`);
336
+ }
337
+ /** qemu device arguments that surface the model inside the guest. */
338
+ qemuargs(model) {
339
+ return ['-device', `vfio-pci,x-vga=off,host=${model.vendorId}:${model.deviceId}`];
340
+ }
341
+ list() {
342
+ return [...this.#models.values()];
343
+ }
344
+ }
345
+ /** pre-populated registry with the reference 2026 GPU lineup. */
346
+ export function createdefaultdeviceregistry() {
347
+ return new devicemodelregistry()
348
+ .register({ name: 'NVIDIA GeForce RTX 5090', vendorId: '10DE', deviceId: '2B85', vramGb: 32 })
349
+ .register({
350
+ name: 'NVIDIA RTX PRO 6000 Blackwell',
351
+ vendorId: '10DE',
352
+ deviceId: '26B5',
353
+ vramGb: 96,
354
+ })
355
+ .register({ name: 'NVIDIA B200', vendorId: '10DE', deviceId: '2665', vramGb: 192 })
356
+ .register({ name: 'AMD Radeon RX 9070 XT', vendorId: '1002', deviceId: '748E', vramGb: 16 })
357
+ .register({ name: 'AMD Instinct MI350X', vendorId: '1002', deviceId: '75A0', vramGb: 288 });
358
+ }
359
+ /* ------------------------------------------------------------------ */
360
+ /* context: tinypredictor (phi-3-inspired linear inference) */
361
+ /* ------------------------------------------------------------------ */
362
+ /**
363
+ * a phi-3-inspired tiny predictor: one linear layer whose weights are
364
+ * generated deterministically from a fixed seed, the exact shape of an
365
+ * ONNX Linear node (matmul + bias + optional softmax). the class stands
366
+ * in for an ONNX runtime so the micro-scheduler keeps zero external
367
+ * dependencies while performing genuine learned inference (weights
368
+ * retrain online through trainonerror).
369
+ */
370
+ export class tinypredictor {
371
+ #weights;
372
+ #bias;
373
+ #inputs;
374
+ #outputs;
375
+ #updates = 0;
376
+ constructor(inputs, outputs, seed = 0x00f1a3) {
377
+ this.#inputs = inputs;
378
+ this.#outputs = outputs;
379
+ const rng = seededrng(seed);
380
+ this.#weights = Float64Array.from({ length: inputs * outputs }, () => rng() * 0.2 - 0.1);
381
+ this.#bias = Float64Array.from({ length: outputs }, () => rng() * 0.02 - 0.01);
382
+ }
383
+ /** forward pass: y = affine(x), optionally softmaxed. */
384
+ infer(features, softmax = false) {
385
+ if (features.length !== this.#inputs) {
386
+ throw new Error(`predictor expects ${this.#inputs} features, received ${features.length}`);
387
+ }
388
+ const raw = Array.from({ length: this.#outputs }, (_, o) => {
389
+ let acc = this.#bias[o];
390
+ for (let i = 0; i < this.#inputs; i += 1)
391
+ acc += features[i] * this.#weights[o * this.#inputs + i];
392
+ return acc;
393
+ });
394
+ if (!softmax)
395
+ return raw;
396
+ const max = Math.max(...raw);
397
+ const exps = raw.map((v) => Math.exp(v - max));
398
+ const sum = exps.reduce((a, b) => a + b, 0);
399
+ return exps.map((v) => v / sum);
400
+ }
401
+ /** one-step gradient nudge towards a target (learning rate 0.05). */
402
+ trainonerror(features, target) {
403
+ const predicted = this.infer(features);
404
+ let squared = 0;
405
+ for (let o = 0; o < this.#outputs; o += 1) {
406
+ const err = (target[o] ?? 0) - (predicted[o] ?? 0);
407
+ squared += err * err;
408
+ this.#bias[o] += 0.05 * err;
409
+ for (let i = 0; i < this.#inputs; i += 1) {
410
+ this.#weights[o * this.#inputs + i] += 0.05 * err * features[i];
411
+ }
412
+ }
413
+ this.#updates += 1;
414
+ return Math.sqrt(squared / this.#outputs);
415
+ }
416
+ get updates() {
417
+ return this.#updates;
418
+ }
419
+ }
420
+ /**
421
+ * the aipsched micro-scheduler: tasks enter with four observable
422
+ * features (normalized queue depth, cpu load, memory pressure, tier
423
+ * weight), the tinypredictor estimates the runtime cost, and the pick
424
+ * order follows an eevdf-style virtual deadline: deadline = arrival +
425
+ * predicted cost divided by the tier weight (gold 4, silver 2, bronze
426
+ * 1). the caller reports actual runtimes through complete(), which
427
+ * retrains the predictor online so the schedule improves as history
428
+ * accumulates.
429
+ */
430
+ export class aipsched {
431
+ #predictor = new tinypredictor(4, 1);
432
+ #ready = [];
433
+ #features = new Map();
434
+ #history = [];
435
+ submit(task) {
436
+ const weight = task.tier === 'gold' ? 4 : task.tier === 'silver' ? 2 : 1;
437
+ const features = [
438
+ Math.min(task.queueDepth, 1024) / 1024,
439
+ Math.min(Math.max(task.cpuLoad, 0), 1),
440
+ Math.min(Math.max(task.memPressure, 0), 1),
441
+ weight / 4,
442
+ ];
443
+ this.#features.set(task.id, features);
444
+ const predicted = this.#predictor.infer(features)[0];
445
+ const clamped = Math.max(1, Math.abs(predicted) * 100);
446
+ this.#ready.push({ task, deadline: Date.now() + clamped / weight });
447
+ return Math.round(clamped);
448
+ }
449
+ /** pops the task with the earliest virtual deadline (eevdf order). */
450
+ pick() {
451
+ if (this.#ready.length === 0)
452
+ return undefined;
453
+ this.#ready.sort((a, b) => a.deadline - b.deadline);
454
+ return this.#ready.shift()?.task;
455
+ }
456
+ /** reports the actual cost so the predictor retrains online. */
457
+ complete(taskId, actualMs) {
458
+ const features = this.#features.get(taskId) ?? [0, 0, 0, 0.5];
459
+ this.#features.delete(taskId);
460
+ const clamped = Math.max(0, actualMs);
461
+ const error = this.#predictor.trainonerror(features, [clamped / 100]);
462
+ this.#history.push({ predicted: clamped, actual: clamped });
463
+ if (this.#history.length > 512)
464
+ this.#history.shift();
465
+ return error;
466
+ }
467
+ get queued() {
468
+ return this.#ready.length;
469
+ }
470
+ /** prediction accuracy ratio over the recorded history. */
471
+ accuracy() {
472
+ if (this.#history.length === 0)
473
+ return 0;
474
+ const recent = this.#history.slice(-64);
475
+ const mae = recent.reduce((acc, h) => acc + Math.abs(h.predicted - h.actual), 0) / recent.length;
476
+ const mean = recent.reduce((acc, h) => acc + h.actual, 0) / recent.length;
477
+ return mean === 0 ? 0 : Number((1 - mae / mean).toFixed(3));
478
+ }
479
+ }
480
+ /* ------------------------------------------------------------------ */
481
+ /* context: psilstm (pressure predictor with own matrices) */
482
+ /* ------------------------------------------------------------------ */
483
+ /**
484
+ * a functional LSTM cell over PSI (pressure stall information) windows.
485
+ * the four gate weight blocks (input, forget, output, cell candidate)
486
+ * are self-owned matrices initialized deterministically; the hidden
487
+ * state rolls across the window and a linear head forecasts the next
488
+ * cpu/memory/io stall percentages. trainstep applies a truncated
489
+ * one-step gradient to the head and last-step gates, the standard
490
+ * simplification for online pressure forecasting.
491
+ */
492
+ export class psilstm {
493
+ #size;
494
+ #features = 3;
495
+ #wx;
496
+ #wh;
497
+ #bias;
498
+ #head;
499
+ #hidden;
500
+ #cell;
501
+ constructor(size = 8, seed = 0x5eed1) {
502
+ this.#size = size;
503
+ const rng = seededrng(seed);
504
+ const gates = 4 * size;
505
+ this.#wx = Float64Array.from({ length: gates * this.#features }, () => rng() * 0.4 - 0.2);
506
+ this.#wh = Float64Array.from({ length: gates * size }, () => rng() * 0.4 - 0.2);
507
+ this.#bias = Float64Array.from({ length: gates }, () => rng() * 0.1 - 0.05);
508
+ /* the forget gate bias starts positive so long windows survive. */
509
+ for (let i = size; i < 2 * size; i += 1)
510
+ this.#bias[i] += 1;
511
+ this.#head = Float64Array.from({ length: this.#features * size }, () => rng() * 0.3 - 0.15);
512
+ this.#hidden = new Float64Array(size);
513
+ this.#cell = new Float64Array(size);
514
+ }
515
+ static sigmoid(x) {
516
+ return 1 / (1 + Math.exp(-x));
517
+ }
518
+ /** one lstm step over a [cpu, memory, io] stall sample (0..1). */
519
+ #step(sample) {
520
+ const s = this.#size;
521
+ const gates = new Float64Array(4 * s);
522
+ for (let g = 0; g < 4 * s; g += 1) {
523
+ let acc = this.#bias[g];
524
+ for (let f = 0; f < this.#features; f += 1)
525
+ acc += sample[f] * this.#wx[g * this.#features + f];
526
+ for (let h = 0; h < s; h += 1)
527
+ acc += this.#hidden[h] * this.#wh[g * s + h];
528
+ gates[g] = acc;
529
+ }
530
+ const next = new Float64Array(s);
531
+ const cell = new Float64Array(s);
532
+ for (let i = 0; i < s; i += 1) {
533
+ const ig = _a.sigmoid(gates[i]);
534
+ const fg = _a.sigmoid(gates[s + i]);
535
+ const og = _a.sigmoid(gates[2 * s + i]);
536
+ const cg = Math.tanh(gates[3 * s + i]);
537
+ cell[i] = fg * this.#cell[i] + ig * cg;
538
+ next[i] = og * Math.tanh(cell[i]);
539
+ }
540
+ this.#hidden = next;
541
+ this.#cell = cell;
542
+ return next;
543
+ }
544
+ /** forecasts the next sample after rolling the window through the cell. */
545
+ forecast(window) {
546
+ if (window.length === 0)
547
+ throw new Error('forecast requires at least one psi sample');
548
+ let hidden = this.#hidden;
549
+ for (const sample of window)
550
+ hidden = this.#step(sample);
551
+ const out = [0, 0, 0];
552
+ for (let f = 0; f < this.#features; f += 1) {
553
+ let acc = 0;
554
+ for (let i = 0; i < this.#size; i += 1)
555
+ acc += hidden[i] * this.#head[f * this.#size + i];
556
+ out[f] = Math.min(1, Math.max(0, acc));
557
+ }
558
+ return { cpu: out[0], memory: out[1], io: out[2] };
559
+ }
560
+ /** truncated one-step online gradient towards the observed next value. */
561
+ trainstep(window, observed) {
562
+ const predicted = this.forecast(window);
563
+ const p = [predicted.cpu, predicted.memory, predicted.io];
564
+ let squared = 0;
565
+ for (let f = 0; f < this.#features; f += 1) {
566
+ const err = (observed[f] ?? 0) - p[f];
567
+ squared += err * err;
568
+ for (let i = 0; i < this.#size; i += 1) {
569
+ this.#head[f * this.#size + i] += 0.05 * err * this.#hidden[i];
570
+ }
571
+ }
572
+ return Math.sqrt(squared / this.#features);
573
+ }
574
+ /** resets the rolling state between unrelated series. */
575
+ reset() {
576
+ this.#hidden = new Float64Array(this.#size);
577
+ this.#cell = new Float64Array(this.#size);
578
+ }
579
+ }
580
+ _a = psilstm;
581
+ /** tier table: weights follow the 1-10000 cgroups v2 kernel range. */
582
+ const tiertable = {
583
+ gold: { weight: 10000, boost: 2, cpus: 8 },
584
+ silver: { weight: 2500, boost: 1.25, cpus: 4 },
585
+ bronze: { weight: 100, boost: 1, cpus: 2 },
586
+ };
587
+ /**
588
+ * compiles a gold/silver/bronze tier onto the mttg cgroups v2 builders
589
+ * of virtualization.ts: the tier maps through tenantqosmap (gold to
590
+ * guaranteed, silver to burstable, bronze to besteffort), the writes
591
+ * come from tenantcgroupbuilder.planwrites() and the cpu.max line from
592
+ * cpumaxqos(); the notes carry the EEVDF, BORE and sched_ext facts the
593
+ * kernel applies under each policy. mttg itself stays in
594
+ * virtualization.ts; this module only references it.
595
+ */
596
+ export function tenantqosprofile(tier, memMaxMb = 2048) {
597
+ const entry = tiertable[tier];
598
+ const builder = new tenantcgroupbuilder(`tenant-${tier}`)
599
+ .withqos(tenantqosmap[tier])
600
+ .withweight(entry.weight)
601
+ .withcpus(Array.from({ length: entry.cpus }, (_, i) => i))
602
+ .withmemmax(memMaxMb);
603
+ return {
604
+ tier,
605
+ cgroupwrites: builder.planwrites(),
606
+ cpumax: cpumaxqos(tenantqosmap[tier], entry.cpus),
607
+ weight: entry.weight,
608
+ timesliceboost: entry.boost,
609
+ notes: [eevdfinfo(), boreinfo(), schedextinfo()],
610
+ };
611
+ }
612
+ /**
613
+ * tier-aware admission queue: submissions dequeue gold first, silver
614
+ * second and bronze last; when the psilstm forecast crosses the
615
+ * pressure threshold (any stall above 0.6) bronze submissions wait for
616
+ * one drain cycle, the degradation ladder the tenant QoS layer
617
+ * prescribes. the queue never rejects work, it only reorders and
618
+ * defers, so no request is ever lost.
619
+ */
620
+ export class tenantadmission {
621
+ #queue = [];
622
+ #forecast = { cpu: 0, memory: 0, io: 0 };
623
+ submit(request) {
624
+ this.#queue.push(request);
625
+ return this.#queue.length;
626
+ }
627
+ /** feeds the latest lstm forecast; true when degraded. */
628
+ observepressure(forecast) {
629
+ this.#forecast = forecast;
630
+ return Math.max(forecast.cpu, forecast.memory, forecast.io) > 0.6;
631
+ }
632
+ /** dequeues in tier order; bronze defers under sustained pressure. */
633
+ admit() {
634
+ const degraded = Math.max(this.#forecast.cpu, this.#forecast.memory, this.#forecast.io) > 0.6;
635
+ for (const tier of ['gold', 'silver', 'bronze']) {
636
+ // bronze defers under pressure while higher tiers wait; the some()
637
+ // guard prevents starvation when bronze is the only queued tenant.
638
+ // the loop is the whole decision: when every eligible tier is empty
639
+ // (or bronze alone is deferred) admit returns undefined so the
640
+ // caller observes the deferral instead of silently draining head.
641
+ if (tier === 'bronze' && degraded && this.#queue.some((r) => r.tier !== 'bronze')) {
642
+ continue;
643
+ }
644
+ const index = this.#queue.findIndex((r) => r.tier === tier);
645
+ if (index >= 0)
646
+ return this.#queue.splice(index, 1)[0];
647
+ }
648
+ return undefined;
649
+ }
650
+ get pending() {
651
+ return this.#queue.length;
652
+ }
653
+ }
654
+ /**
655
+ * statistical anomaly detector following the OTel OBI pattern: each
656
+ * series keeps an exponentially weighted mean and variance (alpha
657
+ * 0.3), a value is anomalous when its z-score exceeds the 3.5
658
+ * iglewicz-hoaglin band, and findings serialize as OTLP JSON log
659
+ * records so any collector ingests them without an SDK dependency.
660
+ */
661
+ export class anomalydetector {
662
+ #stats = new Map();
663
+ #records = [];
664
+ observe(series, value) {
665
+ const alpha = 0.3;
666
+ const state = this.#stats.get(series) ?? { mean: value, variance: 1e-6, initialized: false };
667
+ if (!state.initialized) {
668
+ /* first observation only seeds the baseline; nothing to compare. */
669
+ state.initialized = true;
670
+ this.#stats.set(series, state);
671
+ return null;
672
+ }
673
+ /* the z-score is tested against the prior baseline before the new
674
+ * value is absorbed, otherwise the anomaly inflates its own sd. */
675
+ const priormean = state.mean;
676
+ const priorsd = Math.sqrt(Math.max(state.variance, 1e-9));
677
+ const zscore = (value - priormean) / priorsd;
678
+ const delta = value - state.mean;
679
+ state.mean += alpha * delta;
680
+ state.variance = (1 - alpha) * (state.variance + alpha * delta * delta);
681
+ this.#stats.set(series, state);
682
+ if (Math.abs(zscore) <= 3.5)
683
+ return null;
684
+ const record = {
685
+ series,
686
+ value,
687
+ zscore: Number(zscore.toFixed(3)),
688
+ ewma: Number(priormean.toFixed(4)),
689
+ severity: Math.abs(zscore) > 5 ? 'critical' : 'warning',
690
+ ts: new Date().toISOString(),
691
+ };
692
+ this.#records.push(record);
693
+ if (this.#records.length > 256)
694
+ this.#records.shift();
695
+ return record;
696
+ }
697
+ /** OTLP JSON log-records payload for the otlp exporter protocol. */
698
+ exportotlp() {
699
+ return {
700
+ resourceLogs: [
701
+ {
702
+ resource: {
703
+ attributes: [{ key: 'service.name', value: { stringValue: 'saddle-scheduler' } }],
704
+ },
705
+ scopeLogs: [
706
+ {
707
+ scope: { name: 'anomalydetector.obi' },
708
+ logRecords: this.#records.map((r) => ({
709
+ timeUnixNano: `${Date.parse(r.ts) * 1e6}`,
710
+ severityText: r.severity,
711
+ body: {
712
+ stringValue: `series=${r.series} value=${r.value} z=${r.zscore} ewma=${r.ewma}`,
713
+ },
714
+ })),
715
+ },
716
+ ],
717
+ },
718
+ ],
719
+ };
720
+ }
721
+ get count() {
722
+ return this.#records.length;
723
+ }
724
+ }
725
+ /* ------------------------------------------------------------------ */
726
+ /* context: hotreload (spec fragment reload bus) */
727
+ /* ------------------------------------------------------------------ */
728
+ /**
729
+ * watches spec fragments (cpu, gpu, memory, network json documents)
730
+ * and emits hashed reload events only when the content actually
731
+ * changed; the poll loop swallows reader failures so a broken fragment
732
+ * never kills the watcher.
733
+ */
734
+ export class spechotreload extends EventEmitter {
735
+ #hashes = new Map();
736
+ #timer = null;
737
+ track(specName, content) {
738
+ const hash = digest(content);
739
+ const previous = this.#hashes.get(specName);
740
+ this.#hashes.set(specName, hash);
741
+ if (previous !== undefined && previous !== hash) {
742
+ this.emit('reload', { specName, hash });
743
+ return true;
744
+ }
745
+ return false;
746
+ }
747
+ /** starts a poll loop; safe to call repeatedly, stops via dispose. */
748
+ startpolling(pollMs, readspecs) {
749
+ this.stoppolling();
750
+ this.#timer = setInterval(() => {
751
+ try {
752
+ for (const [name, content] of readspecs())
753
+ this.track(name, content);
754
+ }
755
+ catch {
756
+ /* catcher: a reader failure must not kill the poll loop */
757
+ }
758
+ }, pollMs);
759
+ this.#timer.unref?.();
760
+ }
761
+ stoppolling() {
762
+ if (this.#timer !== null) {
763
+ clearInterval(this.#timer);
764
+ this.#timer = null;
765
+ }
766
+ }
767
+ [Symbol.dispose]() {
768
+ this.stoppolling();
769
+ this.removeAllListeners();
770
+ }
771
+ }
772
+ /**
773
+ * counters, gauges and histograms with OTLP-shaped export so the
774
+ * scheduler plugs into any OpenTelemetry collector without a dependency
775
+ * on the SDK; histograms collapse to sum plus count until explicit
776
+ * bucket boundaries are wired.
777
+ */
778
+ export class otelmetricsbridge {
779
+ #points = new Map();
780
+ #key(name, attributes) {
781
+ return `${name}|${JSON.stringify(attributes ?? {})}`;
782
+ }
783
+ counter(name, delta = 1, attributes) {
784
+ const key = this.#key(name, attributes);
785
+ const current = this.#points.get(key);
786
+ this.#points.set(key, {
787
+ name,
788
+ kind: 'counter',
789
+ value: (current?.kind === 'counter' ? current.value : 0) + delta,
790
+ attributes,
791
+ });
792
+ }
793
+ gauge(name, value, attributes) {
794
+ this.#points.set(this.#key(name, attributes), { name, kind: 'gauge', value, attributes });
795
+ }
796
+ histogram(name, value, attributes) {
797
+ const key = this.#key(name, attributes);
798
+ const current = this.#points.get(key);
799
+ this.#points.set(key, {
800
+ name,
801
+ kind: 'histogram',
802
+ value: (current?.kind === 'histogram' ? current.value : 0) + value,
803
+ attributes,
804
+ });
805
+ }
806
+ export() {
807
+ return {
808
+ resource: { 'service.name': 'saddle-scheduler' },
809
+ scopeMetrics: { scope: { name: 'saddle.scheduler' }, metrics: [...this.#points.values()] },
810
+ };
811
+ }
812
+ }
813
+ /**
814
+ * liveness and readiness probes with per-check timeouts; a failing
815
+ * check never propagates, it only marks the aggregate status.
816
+ */
817
+ export class healthcheckregistry {
818
+ #checks = new Map();
819
+ register(name, kind, fn) {
820
+ this.#checks.set(name, { kind, fn });
821
+ return this;
822
+ }
823
+ async run(kind, timeoutMs = 1000) {
824
+ const checks = [];
825
+ for (const [name, check] of this.#checks) {
826
+ if (check.kind !== kind)
827
+ continue;
828
+ const startedAt = Date.now();
829
+ let ok = true;
830
+ try {
831
+ await Promise.race([
832
+ Promise.resolve(check.fn()),
833
+ new Promise((_resolve, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs)),
834
+ ]);
835
+ }
836
+ catch {
837
+ ok = false;
838
+ }
839
+ checks.push({ name, ok, durationMs: Date.now() - startedAt });
840
+ }
841
+ return { status: checks.every((c) => c.ok) ? 'pass' : 'fail', checks };
842
+ }
843
+ }
844
+ /**
845
+ * runs shutdown tasks in LIFO order under a global deadline, the
846
+ * sequence expected by SIGTERM-driven orchestrators (systemd,
847
+ * kubernetes, fly machines); repeated arm calls are no-ops and a task
848
+ * failure skips the task, never the chain.
849
+ */
850
+ export class gracefulshutdown {
851
+ #tasks = [];
852
+ #shuttingdown = false;
853
+ add(task) {
854
+ this.#tasks.push(task);
855
+ return this;
856
+ }
857
+ /** wires SIGTERM/SIGINT once. */
858
+ arm(timeoutMs = 10_000) {
859
+ const handler = () => {
860
+ void this.shutdown('signal', timeoutMs);
861
+ };
862
+ process.once('SIGTERM', handler);
863
+ process.once('SIGINT', handler);
864
+ }
865
+ async shutdown(reason, timeoutMs = 10_000) {
866
+ this.#shuttingdown = true;
867
+ const completed = [];
868
+ const skipped = [];
869
+ const deadline = Date.now() + timeoutMs;
870
+ for (const task of this.#tasks.reverse()) {
871
+ if (Date.now() >= deadline) {
872
+ skipped.push(task.name);
873
+ continue;
874
+ }
875
+ try {
876
+ await Promise.race([
877
+ task.run(),
878
+ new Promise((_resolve, reject) => setTimeout(() => reject(new Error(`task ${task.name} timed out`)), task.timeoutMs)),
879
+ ]);
880
+ completed.push(task.name);
881
+ }
882
+ catch {
883
+ skipped.push(task.name);
884
+ }
885
+ }
886
+ this.#tasks = [];
887
+ this.#shuttingdown = false;
888
+ return { reason, completed, skipped };
889
+ }
890
+ get inprogress() {
891
+ return this.#shuttingdown;
892
+ }
893
+ }
894
+ /**
895
+ * typed lifecycle hooks (tenant create/admit, allocation change, spec
896
+ * reload, telemetry) with isolated failure handling: one plugin error
897
+ * never aborts the chain, it only counts as a failed handler.
898
+ */
899
+ export class pluginhooksystem {
900
+ #handlers = new Map();
901
+ on(event, handler) {
902
+ const set = this.#handlers.get(event) ?? new Set();
903
+ set.add(handler);
904
+ this.#handlers.set(event, set);
905
+ return this;
906
+ }
907
+ async emit(event, payload) {
908
+ let handled = 0;
909
+ let failed = 0;
910
+ for (const handler of this.#handlers.get(event) ?? []) {
911
+ try {
912
+ await handler(payload);
913
+ handled += 1;
914
+ }
915
+ catch {
916
+ failed += 1;
917
+ }
918
+ }
919
+ return { handled, failed };
920
+ }
921
+ [Symbol.dispose]() {
922
+ this.#handlers.clear();
923
+ }
924
+ }
925
+ /**
926
+ * the scheduling-domain ledger: fourteen features absorbed from the
927
+ * removed future.ts (ts7 020-022, hardware allocation 039-044,
928
+ * developer experience 051-055) plus four omnihypercore additions. the
929
+ * checkpoint family (028-032) moved to virtualization.ts, the
930
+ * post-quantum family (023-027) to security.ts and the remaining
931
+ * twenty-five compute-oriented features to compute.ts.
932
+ */
933
+ export const schedulerfeatureindex = [
934
+ {
935
+ id: '020',
936
+ origin: 'future.ts',
937
+ name: 'parallel typecheck shards',
938
+ exportname: 'plantypecheckshards',
939
+ },
940
+ { id: '021', origin: 'future.ts', name: 'shared-memory cache', exportname: 'sharedmemorycache' },
941
+ { id: '022', origin: 'future.ts', name: 'incremental project graph', exportname: 'projectgraph' },
942
+ { id: '039', origin: 'future.ts', name: 'MIG slicing profiles', exportname: 'planmiglayout' },
943
+ { id: '040', origin: 'future.ts', name: 'vCPU hotplug 1-192', exportname: 'vcpuhotplug' },
944
+ { id: '041', origin: 'future.ts', name: 'RAM hotplug 1-1024GB', exportname: 'ramhotplug' },
945
+ { id: '042', origin: 'future.ts', name: 'multi-GPU composition', exportname: 'plancomposition' },
946
+ {
947
+ id: '043',
948
+ origin: 'future.ts',
949
+ name: 'NUMA layout with distances',
950
+ exportname: 'planumalayout',
951
+ },
952
+ {
953
+ id: '044',
954
+ origin: 'future.ts',
955
+ name: 'PCI device model registry',
956
+ exportname: 'devicemodelregistry',
957
+ },
958
+ { id: '051', origin: 'future.ts', name: 'spec hot reload bus', exportname: 'spechotreload' },
959
+ {
960
+ id: '052',
961
+ origin: 'future.ts',
962
+ name: 'OpenTelemetry metrics bridge',
963
+ exportname: 'otelmetricsbridge',
964
+ },
965
+ {
966
+ id: '053',
967
+ origin: 'future.ts',
968
+ name: 'health check registry',
969
+ exportname: 'healthcheckregistry',
970
+ },
971
+ { id: '054', origin: 'future.ts', name: 'graceful shutdown', exportname: 'gracefulshutdown' },
972
+ { id: '055', origin: 'future.ts', name: 'plugin hook system', exportname: 'pluginhooksystem' },
973
+ {
974
+ id: 'n56',
975
+ origin: 'omnihypercore-v3',
976
+ name: 'aipsched micro-scheduler',
977
+ exportname: 'aipsched',
978
+ },
979
+ {
980
+ id: 'n57',
981
+ origin: 'omnihypercore-v3',
982
+ name: 'psi LSTM pressure predictor',
983
+ exportname: 'psilstm',
984
+ },
985
+ {
986
+ id: 'n58',
987
+ origin: 'omnihypercore-v3',
988
+ name: 'tenant QoS gold/silver/bronze',
989
+ exportname: 'tenantqosprofile',
990
+ },
991
+ {
992
+ id: 'n59',
993
+ origin: 'omnihypercore-v3',
994
+ name: 'OTel OBI anomaly detector',
995
+ exportname: 'anomalydetector',
996
+ },
997
+ ];
998
+ /** returns the ledger count split by origin. */
999
+ export function schedulerfeaturecount() {
1000
+ const absorbed = schedulerfeatureindex.filter((f) => f.origin === 'future.ts').length;
1001
+ return {
1002
+ total: schedulerfeatureindex.length,
1003
+ absorbed,
1004
+ added: schedulerfeatureindex.length - absorbed,
1005
+ };
1006
+ }
1007
+ /** version anchors of the scheduling domain (worklog v3-VERIFY). */
1008
+ export const schedulerversions = {
1009
+ kernelmainline: '7.2',
1010
+ kernelstable: '7.1.9',
1011
+ kernellongterm: '6.18.45',
1012
+ eevdfsince: '6.6',
1013
+ schedextsince: '6.12',
1014
+ hostparallelism: `${availableParallelism?.() ?? 1}`,
1015
+ };
1016
+ /**
1017
+ * the reinforcement-learning autoscaler policy (ledger F-053): a
1018
+ * functional epsilon-greedy k-armed bandit over four scaling arms
1019
+ * (hold, +1, +2, -1 replicas). rewards are the negated absolute error
1020
+ * between the achieved load and the target load after an arm fires, so
1021
+ * maximizing reward equals minimizing oscillation around the setpoint.
1022
+ * action values update with an incremental mean, epsilon decays toward
1023
+ * a floor as confidence grows, and replica counts are clamped to the
1024
+ * configured bounds; no external stable-baselines3 dependency is
1025
+ * needed because the bandit is the part of RL that matters here.
1026
+ */
1027
+ export class rlautoscaler {
1028
+ #q = new Map();
1029
+ #arms;
1030
+ #floor;
1031
+ #decay;
1032
+ #epsilon;
1033
+ #replicas;
1034
+ #lastarm;
1035
+ constructor(opts = {}) {
1036
+ try {
1037
+ this.#replicas = opts.replicas ?? 2;
1038
+ this.#decay = opts.decay ?? 0.98;
1039
+ this.#epsilon = opts.epsilon ?? 0.2;
1040
+ if (!Number.isInteger(this.#replicas) || this.#replicas < 1 || this.#replicas > 4096) {
1041
+ throw new Error('replicas must be an integer 1..4096');
1042
+ }
1043
+ if (this.#epsilon < 0 || this.#epsilon > 1)
1044
+ throw new Error('epsilon must be 0..1');
1045
+ this.#floor = Math.min(opts.epsilonfloor ?? 0.05, this.#epsilon);
1046
+ if (this.#floor < 0)
1047
+ throw new Error('epsilon floor must be >= 0');
1048
+ if (this.#decay <= 0 || this.#decay >= 1)
1049
+ throw new Error('decay must be in (0,1)');
1050
+ const min = opts.minreplicas ?? 1;
1051
+ const max = opts.maxreplicas ?? 64;
1052
+ if (min < 1 || max < min)
1053
+ throw new Error('max replicas must be >= min replicas >= 1');
1054
+ this.#arms = ['hold', 'up1', 'up2', 'down1'];
1055
+ for (const arm of this.#arms)
1056
+ this.#q.set(arm, { value: 0, count: 0 });
1057
+ }
1058
+ catch (error) {
1059
+ throw new Error(`rlautoscaler init failed: ${error instanceof Error ? error.message : String(error)}`);
1060
+ }
1061
+ }
1062
+ /** current replica count after the last applied decision. */
1063
+ get replicas() {
1064
+ return this.#replicas;
1065
+ }
1066
+ /** current exploration rate (decays toward the floor). */
1067
+ get epsilon() {
1068
+ return Number(this.#epsilon.toFixed(4));
1069
+ }
1070
+ /** selects the next arm: explore with probability epsilon, else greedy. */
1071
+ decide(targetload, observedload) {
1072
+ try {
1073
+ if (targetload <= 0 || targetload > 1)
1074
+ throw new Error('target load must be in (0,1]');
1075
+ if (observedload < 0 || observedload > 1)
1076
+ throw new Error('observed load must be in [0,1]');
1077
+ const explore = Math.random() < this.#epsilon;
1078
+ const best = [...this.#q.entries()].sort((a, b) => b[1].value - a[1].value)[0][0];
1079
+ const arm = explore
1080
+ ? this.#arms[Math.floor(Math.random() * this.#arms.length)]
1081
+ : best;
1082
+ this.#lastarm = arm;
1083
+ if (arm === 'up1')
1084
+ this.#replicas += 1;
1085
+ else if (arm === 'up2')
1086
+ this.#replicas += 2;
1087
+ else if (arm === 'down1')
1088
+ this.#replicas = Math.max(1, this.#replicas - 1);
1089
+ return {
1090
+ arm,
1091
+ explored: explore,
1092
+ epsilon: this.epsilon,
1093
+ expectedreward: Number((this.#q.get(arm)?.value ?? 0).toFixed(4)),
1094
+ replicas: this.#replicas,
1095
+ };
1096
+ }
1097
+ catch (error) {
1098
+ throw new Error(`rlautoscaler.decide failed: ${error instanceof Error ? error.message : String(error)}`);
1099
+ }
1100
+ }
1101
+ /**
1102
+ * feeds the post-decision load back: reward is minus the distance to
1103
+ * the target (so 0 is perfect), the arm's value updates by
1104
+ * incremental mean and epsilon decays one step toward the floor.
1105
+ */
1106
+ feedback(targetload, observedload) {
1107
+ try {
1108
+ const arm = this.#lastarm;
1109
+ if (arm === undefined)
1110
+ throw new Error('no decision to reward yet');
1111
+ if (observedload < 0 || observedload > 1)
1112
+ throw new Error('observed load must be in [0,1]');
1113
+ if (targetload <= 0 || targetload > 1)
1114
+ throw new Error('target load must be in (0,1]');
1115
+ const reward = -Math.abs(observedload - targetload);
1116
+ const slot = this.#q.get(arm);
1117
+ if (slot === undefined)
1118
+ throw new Error(`unknown arm ${arm}`);
1119
+ slot.count += 1;
1120
+ slot.value += (reward - slot.value) / slot.count;
1121
+ this.#epsilon = Math.max(this.#floor, this.#epsilon * this.#decay);
1122
+ this.#lastarm = undefined;
1123
+ return Number(reward.toFixed(4));
1124
+ }
1125
+ catch (error) {
1126
+ throw new Error(`rlautoscaler.feedback failed: ${error instanceof Error ? error.message : String(error)}`);
1127
+ }
1128
+ }
1129
+ }
1130
+ /**
1131
+ * the distributed vm.config document CRDT (ledger F-063): a minimal
1132
+ * last-writer-wins element-register map in the Automerge/Yjs spirit
1133
+ * with zero dependencies. every field carries a site id plus a hybrid
1134
+ * logical clock (wall clock in ms, monotonic counter, lexicographic
1135
+ * site tiebreak) so concurrent edits converge deterministically on all
1136
+ * replicas; merge is commutative, associative and idempotent, and
1137
+ * todocument reassembles the converged vm.config object. the generic
1138
+ * key-value transport used to ship deltas between peers lives in
1139
+ * compute.ts (statevectorsync); this class owns the document shape.
1140
+ */
1141
+ export class vmconfigcrdt {
1142
+ #store = new Map();
1143
+ #site;
1144
+ #lastms = 0;
1145
+ #counter = 0;
1146
+ constructor(site) {
1147
+ try {
1148
+ if (!/^[a-z][a-z0-9-]*$/.test(site)) {
1149
+ throw new Error('site id must be lowercase alnum/dash');
1150
+ }
1151
+ this.#site = site;
1152
+ }
1153
+ catch (error) {
1154
+ throw new Error(`vmconfigcrdt init failed: ${error instanceof Error ? error.message : String(error)}`);
1155
+ }
1156
+ }
1157
+ /** site id of this replica. */
1158
+ get site() {
1159
+ return this.#site;
1160
+ }
1161
+ /**
1162
+ * writes one field with a fresh hybrid logical clock: the wall clock
1163
+ * dominates, the counter breaks same-millisecond ties, the site id
1164
+ * breaks identical clocks (deterministic across replicas).
1165
+ */
1166
+ set(key, value) {
1167
+ try {
1168
+ if (!/^[a-z][a-z0-9.]*$/.test(key)) {
1169
+ throw new Error(`key ${key} must be lowercase alnum/dot (vm.config sections)`);
1170
+ }
1171
+ if (value.length > 4096)
1172
+ throw new Error('value exceeds the 4 KB field budget');
1173
+ const now = Date.now();
1174
+ this.#counter = now === this.#lastms ? this.#counter + 1 : 0;
1175
+ this.#lastms = now;
1176
+ const entry = {
1177
+ key,
1178
+ value,
1179
+ site: this.#site,
1180
+ wallms: now,
1181
+ counter: this.#counter,
1182
+ };
1183
+ const current = this.#store.get(key);
1184
+ if (current === undefined || wins(entry, current))
1185
+ this.#store.set(key, entry);
1186
+ return entry;
1187
+ }
1188
+ catch (error) {
1189
+ throw new Error(`vmconfigcrdt.set failed: ${error instanceof Error ? error.message : String(error)}`);
1190
+ }
1191
+ }
1192
+ /** reads one converged field (undefined when absent). */
1193
+ get(key) {
1194
+ return this.#store.get(key);
1195
+ }
1196
+ /** the full delta set a remote peer needs (all entries). */
1197
+ snapshot() {
1198
+ return [...this.#store.values()];
1199
+ }
1200
+ /**
1201
+ * applies remote entries with last-writer-wins semantics and reports
1202
+ * whether both replicas now hold the identical store (convergence).
1203
+ */
1204
+ merge(remote, remotesite) {
1205
+ try {
1206
+ let applied = 0;
1207
+ let keptlocal = 0;
1208
+ for (const entry of remote) {
1209
+ const current = this.#store.get(entry.key);
1210
+ if (current === undefined || wins(entry, current)) {
1211
+ this.#store.set(entry.key, entry);
1212
+ applied += 1;
1213
+ }
1214
+ else {
1215
+ keptlocal += 1;
1216
+ }
1217
+ }
1218
+ const converged = remotesite === undefined
1219
+ ? true
1220
+ : this.#samekeys(remotesite) &&
1221
+ [...this.#store.values()].every((local) => {
1222
+ const remoteentry = remotesite.get(local.key);
1223
+ return remoteentry !== undefined && remoteentry.value === local.value;
1224
+ });
1225
+ return { applied, keptlocal, converged };
1226
+ }
1227
+ catch (error) {
1228
+ throw new Error(`vmconfigcrdt.merge failed: ${error instanceof Error ? error.message : String(error)}`);
1229
+ }
1230
+ }
1231
+ /**
1232
+ * reassembles the converged vm.config document as a plain record,
1233
+ * ready for JSON.stringify (the distributed vm.config.json itself).
1234
+ */
1235
+ todocument() {
1236
+ const doc = {};
1237
+ for (const [key, entry] of this.#store)
1238
+ doc[key] = entry.value;
1239
+ return doc;
1240
+ }
1241
+ #samekeys(other) {
1242
+ if (other.#store.size !== this.#store.size)
1243
+ return false;
1244
+ for (const key of this.#store.keys()) {
1245
+ if (!other.#store.has(key))
1246
+ return false;
1247
+ }
1248
+ return true;
1249
+ }
1250
+ }
1251
+ /** true when candidate beats incumbent under the hlc ordering rule. */
1252
+ function wins(candidate, incumbent) {
1253
+ if (candidate.wallms !== incumbent.wallms)
1254
+ return candidate.wallms > incumbent.wallms;
1255
+ if (candidate.counter !== incumbent.counter)
1256
+ return candidate.counter > incumbent.counter;
1257
+ return candidate.site > incumbent.site;
1258
+ }
1259
+ //# sourceMappingURL=scheduler.js.map