@elaraai/e3-rack 0.0.0-bootstrap.0 → 1.0.94

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 (306) hide show
  1. package/README.md +407 -2
  2. package/dist/src/client/client.spec.d.ts +6 -0
  3. package/dist/src/client/client.spec.d.ts.map +1 -0
  4. package/dist/src/client/client.spec.js +150 -0
  5. package/dist/src/client/client.spec.js.map +1 -0
  6. package/dist/src/client/connect.d.ts +52 -0
  7. package/dist/src/client/connect.d.ts.map +1 -0
  8. package/dist/src/client/connect.js +112 -0
  9. package/dist/src/client/connect.js.map +1 -0
  10. package/dist/src/client/hub-client.d.ts +57 -0
  11. package/dist/src/client/hub-client.d.ts.map +1 -0
  12. package/dist/src/client/hub-client.js +87 -0
  13. package/dist/src/client/hub-client.js.map +1 -0
  14. package/dist/src/client/local-http.d.ts +78 -0
  15. package/dist/src/client/local-http.d.ts.map +1 -0
  16. package/dist/src/client/local-http.js +149 -0
  17. package/dist/src/client/local-http.js.map +1 -0
  18. package/dist/src/client/session-attempts.d.ts +20 -0
  19. package/dist/src/client/session-attempts.d.ts.map +1 -0
  20. package/dist/src/client/session-attempts.js +88 -0
  21. package/dist/src/client/session-attempts.js.map +1 -0
  22. package/dist/src/client/session-data-server.d.ts +37 -0
  23. package/dist/src/client/session-data-server.d.ts.map +1 -0
  24. package/dist/src/client/session-data-server.js +280 -0
  25. package/dist/src/client/session-data-server.js.map +1 -0
  26. package/dist/src/client/session-data-server.spec.d.ts +6 -0
  27. package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
  28. package/dist/src/client/session-data-server.spec.js +192 -0
  29. package/dist/src/client/session-data-server.spec.js.map +1 -0
  30. package/dist/src/client/session.d.ts +119 -0
  31. package/dist/src/client/session.d.ts.map +1 -0
  32. package/dist/src/client/session.js +290 -0
  33. package/dist/src/client/session.js.map +1 -0
  34. package/dist/src/hub/config.d.ts +74 -0
  35. package/dist/src/hub/config.d.ts.map +1 -0
  36. package/dist/src/hub/config.js +159 -0
  37. package/dist/src/hub/config.js.map +1 -0
  38. package/dist/src/hub/fair-lease-store.d.ts +36 -0
  39. package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
  40. package/dist/src/hub/fair-lease-store.js +73 -0
  41. package/dist/src/hub/fair-lease-store.js.map +1 -0
  42. package/dist/src/hub/hub.d.ts +91 -0
  43. package/dist/src/hub/hub.d.ts.map +1 -0
  44. package/dist/src/hub/hub.js +641 -0
  45. package/dist/src/hub/hub.js.map +1 -0
  46. package/dist/src/hub/hub.spec.d.ts +6 -0
  47. package/dist/src/hub/hub.spec.d.ts.map +1 -0
  48. package/dist/src/hub/hub.spec.js +363 -0
  49. package/dist/src/hub/hub.spec.js.map +1 -0
  50. package/dist/src/hub/infrastructure.spec.d.ts +6 -0
  51. package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
  52. package/dist/src/hub/infrastructure.spec.js +211 -0
  53. package/dist/src/hub/infrastructure.spec.js.map +1 -0
  54. package/dist/src/hub/lock.d.ts +62 -0
  55. package/dist/src/hub/lock.d.ts.map +1 -0
  56. package/dist/src/hub/lock.js +165 -0
  57. package/dist/src/hub/lock.js.map +1 -0
  58. package/dist/src/hub/main.d.ts +16 -0
  59. package/dist/src/hub/main.d.ts.map +1 -0
  60. package/dist/src/hub/main.js +56 -0
  61. package/dist/src/hub/main.js.map +1 -0
  62. package/dist/src/hub/session-bridge.d.ts +116 -0
  63. package/dist/src/hub/session-bridge.d.ts.map +1 -0
  64. package/dist/src/hub/session-bridge.js +336 -0
  65. package/dist/src/hub/session-bridge.js.map +1 -0
  66. package/dist/src/identity/file-identity-store.d.ts +18 -0
  67. package/dist/src/identity/file-identity-store.d.ts.map +1 -0
  68. package/dist/src/identity/file-identity-store.js +34 -0
  69. package/dist/src/identity/file-identity-store.js.map +1 -0
  70. package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
  71. package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
  72. package/dist/src/identity/file-identity-store.spec.js +59 -0
  73. package/dist/src/identity/file-identity-store.spec.js.map +1 -0
  74. package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
  75. package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
  76. package/dist/src/identity/in-memory-identity-store.js +102 -0
  77. package/dist/src/identity/in-memory-identity-store.js.map +1 -0
  78. package/dist/src/identity/machine-identity.d.ts +134 -0
  79. package/dist/src/identity/machine-identity.d.ts.map +1 -0
  80. package/dist/src/identity/machine-identity.js +65 -0
  81. package/dist/src/identity/machine-identity.js.map +1 -0
  82. package/dist/src/index.d.ts +34 -0
  83. package/dist/src/index.d.ts.map +1 -0
  84. package/dist/src/index.js +34 -0
  85. package/dist/src/index.js.map +1 -0
  86. package/dist/src/lease/closure.d.ts +96 -0
  87. package/dist/src/lease/closure.d.ts.map +1 -0
  88. package/dist/src/lease/closure.js +192 -0
  89. package/dist/src/lease/closure.js.map +1 -0
  90. package/dist/src/lease/closure.spec.d.ts +6 -0
  91. package/dist/src/lease/closure.spec.d.ts.map +1 -0
  92. package/dist/src/lease/closure.spec.js +35 -0
  93. package/dist/src/lease/closure.spec.js.map +1 -0
  94. package/dist/src/lease/coordinator.d.ts +34 -0
  95. package/dist/src/lease/coordinator.d.ts.map +1 -0
  96. package/dist/src/lease/coordinator.js +42 -0
  97. package/dist/src/lease/coordinator.js.map +1 -0
  98. package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
  99. package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
  100. package/dist/src/lease/in-memory-lease-store.js +132 -0
  101. package/dist/src/lease/in-memory-lease-store.js.map +1 -0
  102. package/dist/src/lease/lease-store.d.ts +169 -0
  103. package/dist/src/lease/lease-store.d.ts.map +1 -0
  104. package/dist/src/lease/lease-store.js +94 -0
  105. package/dist/src/lease/lease-store.js.map +1 -0
  106. package/dist/src/lease/lease-store.spec.d.ts +6 -0
  107. package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
  108. package/dist/src/lease/lease-store.spec.js +8 -0
  109. package/dist/src/lease/lease-store.spec.js.map +1 -0
  110. package/dist/src/lease/rack-dispatch.d.ts +105 -0
  111. package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
  112. package/dist/src/lease/rack-dispatch.js +6 -0
  113. package/dist/src/lease/rack-dispatch.js.map +1 -0
  114. package/dist/src/mutation-queue.d.ts +13 -0
  115. package/dist/src/mutation-queue.d.ts.map +1 -0
  116. package/dist/src/mutation-queue.js +17 -0
  117. package/dist/src/mutation-queue.js.map +1 -0
  118. package/dist/src/paths.d.ts +56 -0
  119. package/dist/src/paths.d.ts.map +1 -0
  120. package/dist/src/paths.js +82 -0
  121. package/dist/src/paths.js.map +1 -0
  122. package/dist/src/protocol/control.d.ts +295 -0
  123. package/dist/src/protocol/control.d.ts.map +1 -0
  124. package/dist/src/protocol/control.js +74 -0
  125. package/dist/src/protocol/control.js.map +1 -0
  126. package/dist/src/protocol/index.d.ts +9 -0
  127. package/dist/src/protocol/index.d.ts.map +1 -0
  128. package/dist/src/protocol/index.js +9 -0
  129. package/dist/src/protocol/index.js.map +1 -0
  130. package/dist/src/protocol/rack-wire.d.ts +357 -0
  131. package/dist/src/protocol/rack-wire.d.ts.map +1 -0
  132. package/dist/src/protocol/rack-wire.js +262 -0
  133. package/dist/src/protocol/rack-wire.js.map +1 -0
  134. package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
  135. package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
  136. package/dist/src/protocol/rack-wire.spec.js +14 -0
  137. package/dist/src/protocol/rack-wire.spec.js.map +1 -0
  138. package/dist/src/protocol/registration.d.ts +70 -0
  139. package/dist/src/protocol/registration.d.ts.map +1 -0
  140. package/dist/src/protocol/registration.js +67 -0
  141. package/dist/src/protocol/registration.js.map +1 -0
  142. package/dist/src/protocol/session-data.d.ts +69 -0
  143. package/dist/src/protocol/session-data.d.ts.map +1 -0
  144. package/dist/src/protocol/session-data.js +26 -0
  145. package/dist/src/protocol/session-data.js.map +1 -0
  146. package/dist/src/protocol/task-envelope.d.ts +198 -0
  147. package/dist/src/protocol/task-envelope.d.ts.map +1 -0
  148. package/dist/src/protocol/task-envelope.js +93 -0
  149. package/dist/src/protocol/task-envelope.js.map +1 -0
  150. package/dist/src/protocol/wire-golden.d.ts +8 -0
  151. package/dist/src/protocol/wire-golden.d.ts.map +1 -0
  152. package/dist/src/protocol/wire-golden.js +34 -0
  153. package/dist/src/protocol/wire-golden.js.map +1 -0
  154. package/dist/src/protocol/wire-samples.d.ts +11 -0
  155. package/dist/src/protocol/wire-samples.d.ts.map +1 -0
  156. package/dist/src/protocol/wire-samples.js +52 -0
  157. package/dist/src/protocol/wire-samples.js.map +1 -0
  158. package/dist/src/registry/file-rack-registry.d.ts +68 -0
  159. package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
  160. package/dist/src/registry/file-rack-registry.js +138 -0
  161. package/dist/src/registry/file-rack-registry.js.map +1 -0
  162. package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
  163. package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
  164. package/dist/src/registry/file-rack-registry.spec.js +50 -0
  165. package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
  166. package/dist/src/registry/rack-registry.d.ts +64 -0
  167. package/dist/src/registry/rack-registry.d.ts.map +1 -0
  168. package/dist/src/registry/rack-registry.js +65 -0
  169. package/dist/src/registry/rack-registry.js.map +1 -0
  170. package/dist/src/registry/rack-registry.spec.d.ts +6 -0
  171. package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
  172. package/dist/src/registry/rack-registry.spec.js +8 -0
  173. package/dist/src/registry/rack-registry.spec.js.map +1 -0
  174. package/dist/src/routing/eligibility.d.ts +38 -0
  175. package/dist/src/routing/eligibility.d.ts.map +1 -0
  176. package/dist/src/routing/eligibility.js +78 -0
  177. package/dist/src/routing/eligibility.js.map +1 -0
  178. package/dist/src/routing/host-coupling.d.ts +26 -0
  179. package/dist/src/routing/host-coupling.d.ts.map +1 -0
  180. package/dist/src/routing/host-coupling.js +62 -0
  181. package/dist/src/routing/host-coupling.js.map +1 -0
  182. package/dist/src/routing/policy.d.ts +188 -0
  183. package/dist/src/routing/policy.d.ts.map +1 -0
  184. package/dist/src/routing/policy.js +212 -0
  185. package/dist/src/routing/policy.js.map +1 -0
  186. package/dist/src/routing/routing.spec.d.ts +6 -0
  187. package/dist/src/routing/routing.spec.d.ts.map +1 -0
  188. package/dist/src/routing/routing.spec.js +100 -0
  189. package/dist/src/routing/routing.spec.js.map +1 -0
  190. package/dist/src/routing/tiers.d.ts +22 -0
  191. package/dist/src/routing/tiers.d.ts.map +1 -0
  192. package/dist/src/routing/tiers.js +26 -0
  193. package/dist/src/routing/tiers.js.map +1 -0
  194. package/dist/src/runner/api-server.d.ts +45 -0
  195. package/dist/src/runner/api-server.d.ts.map +1 -0
  196. package/dist/src/runner/api-server.js +21 -0
  197. package/dist/src/runner/api-server.js.map +1 -0
  198. package/dist/src/runner/capacity.d.ts +13 -0
  199. package/dist/src/runner/capacity.d.ts.map +1 -0
  200. package/dist/src/runner/capacity.js +18 -0
  201. package/dist/src/runner/capacity.js.map +1 -0
  202. package/dist/src/runner/rack-body.d.ts +43 -0
  203. package/dist/src/runner/rack-body.d.ts.map +1 -0
  204. package/dist/src/runner/rack-body.js +208 -0
  205. package/dist/src/runner/rack-body.js.map +1 -0
  206. package/dist/src/runner/rack-runner.d.ts +62 -0
  207. package/dist/src/runner/rack-runner.d.ts.map +1 -0
  208. package/dist/src/runner/rack-runner.js +75 -0
  209. package/dist/src/runner/rack-runner.js.map +1 -0
  210. package/dist/src/runner/rack-runner.spec.d.ts +6 -0
  211. package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
  212. package/dist/src/runner/rack-runner.spec.js +302 -0
  213. package/dist/src/runner/rack-runner.spec.js.map +1 -0
  214. package/dist/src/runner/split.spec.d.ts +6 -0
  215. package/dist/src/runner/split.spec.d.ts.map +1 -0
  216. package/dist/src/runner/split.spec.js +188 -0
  217. package/dist/src/runner/split.spec.js.map +1 -0
  218. package/dist/src/runner-event.d.ts +261 -0
  219. package/dist/src/runner-event.d.ts.map +1 -0
  220. package/dist/src/runner-event.js +332 -0
  221. package/dist/src/runner-event.js.map +1 -0
  222. package/dist/src/server/beast2.d.ts +19 -0
  223. package/dist/src/server/beast2.d.ts.map +1 -0
  224. package/dist/src/server/beast2.js +18 -0
  225. package/dist/src/server/beast2.js.map +1 -0
  226. package/dist/src/server/body-limit.d.ts +16 -0
  227. package/dist/src/server/body-limit.d.ts.map +1 -0
  228. package/dist/src/server/body-limit.js +53 -0
  229. package/dist/src/server/body-limit.js.map +1 -0
  230. package/dist/src/server/body-limit.spec.d.ts +2 -0
  231. package/dist/src/server/body-limit.spec.d.ts.map +1 -0
  232. package/dist/src/server/body-limit.spec.js +32 -0
  233. package/dist/src/server/body-limit.spec.js.map +1 -0
  234. package/dist/src/server/bounded.d.ts +16 -0
  235. package/dist/src/server/bounded.d.ts.map +1 -0
  236. package/dist/src/server/bounded.js +39 -0
  237. package/dist/src/server/bounded.js.map +1 -0
  238. package/dist/src/server/dispatch.d.ts +137 -0
  239. package/dist/src/server/dispatch.d.ts.map +1 -0
  240. package/dist/src/server/dispatch.js +267 -0
  241. package/dist/src/server/dispatch.js.map +1 -0
  242. package/dist/src/server/env-publication.d.ts +45 -0
  243. package/dist/src/server/env-publication.d.ts.map +1 -0
  244. package/dist/src/server/env-publication.js +10 -0
  245. package/dist/src/server/env-publication.js.map +1 -0
  246. package/dist/src/server/index.d.ts +16 -0
  247. package/dist/src/server/index.d.ts.map +1 -0
  248. package/dist/src/server/index.js +17 -0
  249. package/dist/src/server/index.js.map +1 -0
  250. package/dist/src/server/protocol.spec.d.ts +6 -0
  251. package/dist/src/server/protocol.spec.d.ts.map +1 -0
  252. package/dist/src/server/protocol.spec.js +78 -0
  253. package/dist/src/server/protocol.spec.js.map +1 -0
  254. package/dist/src/server/rack-routes.d.ts +175 -0
  255. package/dist/src/server/rack-routes.d.ts.map +1 -0
  256. package/dist/src/server/rack-routes.js +755 -0
  257. package/dist/src/server/rack-routes.js.map +1 -0
  258. package/dist/src/server/rack-routes.spec.d.ts +6 -0
  259. package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
  260. package/dist/src/server/rack-routes.spec.js +477 -0
  261. package/dist/src/server/rack-routes.spec.js.map +1 -0
  262. package/dist/src/server/storage-bridge.d.ts +140 -0
  263. package/dist/src/server/storage-bridge.d.ts.map +1 -0
  264. package/dist/src/server/storage-bridge.js +6 -0
  265. package/dist/src/server/storage-bridge.js.map +1 -0
  266. package/dist/src/state-file.d.ts +10 -0
  267. package/dist/src/state-file.d.ts.map +1 -0
  268. package/dist/src/state-file.js +38 -0
  269. package/dist/src/state-file.js.map +1 -0
  270. package/dist/src/testing/in-memory.d.ts +116 -0
  271. package/dist/src/testing/in-memory.d.ts.map +1 -0
  272. package/dist/src/testing/in-memory.js +193 -0
  273. package/dist/src/testing/in-memory.js.map +1 -0
  274. package/dist/src/testing/index.d.ts +14 -0
  275. package/dist/src/testing/index.d.ts.map +1 -0
  276. package/dist/src/testing/index.js +14 -0
  277. package/dist/src/testing/index.js.map +1 -0
  278. package/dist/src/testing/lease-store-contract.d.ts +14 -0
  279. package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
  280. package/dist/src/testing/lease-store-contract.js +78 -0
  281. package/dist/src/testing/lease-store-contract.js.map +1 -0
  282. package/dist/src/testing/protocol-suite.d.ts +38 -0
  283. package/dist/src/testing/protocol-suite.d.ts.map +1 -0
  284. package/dist/src/testing/protocol-suite.js +207 -0
  285. package/dist/src/testing/protocol-suite.js.map +1 -0
  286. package/dist/src/testing/rack-registry-contract.d.ts +15 -0
  287. package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
  288. package/dist/src/testing/rack-registry-contract.js +106 -0
  289. package/dist/src/testing/rack-registry-contract.js.map +1 -0
  290. package/dist/src/testing/test-rack-agent.d.ts +121 -0
  291. package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
  292. package/dist/src/testing/test-rack-agent.js +316 -0
  293. package/dist/src/testing/test-rack-agent.js.map +1 -0
  294. package/dist/src/tls/tls.d.ts +67 -0
  295. package/dist/src/tls/tls.d.ts.map +1 -0
  296. package/dist/src/tls/tls.js +200 -0
  297. package/dist/src/tls/tls.js.map +1 -0
  298. package/dist/src/tls/tls.spec.d.ts +6 -0
  299. package/dist/src/tls/tls.spec.d.ts.map +1 -0
  300. package/dist/src/tls/tls.spec.js +101 -0
  301. package/dist/src/tls/tls.spec.js.map +1 -0
  302. package/dist/src/version.d.ts +9 -0
  303. package/dist/src/version.d.ts.map +1 -0
  304. package/dist/src/version.js +10 -0
  305. package/dist/src/version.js.map +1 -0
  306. package/package.json +67 -7
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { decodeTaskObject } from '@elaraai/e3-types';
6
+ import { selectTask } from './policy.js';
7
+ import { rackTierFor } from './tiers.js';
8
+ import { scanProgram } from './host-coupling.js';
9
+ /**
10
+ * Evaluates routing once per logical task and graph name for a run.
11
+ * The program and output reducer are task-object references, so a merge that
12
+ * arrives before any map (cached maps) receives the same complete scan.
13
+ * @example
14
+ * const eligibility = await new EligibilityEvaluator(policy).evaluate(request);
15
+ */
16
+ export class EligibilityEvaluator {
17
+ policy;
18
+ verdicts = new Map();
19
+ /** @param policy - The policy snapshot for this run */
20
+ constructor(policy) {
21
+ this.policy = policy;
22
+ }
23
+ /**
24
+ * Checks selection, runtime, environment and every executable IR bundle.
25
+ * @param request - A task or split unit after its cache miss
26
+ * @returns Its eligibility, with a deterministic reason on refusal
27
+ */
28
+ evaluate(request) {
29
+ const name = request.options.taskName;
30
+ if (name === undefined)
31
+ return Promise.resolve({ eligible: false, reason: 'no-task-name' });
32
+ const hash = request.logicalTaskHash ?? request.taskHash;
33
+ const key = JSON.stringify([request.repo, hash, name]);
34
+ let result = this.verdicts.get(key);
35
+ if (result === undefined) {
36
+ if (this.verdicts.size >= 4096)
37
+ this.verdicts.clear();
38
+ result = this.check(request, hash, name);
39
+ this.verdicts.set(key, result);
40
+ }
41
+ return result;
42
+ }
43
+ async check(request, logicalHash, name) {
44
+ const selection = selectTask(this.policy, name);
45
+ if (selection.target === 'local')
46
+ return { eligible: false, reason: 'not-selected' };
47
+ try {
48
+ const task = logicalHash === request.taskHash ? request.task : decodeTaskObject(await request.storage.objects.read(request.repo, logicalHash));
49
+ if (task.environment.type === 'some')
50
+ return { eligible: false, reason: 'environment' };
51
+ const tier = rackTierFor(task.runner);
52
+ if ('ineligible' in tier)
53
+ return { eligible: false, reason: tier.ineligible };
54
+ if (task.body.type !== 'east')
55
+ return { eligible: false, reason: 'custom-runner' };
56
+ if (!selection.allowHostCoupled) {
57
+ const programs = [task.body.value.program];
58
+ const output = task.output.kind;
59
+ if (output.type === 'dict' && output.value.merge.type === 'some')
60
+ programs.push(output.value.merge.value);
61
+ if (output.type === 'fold')
62
+ programs.push(output.value.combine);
63
+ const blocked = new Set();
64
+ for (const hash of programs) {
65
+ for (const platform of await scanProgram(hash, () => request.storage.objects.read(request.repo, hash)))
66
+ blocked.add(platform);
67
+ }
68
+ if (blocked.size > 0)
69
+ return { eligible: false, reason: `host-coupled:${[...blocked].sort().join(',')}` };
70
+ }
71
+ return { eligible: true, tier: tier.tier, size: selection.size, timeoutMinutes: selection.timeoutMinutes };
72
+ }
73
+ catch {
74
+ return { eligible: false, reason: 'unscannable' };
75
+ }
76
+ }
77
+ }
78
+ //# sourceMappingURL=eligibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eligibility.js","sourceRoot":"","sources":["../../../src/routing/eligibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAwC,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOjD;;;;;;GAMG;AACH,MAAM,OAAO,oBAAoB;IAIF;IAHZ,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEpE,uDAAuD;IACvD,YAA6B,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAEnD;;;;OAIG;IACH,QAAQ,CAAC,OAAwB;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QAC5F,MAAM,IAAI,GAAG,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,QAAQ,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI;gBAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,OAAwB,EAAE,WAAmB,EAAE,IAAY;QAC7E,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO;YAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACrF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;YAC/I,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;YACxF,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,YAAY,IAAI,IAAI;gBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9E,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;YACnF,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;gBAChC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAChC,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM;oBAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC1G,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;oBAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAChE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,KAAK,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;wBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAChI,CAAC;gBACD,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC;oBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YAC5G,CAAC;YACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,cAAc,EAAE,CAAC;QAC7G,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACpD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /** Platform families that depend on host state or network access. */
6
+ export declare const HOST_COUPLED_PREFIXES: readonly ["fs_", "env_", "sqlite_", "access_", "fetch_", "s3_", "postgres_", "mysql_", "redis_", "mongodb_", "ftp_", "sftp_"];
7
+ /**
8
+ * Collects every called platform name, including nested functions/dead branches.
9
+ * @param bytes - A sync or async East IR envelope
10
+ * @returns Sorted, distinct platform names
11
+ * @throws When neither envelope decodes
12
+ * @example
13
+ * const platforms = collectPlatformNames(await storage.objects.read(repo, program));
14
+ */
15
+ export declare function collectPlatformNames(bytes: Uint8Array): string[];
16
+ /**
17
+ * Selects platform calls whose host dependencies are unavailable in a guest.
18
+ * @param names - The program's platform names
19
+ * @returns Blocked names in input order
20
+ * @example
21
+ * hostCoupledPlatforms(['console_log', 'env_get']); // ['env_get']
22
+ */
23
+ export declare function hostCoupledPlatforms(names: Iterable<string>): string[];
24
+ /** Reads and scans an immutable IR object once per process, bounded to 4096. @internal */
25
+ export declare function scanProgram(hash: string, read: () => Promise<Uint8Array>): Promise<readonly string[]>;
26
+ //# sourceMappingURL=host-coupling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-coupling.d.ts","sourceRoot":"","sources":["../../../src/routing/host-coupling.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,+HAOxB,CAAC;AAKX;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAOhE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAEtE;AAID,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CASrG"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { decodeAsyncEastIR, decodeEastIR, walkIR } from '@elaraai/east';
6
+ /** Platform families that depend on host state or network access. */
7
+ export const HOST_COUPLED_PREFIXES = [
8
+ 'fs_', // Host files and directories.
9
+ 'env_', // Host environment variables and process state.
10
+ 'sqlite_', 'access_', // Local database files.
11
+ 'fetch_', 's3_', // HTTP and object storage.
12
+ 'postgres_', 'mysql_', 'redis_', 'mongodb_', // Network database services.
13
+ 'ftp_', 'sftp_', // Remote files.
14
+ ];
15
+ // These are exact names: json_open_text reads an argument, not a host file.
16
+ const HOST_COUPLED_NAMES = new Set(['json_open', 'json_value', 'path_resolve']);
17
+ /**
18
+ * Collects every called platform name, including nested functions/dead branches.
19
+ * @param bytes - A sync or async East IR envelope
20
+ * @returns Sorted, distinct platform names
21
+ * @throws When neither envelope decodes
22
+ * @example
23
+ * const platforms = collectPlatformNames(await storage.objects.read(repo, program));
24
+ */
25
+ export function collectPlatformNames(bytes) {
26
+ let ir;
27
+ try {
28
+ ir = decodeAsyncEastIR(bytes).ir;
29
+ }
30
+ catch {
31
+ ir = decodeEastIR(bytes).ir;
32
+ }
33
+ const names = new Set();
34
+ walkIR(ir, (node) => { if (node.type === 'Platform')
35
+ names.add(node.value.name); });
36
+ return [...names].sort();
37
+ }
38
+ /**
39
+ * Selects platform calls whose host dependencies are unavailable in a guest.
40
+ * @param names - The program's platform names
41
+ * @returns Blocked names in input order
42
+ * @example
43
+ * hostCoupledPlatforms(['console_log', 'env_get']); // ['env_get']
44
+ */
45
+ export function hostCoupledPlatforms(names) {
46
+ return [...names].filter((name) => HOST_COUPLED_NAMES.has(name) || HOST_COUPLED_PREFIXES.some((prefix) => name.startsWith(prefix)));
47
+ }
48
+ const scans = new Map();
49
+ /** Reads and scans an immutable IR object once per process, bounded to 4096. @internal */
50
+ export function scanProgram(hash, read) {
51
+ let result = scans.get(hash);
52
+ if (result === undefined) {
53
+ if (scans.size >= 4096)
54
+ scans.clear();
55
+ result = read().then((bytes) => hostCoupledPlatforms(collectPlatformNames(bytes)));
56
+ scans.set(hash, result);
57
+ void result.catch(() => { if (scans.get(hash) === result)
58
+ scans.delete(hash); });
59
+ }
60
+ return result;
61
+ }
62
+ //# sourceMappingURL=host-coupling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-coupling.js","sourceRoot":"","sources":["../../../src/routing/host-coupling.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,EAAW,MAAM,eAAe,CAAC;AAEjF,qEAAqE;AACrE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,KAAK,EAAE,8BAA8B;IACrC,MAAM,EAAE,gDAAgD;IACxD,SAAS,EAAE,SAAS,EAAE,wBAAwB;IAC9C,QAAQ,EAAE,KAAK,EAAE,2BAA2B;IAC5C,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,6BAA6B;IAC1E,MAAM,EAAE,OAAO,EAAE,gBAAgB;CACzB,CAAC;AAEX,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAiB;IACpD,IAAI,EAAM,CAAC;IACX,IAAI,CAAC;QAAC,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAmB,CAAC;IAAC,CAAC;IAC1D,MAAM,CAAC;QAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAmB,CAAC;IAAC,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;QAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAuB;IAC1D,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtI,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsC,CAAC;AAE5D,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAA+B;IACvE,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACtC,MAAM,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnF,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM;YAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { ArrayType, BooleanType, IntegerType, NullType, OptionType, StringType, StructType, VariantType, type ValueTypeOf } from '@elaraai/east';
6
+ /** The VM shapes the rack agent supports. */
7
+ export declare const RackComputeSizeType: VariantType<{
8
+ readonly serverless: NullType;
9
+ readonly small: NullType;
10
+ readonly medium: NullType;
11
+ readonly large: NullType;
12
+ readonly xlarge: NullType;
13
+ }>;
14
+ /** A whole-task-name glob and its execution policy; first match wins. */
15
+ export declare const RackRuleType: StructType<{
16
+ readonly tasks: StringType;
17
+ readonly target: VariantType<{
18
+ readonly rack: NullType;
19
+ readonly local: NullType;
20
+ }>;
21
+ readonly size: OptionType<VariantType<{
22
+ readonly serverless: NullType;
23
+ readonly small: NullType;
24
+ readonly medium: NullType;
25
+ readonly large: NullType;
26
+ readonly xlarge: NullType;
27
+ }>>;
28
+ readonly timeoutMinutes: OptionType<IntegerType>;
29
+ readonly allowHostCoupled: BooleanType;
30
+ }>;
31
+ /**
32
+ * Stores this repository's rack opt-in. Runtime policy never affects hashes.
33
+ * This is repository state: a future shape change needs a repository upgrade
34
+ * under WIRE_MIGRATION.md, not a fallback decoder or an in-place widening.
35
+ */
36
+ export declare const RackPolicyType: StructType<{
37
+ readonly enabled: BooleanType;
38
+ readonly mode: VariantType<{
39
+ readonly optIn: NullType;
40
+ readonly auto: NullType;
41
+ }>;
42
+ readonly rules: ArrayType<StructType<{
43
+ readonly tasks: StringType;
44
+ readonly target: VariantType<{
45
+ readonly rack: NullType;
46
+ readonly local: NullType;
47
+ }>;
48
+ readonly size: OptionType<VariantType<{
49
+ readonly serverless: NullType;
50
+ readonly small: NullType;
51
+ readonly medium: NullType;
52
+ readonly large: NullType;
53
+ readonly xlarge: NullType;
54
+ }>>;
55
+ readonly timeoutMinutes: OptionType<IntegerType>;
56
+ readonly allowHostCoupled: BooleanType;
57
+ }>>;
58
+ readonly defaultSize: VariantType<{
59
+ readonly serverless: NullType;
60
+ readonly small: NullType;
61
+ readonly medium: NullType;
62
+ readonly large: NullType;
63
+ readonly xlarge: NullType;
64
+ }>;
65
+ readonly defaultTimeoutMinutes: IntegerType;
66
+ readonly spill: BooleanType;
67
+ readonly claimTimeoutSeconds: IntegerType;
68
+ readonly retryTaskFailuresLocally: BooleanType;
69
+ }>;
70
+ /** A repository's rack policy. */
71
+ export type RackPolicy = ValueTypeOf<typeof RackPolicyType>;
72
+ /** A task's rule. */
73
+ export type RackRule = ValueTypeOf<typeof RackRuleType>;
74
+ /** An agent VM shape. */
75
+ export type RackComputeSize = ValueTypeOf<typeof RackComputeSizeType>['type'];
76
+ /** Conservative defaults: disabled, with explicit task selection required. */
77
+ export declare const DEFAULT_RACK_POLICY: RackPolicy;
78
+ /** Explains a policy that cannot be used; no damaged policy silently delegates. */
79
+ export declare class RackPolicyError extends Error {
80
+ /** @param message - The invalid policy and its remedy */
81
+ constructor(message: string);
82
+ }
83
+ /**
84
+ * Names a repository's runtime rack policy.
85
+ * @param repo - Repository path
86
+ * @returns Its policy path
87
+ * @example
88
+ * const path = policyPath(repo);
89
+ */
90
+ export declare function policyPath(repo: string): string;
91
+ /**
92
+ * Reads the policy, or returns independent defaults when none exists.
93
+ * @param repo - Repository path
94
+ * @returns The policy
95
+ * @throws {RackPolicyError} When the file is invalid, naming its reset command
96
+ * @example
97
+ * const policy = await loadPolicy(repo);
98
+ */
99
+ export declare function loadPolicy(repo: string): Promise<RackPolicy>;
100
+ /**
101
+ * Atomically persists a validated rack policy.
102
+ * @param repo - Repository path
103
+ * @param policy - The new policy
104
+ * @returns Once durable to concurrent readers
105
+ * @example
106
+ * await savePolicy(repo, setEnabled(await loadPolicy(repo), true));
107
+ */
108
+ export declare function savePolicy(repo: string, policy: RackPolicy): Promise<void>;
109
+ /** A task's selected runtime policy, with the winning rule's index. */
110
+ export interface TaskSelection {
111
+ /** Where this task is requested to run. */
112
+ target: 'rack' | 'local';
113
+ /** Rack VM shape. */
114
+ size: RackComputeSize;
115
+ /** Maximum execution time in minutes. */
116
+ timeoutMinutes: number;
117
+ /** Whether the author deliberately overrides the host-access guard. */
118
+ allowHostCoupled: boolean;
119
+ /** First matching rule, or null for policy defaults. */
120
+ ruleIndex: number | null;
121
+ }
122
+ /**
123
+ * Selects the first whole-name matching rule, then policy defaults.
124
+ * @param policy - The run's policy
125
+ * @param taskName - The graph task name
126
+ * @returns Its selection (eligibility is checked separately)
127
+ * @example
128
+ * const selection = selectTask(policy, 'train_model');
129
+ */
130
+ export declare function selectTask(policy: RackPolicy, taskName: string): TaskSelection;
131
+ /** Optional settings applied when replacing or adding a task rule. */
132
+ export interface RuleSettings {
133
+ /** Rack VM shape. */
134
+ size?: RackComputeSize;
135
+ /** Maximum task time in minutes. */
136
+ timeoutMinutes?: number;
137
+ /** Deliberate override of the host-access guard. */
138
+ allowHostCoupled?: boolean;
139
+ }
140
+ /**
141
+ * Replaces a rule in place, or appends it, leaving its input policy unchanged.
142
+ * @param policy - Original policy
143
+ * @param tasks - Whole-name glob
144
+ * @param target - Requested location
145
+ * @param settings - Optional overrides
146
+ * @returns An independent policy
147
+ * @example
148
+ * const next = setRule(policy, 'train_*', 'rack', { size: 'large' });
149
+ */
150
+ export declare function setRule(policy: RackPolicy, tasks: string, target: 'rack' | 'local', settings?: RuleSettings): RackPolicy;
151
+ /**
152
+ * Removes an exact pattern without changing the input policy.
153
+ * @param policy - Original policy
154
+ * @param tasks - Pattern to remove
155
+ * @returns An independent policy
156
+ * @example
157
+ * const next = removeRule(policy, 'train_*');
158
+ */
159
+ export declare function removeRule(policy: RackPolicy, tasks: string): RackPolicy;
160
+ /**
161
+ * Changes whether rack routing is enabled by default.
162
+ * @param policy - Original policy
163
+ * @param enabled - New default
164
+ * @returns An independent policy
165
+ * @example
166
+ * const next = setEnabled(policy, true);
167
+ */
168
+ export declare function setEnabled(policy: RackPolicy, enabled: boolean): RackPolicy;
169
+ /**
170
+ * Changes the unmatched-task selection mode.
171
+ * @param policy - Original policy
172
+ * @param mode - optIn or auto
173
+ * @returns An independent policy
174
+ * @example
175
+ * const next = setMode(policy, 'auto');
176
+ */
177
+ export declare function setMode(policy: RackPolicy, mode: 'optIn' | 'auto'): RackPolicy;
178
+ /**
179
+ * Whether the policy can select any task for a rack: automatic selection of
180
+ * unmatched tasks, or a rule whose target is a rack. A run under a policy
181
+ * that cannot opens no rack session, and waits for no rack.
182
+ * @param policy - The run's policy
183
+ * @returns Whether a task could be routed to a rack
184
+ * @example
185
+ * if (policyTargetsRack(policy)) rack = await openRackRunner(options);
186
+ */
187
+ export declare function policyTargetsRack(policy: RackPolicy): boolean;
188
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/routing/policy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAyD,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAGxM,6CAA6C;AAC7C,eAAO,MAAM,mBAAmB;;;;;;EAA8G,CAAC;AAC/I,yEAAyE;AACzE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;EAMvB,CAAC;AACH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASzB,CAAC;AACH,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,cAAc,CAAC,CAAC;AAC5D,qBAAqB;AACrB,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,yBAAyB;AACzB,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,EAAE,UAGjC,CAAC;AAIF,mFAAmF;AACnF,qBAAa,eAAgB,SAAQ,KAAK;IACxC,yDAAyD;gBAC7C,OAAO,EAAE,MAAM;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAgD;AAoBhG;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAclE;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhF;AAaD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,qBAAqB;IACrB,IAAI,EAAE,eAAe,CAAC;IACtB,yCAAyC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,wDAAwD;IACxD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAU9E;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,qBAAqB;IACrB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,oCAAoC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,GAAE,YAAiB,GAAG,UAAU,CAW5H;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAExE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,CAAmD;AAE/H;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAqE;AAEpJ;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { readFile } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+ import { ArrayType, BooleanType, IntegerType, NullType, OptionType, StringType, StructType, VariantType, decodeBeast2For, encodeBeast2For, none, some, variant } from '@elaraai/east';
8
+ import { atomicWriteFile } from '@elaraai/e3-core';
9
+ /** The VM shapes the rack agent supports. */
10
+ export const RackComputeSizeType = VariantType({ serverless: NullType, small: NullType, medium: NullType, large: NullType, xlarge: NullType });
11
+ /** A whole-task-name glob and its execution policy; first match wins. */
12
+ export const RackRuleType = StructType({
13
+ tasks: StringType,
14
+ target: VariantType({ rack: NullType, local: NullType }),
15
+ size: OptionType(RackComputeSizeType),
16
+ timeoutMinutes: OptionType(IntegerType),
17
+ allowHostCoupled: BooleanType,
18
+ });
19
+ /**
20
+ * Stores this repository's rack opt-in. Runtime policy never affects hashes.
21
+ * This is repository state: a future shape change needs a repository upgrade
22
+ * under WIRE_MIGRATION.md, not a fallback decoder or an in-place widening.
23
+ */
24
+ export const RackPolicyType = StructType({
25
+ enabled: BooleanType,
26
+ mode: VariantType({ optIn: NullType, auto: NullType }),
27
+ rules: ArrayType(RackRuleType),
28
+ defaultSize: RackComputeSizeType,
29
+ defaultTimeoutMinutes: IntegerType,
30
+ spill: BooleanType,
31
+ claimTimeoutSeconds: IntegerType,
32
+ retryTaskFailuresLocally: BooleanType,
33
+ });
34
+ /** Conservative defaults: disabled, with explicit task selection required. */
35
+ export const DEFAULT_RACK_POLICY = {
36
+ enabled: false, mode: variant('optIn', null), rules: [], defaultSize: variant('large', null),
37
+ defaultTimeoutMinutes: 1440n, spill: true, claimTimeoutSeconds: 30n, retryTaskFailuresLocally: false,
38
+ };
39
+ const encode = encodeBeast2For(RackPolicyType);
40
+ const decode = decodeBeast2For(RackPolicyType);
41
+ /** Explains a policy that cannot be used; no damaged policy silently delegates. */
42
+ export class RackPolicyError extends Error {
43
+ /** @param message - The invalid policy and its remedy */
44
+ constructor(message) { super(message); this.name = 'RackPolicyError'; }
45
+ }
46
+ /**
47
+ * Names a repository's runtime rack policy.
48
+ * @param repo - Repository path
49
+ * @returns Its policy path
50
+ * @example
51
+ * const path = policyPath(repo);
52
+ */
53
+ export function policyPath(repo) { return join(repo, 'rack', 'policy.beast2'); }
54
+ function positive(value, field) {
55
+ if (!Number.isSafeInteger(Number(value)) || Number(value) <= 0)
56
+ throw new RackPolicyError(`${field} must be a positive safe integer`);
57
+ }
58
+ function validate(policy) {
59
+ positive(policy.defaultTimeoutMinutes, 'defaultTimeoutMinutes');
60
+ positive(policy.claimTimeoutSeconds, 'claimTimeoutSeconds');
61
+ if (Number(policy.claimTimeoutSeconds) > Number.MAX_SAFE_INTEGER / 1000)
62
+ throw new RackPolicyError('claimTimeoutSeconds is too large');
63
+ if (Number(policy.defaultTimeoutMinutes) > Number.MAX_SAFE_INTEGER / 60_000)
64
+ throw new RackPolicyError('defaultTimeoutMinutes is too large');
65
+ for (const rule of policy.rules) {
66
+ if (rule.tasks.length === 0)
67
+ throw new RackPolicyError('A task pattern cannot be empty');
68
+ if (rule.timeoutMinutes.type === 'some') {
69
+ positive(rule.timeoutMinutes.value, 'timeoutMinutes');
70
+ if (Number(rule.timeoutMinutes.value) > Number.MAX_SAFE_INTEGER / 60_000)
71
+ throw new RackPolicyError('timeoutMinutes is too large');
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Reads the policy, or returns independent defaults when none exists.
77
+ * @param repo - Repository path
78
+ * @returns The policy
79
+ * @throws {RackPolicyError} When the file is invalid, naming its reset command
80
+ * @example
81
+ * const policy = await loadPolicy(repo);
82
+ */
83
+ export async function loadPolicy(repo) {
84
+ const file = policyPath(repo);
85
+ let bytes;
86
+ try {
87
+ bytes = await readFile(file);
88
+ }
89
+ catch (err) {
90
+ if (err.code === 'ENOENT')
91
+ return decode(encode(DEFAULT_RACK_POLICY));
92
+ throw err;
93
+ }
94
+ try {
95
+ const policy = decode(bytes);
96
+ validate(policy);
97
+ return policy;
98
+ }
99
+ catch (err) {
100
+ throw new RackPolicyError(`${file}: ${err instanceof Error ? err.message : String(err)}; use 'e3 rack policy reset' to restore defaults`);
101
+ }
102
+ }
103
+ /**
104
+ * Atomically persists a validated rack policy.
105
+ * @param repo - Repository path
106
+ * @param policy - The new policy
107
+ * @returns Once durable to concurrent readers
108
+ * @example
109
+ * await savePolicy(repo, setEnabled(await loadPolicy(repo), true));
110
+ */
111
+ export async function savePolicy(repo, policy) {
112
+ validate(policy);
113
+ await atomicWriteFile(policyPath(repo), encode(policy));
114
+ }
115
+ const patterns = new Map();
116
+ function pattern(text) {
117
+ let result = patterns.get(text);
118
+ if (result === undefined) {
119
+ result = new RegExp(`^${[...text].map((c) => c === '*' ? '.*' : c === '?' ? '.' : c.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')).join('')}$`, 'u');
120
+ if (patterns.size >= 4096)
121
+ patterns.clear();
122
+ patterns.set(text, result);
123
+ }
124
+ return result;
125
+ }
126
+ /**
127
+ * Selects the first whole-name matching rule, then policy defaults.
128
+ * @param policy - The run's policy
129
+ * @param taskName - The graph task name
130
+ * @returns Its selection (eligibility is checked separately)
131
+ * @example
132
+ * const selection = selectTask(policy, 'train_model');
133
+ */
134
+ export function selectTask(policy, taskName) {
135
+ const index = policy.rules.findIndex((rule) => pattern(rule.tasks).test(taskName));
136
+ const rule = policy.rules[index];
137
+ return {
138
+ target: rule?.target.type ?? (policy.mode.type === 'auto' ? 'rack' : 'local'),
139
+ size: rule?.size.type === 'some' ? rule.size.value.type : policy.defaultSize.type,
140
+ timeoutMinutes: Number(rule?.timeoutMinutes.type === 'some' ? rule.timeoutMinutes.value : policy.defaultTimeoutMinutes),
141
+ allowHostCoupled: rule?.allowHostCoupled ?? false,
142
+ ruleIndex: index < 0 ? null : index,
143
+ };
144
+ }
145
+ /**
146
+ * Replaces a rule in place, or appends it, leaving its input policy unchanged.
147
+ * @param policy - Original policy
148
+ * @param tasks - Whole-name glob
149
+ * @param target - Requested location
150
+ * @param settings - Optional overrides
151
+ * @returns An independent policy
152
+ * @example
153
+ * const next = setRule(policy, 'train_*', 'rack', { size: 'large' });
154
+ */
155
+ export function setRule(policy, tasks, target, settings = {}) {
156
+ const next = decode(encode(policy));
157
+ if (settings.timeoutMinutes !== undefined && (!Number.isSafeInteger(settings.timeoutMinutes) || settings.timeoutMinutes <= 0)) {
158
+ throw new RackPolicyError('timeoutMinutes must be a positive safe integer');
159
+ }
160
+ const rule = { tasks, target: variant(target, null), size: settings.size === undefined ? none : some(variant(settings.size, null)),
161
+ timeoutMinutes: settings.timeoutMinutes === undefined ? none : some(BigInt(settings.timeoutMinutes)), allowHostCoupled: settings.allowHostCoupled ?? false };
162
+ const index = next.rules.findIndex((r) => r.tasks === tasks);
163
+ if (index < 0)
164
+ next.rules.push(rule);
165
+ else
166
+ next.rules[index] = rule;
167
+ validate(next);
168
+ return next;
169
+ }
170
+ /**
171
+ * Removes an exact pattern without changing the input policy.
172
+ * @param policy - Original policy
173
+ * @param tasks - Pattern to remove
174
+ * @returns An independent policy
175
+ * @example
176
+ * const next = removeRule(policy, 'train_*');
177
+ */
178
+ export function removeRule(policy, tasks) {
179
+ const next = decode(encode(policy));
180
+ return { ...next, rules: next.rules.filter((r) => r.tasks !== tasks) };
181
+ }
182
+ /**
183
+ * Changes whether rack routing is enabled by default.
184
+ * @param policy - Original policy
185
+ * @param enabled - New default
186
+ * @returns An independent policy
187
+ * @example
188
+ * const next = setEnabled(policy, true);
189
+ */
190
+ export function setEnabled(policy, enabled) { return { ...decode(encode(policy)), enabled }; }
191
+ /**
192
+ * Changes the unmatched-task selection mode.
193
+ * @param policy - Original policy
194
+ * @param mode - optIn or auto
195
+ * @returns An independent policy
196
+ * @example
197
+ * const next = setMode(policy, 'auto');
198
+ */
199
+ export function setMode(policy, mode) { return { ...decode(encode(policy)), mode: variant(mode, null) }; }
200
+ /**
201
+ * Whether the policy can select any task for a rack: automatic selection of
202
+ * unmatched tasks, or a rule whose target is a rack. A run under a policy
203
+ * that cannot opens no rack session, and waits for no rack.
204
+ * @param policy - The run's policy
205
+ * @returns Whether a task could be routed to a rack
206
+ * @example
207
+ * if (policyTargetsRack(policy)) rack = await openRackRunner(options);
208
+ */
209
+ export function policyTargetsRack(policy) {
210
+ return policy.mode.type === 'auto' || policy.rules.some((rule) => rule.target.type === 'rack');
211
+ }
212
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/routing/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=routing.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.spec.d.ts","sourceRoot":"","sources":["../../../src/routing/routing.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}