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