@b00dea/cockpit 0.0.0-stage → 0.1.0

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 (363) hide show
  1. package/CHANGELOG.md +375 -0
  2. package/LICENSE +21 -0
  3. package/README.md +22 -2
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2574 -0
  6. package/dist/autonomy.d.ts +44 -0
  7. package/dist/autonomy.js +156 -0
  8. package/dist/bounded-read.d.ts +14 -0
  9. package/dist/bounded-read.js +42 -0
  10. package/dist/browser/commands.d.ts +62 -0
  11. package/dist/browser/commands.js +349 -0
  12. package/dist/browser/package-paths.d.ts +1 -0
  13. package/dist/browser/package-paths.js +6 -0
  14. package/dist/browser/proxy.d.ts +22 -0
  15. package/dist/browser/proxy.js +37 -0
  16. package/dist/browser/runtime.d.ts +117 -0
  17. package/dist/browser/runtime.js +183 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +556 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/cli-guard.d.ts +5 -0
  23. package/dist/cli-guard.js +71 -0
  24. package/dist/cli-main.d.ts +139 -0
  25. package/dist/cli-main.js +1405 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.js +16 -0
  28. package/dist/command-table.d.ts +113 -0
  29. package/dist/command-table.js +512 -0
  30. package/dist/config/load.d.ts +171 -0
  31. package/dist/config/load.js +345 -0
  32. package/dist/config/sibling-toml.d.ts +48 -0
  33. package/dist/config/sibling-toml.js +160 -0
  34. package/dist/config/surface-tools-toml.d.ts +9 -0
  35. package/dist/config/surface-tools-toml.js +37 -0
  36. package/dist/config/verified-write.d.ts +43 -0
  37. package/dist/config/verified-write.js +89 -0
  38. package/dist/diagnostics.d.ts +26 -0
  39. package/dist/diagnostics.js +335 -0
  40. package/dist/emit.d.ts +22 -0
  41. package/dist/emit.js +43 -0
  42. package/dist/entrypoint-kinds.d.ts +3 -0
  43. package/dist/entrypoint-kinds.js +11 -0
  44. package/dist/environment/application/destructive.d.ts +6 -0
  45. package/dist/environment/application/destructive.js +425 -0
  46. package/dist/environment/application/doctor.d.ts +89 -0
  47. package/dist/environment/application/doctor.js +235 -0
  48. package/dist/environment/application/guard.d.ts +43 -0
  49. package/dist/environment/application/guard.js +622 -0
  50. package/dist/environment/application/health.d.ts +134 -0
  51. package/dist/environment/application/health.js +379 -0
  52. package/dist/environment/application/lifecycle-context.d.ts +228 -0
  53. package/dist/environment/application/lifecycle-context.js +154 -0
  54. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  55. package/dist/environment/application/lifecycle-state.js +201 -0
  56. package/dist/environment/application/lifecycle.d.ts +17 -0
  57. package/dist/environment/application/lifecycle.js +729 -0
  58. package/dist/environment/application/logs.d.ts +45 -0
  59. package/dist/environment/application/logs.js +127 -0
  60. package/dist/environment/application/setup.d.ts +129 -0
  61. package/dist/environment/application/setup.js +741 -0
  62. package/dist/environment/application/shared.d.ts +11 -0
  63. package/dist/environment/application/shared.js +61 -0
  64. package/dist/environment/claims.d.ts +389 -0
  65. package/dist/environment/claims.js +1709 -0
  66. package/dist/environment/codex-hook-trust.d.ts +11 -0
  67. package/dist/environment/codex-hook-trust.js +185 -0
  68. package/dist/environment/compose-environment.d.ts +1 -0
  69. package/dist/environment/compose-environment.js +6 -0
  70. package/dist/environment/compose-ownership.d.ts +21 -0
  71. package/dist/environment/compose-ownership.js +117 -0
  72. package/dist/environment/compose-topology.d.ts +117 -0
  73. package/dist/environment/compose-topology.js +413 -0
  74. package/dist/environment/contract.d.ts +489 -0
  75. package/dist/environment/contract.js +761 -0
  76. package/dist/environment/declaration.d.ts +14 -0
  77. package/dist/environment/declaration.js +39 -0
  78. package/dist/environment/destructive-composition.d.ts +29 -0
  79. package/dist/environment/destructive-composition.js +333 -0
  80. package/dist/environment/docker-daemon.d.ts +30 -0
  81. package/dist/environment/docker-daemon.js +78 -0
  82. package/dist/environment/docker-endpoint.d.ts +10 -0
  83. package/dist/environment/docker-endpoint.js +19 -0
  84. package/dist/environment/env-schema-observation.d.ts +46 -0
  85. package/dist/environment/env-schema-observation.js +241 -0
  86. package/dist/environment/evidence.d.ts +136 -0
  87. package/dist/environment/evidence.js +437 -0
  88. package/dist/environment/executable.d.ts +26 -0
  89. package/dist/environment/executable.js +167 -0
  90. package/dist/environment/generated-application/authorities.d.ts +5 -0
  91. package/dist/environment/generated-application/authorities.js +61 -0
  92. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  93. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  94. package/dist/environment/generated-application/check.d.ts +13 -0
  95. package/dist/environment/generated-application/check.js +189 -0
  96. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  97. package/dist/environment/generated-application/custom-surface.js +289 -0
  98. package/dist/environment/generated-application/prepare.d.ts +29 -0
  99. package/dist/environment/generated-application/prepare.js +276 -0
  100. package/dist/environment/generated-application/publication.d.ts +33 -0
  101. package/dist/environment/generated-application/publication.js +547 -0
  102. package/dist/environment/generated-application/shared.d.ts +484 -0
  103. package/dist/environment/generated-application/shared.js +349 -0
  104. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  105. package/dist/environment/generated-application/surface-observation.js +69 -0
  106. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  107. package/dist/environment/generated-application/surface-outputs.js +389 -0
  108. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  109. package/dist/environment/generated-application/surfaces.js +699 -0
  110. package/dist/environment/generated-application/sync.d.ts +6 -0
  111. package/dist/environment/generated-application/sync.js +109 -0
  112. package/dist/environment/git-observation.d.ts +183 -0
  113. package/dist/environment/git-observation.js +544 -0
  114. package/dist/environment/health-composition.d.ts +11 -0
  115. package/dist/environment/health-composition.js +628 -0
  116. package/dist/environment/host-observation.d.ts +56 -0
  117. package/dist/environment/host-observation.js +52 -0
  118. package/dist/environment/identity.d.ts +48 -0
  119. package/dist/environment/identity.js +85 -0
  120. package/dist/environment/init-application.d.ts +308 -0
  121. package/dist/environment/init-application.js +697 -0
  122. package/dist/environment/install-policy-observation.d.ts +71 -0
  123. package/dist/environment/install-policy-observation.js +284 -0
  124. package/dist/environment/install-policy.d.ts +48 -0
  125. package/dist/environment/install-policy.js +96 -0
  126. package/dist/environment/instance.d.ts +33 -0
  127. package/dist/environment/instance.js +122 -0
  128. package/dist/environment/instruction-pointer.d.ts +19 -0
  129. package/dist/environment/instruction-pointer.js +144 -0
  130. package/dist/environment/lifecycle-composition.d.ts +29 -0
  131. package/dist/environment/lifecycle-composition.js +675 -0
  132. package/dist/environment/lifecycle-stage.d.ts +115 -0
  133. package/dist/environment/lifecycle-stage.js +398 -0
  134. package/dist/environment/lifecycle.d.ts +75 -0
  135. package/dist/environment/lifecycle.js +354 -0
  136. package/dist/environment/logs.d.ts +132 -0
  137. package/dist/environment/logs.js +519 -0
  138. package/dist/environment/observations.d.ts +46 -0
  139. package/dist/environment/observations.js +344 -0
  140. package/dist/environment/operator-application.d.ts +50 -0
  141. package/dist/environment/operator-application.js +155 -0
  142. package/dist/environment/ports.d.ts +182 -0
  143. package/dist/environment/ports.js +1205 -0
  144. package/dist/environment/posture-observation.d.ts +68 -0
  145. package/dist/environment/posture-observation.js +253 -0
  146. package/dist/environment/read-composition.d.ts +27 -0
  147. package/dist/environment/read-composition.js +352 -0
  148. package/dist/environment/readiness-composition.d.ts +38 -0
  149. package/dist/environment/readiness-composition.js +130 -0
  150. package/dist/environment/reclaim.d.ts +333 -0
  151. package/dist/environment/reclaim.js +1835 -0
  152. package/dist/environment/repository-identity.d.ts +13 -0
  153. package/dist/environment/repository-identity.js +108 -0
  154. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  155. package/dist/environment/runtime-measurement-record.js +111 -0
  156. package/dist/environment/runtime-measurement.d.ts +27 -0
  157. package/dist/environment/runtime-measurement.js +224 -0
  158. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  159. package/dist/environment/runtime-probe-residue.js +148 -0
  160. package/dist/environment/runtime-probe.d.ts +72 -0
  161. package/dist/environment/runtime-probe.js +725 -0
  162. package/dist/environment/runtime.d.ts +505 -0
  163. package/dist/environment/runtime.js +2335 -0
  164. package/dist/environment/seed.d.ts +16 -0
  165. package/dist/environment/seed.js +43 -0
  166. package/dist/environment/selftest-application.d.ts +86 -0
  167. package/dist/environment/selftest-application.js +713 -0
  168. package/dist/environment/sensitive.d.ts +3 -0
  169. package/dist/environment/sensitive.js +48 -0
  170. package/dist/environment/setup-observation.d.ts +62 -0
  171. package/dist/environment/setup-observation.js +1473 -0
  172. package/dist/environment/setup.d.ts +43 -0
  173. package/dist/environment/setup.js +176 -0
  174. package/dist/environment/sibling-instructions.d.ts +33 -0
  175. package/dist/environment/sibling-instructions.js +224 -0
  176. package/dist/environment/sibling-registration.d.ts +45 -0
  177. package/dist/environment/sibling-registration.js +538 -0
  178. package/dist/environment/state.d.ts +371 -0
  179. package/dist/environment/state.js +2013 -0
  180. package/dist/environment/templates.d.ts +140 -0
  181. package/dist/environment/templates.js +685 -0
  182. package/dist/environment/tool-registration.d.ts +9 -0
  183. package/dist/environment/tool-registration.js +96 -0
  184. package/dist/environment/upgrade-application.d.ts +19 -0
  185. package/dist/environment/upgrade-application.js +175 -0
  186. package/dist/environment-exec/execute.d.ts +102 -0
  187. package/dist/environment-exec/execute.js +1175 -0
  188. package/dist/environment-exec/libexec-program.d.ts +6 -0
  189. package/dist/environment-exec/libexec-program.js +22 -0
  190. package/dist/environment-exec/verified-digest.d.ts +4 -0
  191. package/dist/environment-exec/verified-digest.js +16 -0
  192. package/dist/exact-keys.d.ts +7 -0
  193. package/dist/exact-keys.js +15 -0
  194. package/dist/fix-catalogue.d.ts +32 -0
  195. package/dist/fix-catalogue.js +60 -0
  196. package/dist/freshness.d.ts +29 -0
  197. package/dist/freshness.js +75 -0
  198. package/dist/generated-environment/adopt.d.ts +16 -0
  199. package/dist/generated-environment/adopt.js +275 -0
  200. package/dist/generated-environment/command.d.ts +47 -0
  201. package/dist/generated-environment/command.js +75 -0
  202. package/dist/generated-environment/transaction.d.ts +186 -0
  203. package/dist/generated-environment/transaction.js +1770 -0
  204. package/dist/grading/evaluate.d.ts +71 -0
  205. package/dist/grading/evaluate.js +403 -0
  206. package/dist/grading/grade.d.ts +33 -0
  207. package/dist/grading/grade.js +57 -0
  208. package/dist/guards/evaluator.d.ts +113 -0
  209. package/dist/guards/evaluator.js +1226 -0
  210. package/dist/guards/harness-adapter.d.ts +17 -0
  211. package/dist/guards/harness-adapter.js +57 -0
  212. package/dist/guards/host.d.ts +8 -0
  213. package/dist/guards/host.js +10 -0
  214. package/dist/guards/invocation-parser.d.ts +66 -0
  215. package/dist/guards/invocation-parser.js +595 -0
  216. package/dist/guards/local-identity.d.ts +40 -0
  217. package/dist/guards/local-identity.js +123 -0
  218. package/dist/guards/policy-pin.d.ts +13 -0
  219. package/dist/guards/policy-pin.js +175 -0
  220. package/dist/guards/protected-locations.d.ts +62 -0
  221. package/dist/guards/protected-locations.js +461 -0
  222. package/dist/guards/read-only.d.ts +37 -0
  223. package/dist/guards/read-only.js +315 -0
  224. package/dist/init/command.d.ts +40 -0
  225. package/dist/init/command.js +310 -0
  226. package/dist/init/derive.d.ts +51 -0
  227. package/dist/init/derive.js +715 -0
  228. package/dist/init/draft.d.ts +138 -0
  229. package/dist/init/draft.js +1205 -0
  230. package/dist/init/render.d.ts +35 -0
  231. package/dist/init/render.js +82 -0
  232. package/dist/init/scaffold.d.ts +53 -0
  233. package/dist/init/scaffold.js +121 -0
  234. package/dist/invocation.d.ts +13 -0
  235. package/dist/invocation.js +20 -0
  236. package/dist/package-metadata.d.ts +9 -0
  237. package/dist/package-metadata.js +19 -0
  238. package/dist/readiness.d.ts +53 -0
  239. package/dist/readiness.js +88 -0
  240. package/dist/references/named.d.ts +24 -0
  241. package/dist/references/named.js +27 -0
  242. package/dist/refusal.d.ts +15 -0
  243. package/dist/refusal.js +7 -0
  244. package/dist/registry-derivation.d.ts +31 -0
  245. package/dist/registry-derivation.js +32 -0
  246. package/dist/registry-resolve/command.d.ts +47 -0
  247. package/dist/registry-resolve/command.js +226 -0
  248. package/dist/registry-resolve/registry.d.ts +68 -0
  249. package/dist/registry-resolve/registry.js +292 -0
  250. package/dist/registry-resolve/render-shell.d.ts +18 -0
  251. package/dist/registry-resolve/render-shell.js +36 -0
  252. package/dist/repair.d.ts +29 -0
  253. package/dist/repair.js +8 -0
  254. package/dist/schema-json.d.ts +1 -0
  255. package/dist/schema-json.js +177 -0
  256. package/dist/schema.d.ts +1322 -0
  257. package/dist/schema.js +934 -0
  258. package/dist/setup/command.d.ts +4 -0
  259. package/dist/setup/command.js +4 -0
  260. package/dist/sha256.d.ts +1 -0
  261. package/dist/sha256.js +4 -0
  262. package/dist/surfaces/adoption.d.ts +41 -0
  263. package/dist/surfaces/adoption.js +217 -0
  264. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  265. package/dist/surfaces/consumer-instructions.js +43 -0
  266. package/dist/surfaces/contract.d.ts +42 -0
  267. package/dist/surfaces/contract.js +169 -0
  268. package/dist/surfaces/core-declarations.d.ts +24 -0
  269. package/dist/surfaces/core-declarations.js +79 -0
  270. package/dist/surfaces/development-markers.d.ts +1 -0
  271. package/dist/surfaces/development-markers.js +18 -0
  272. package/dist/surfaces/generator-adapter.d.ts +71 -0
  273. package/dist/surfaces/generator-adapter.js +809 -0
  274. package/dist/surfaces/harness-registry.d.ts +180 -0
  275. package/dist/surfaces/harness-registry.js +117 -0
  276. package/dist/surfaces/mcp.d.ts +95 -0
  277. package/dist/surfaces/mcp.js +186 -0
  278. package/dist/surfaces/merge.d.ts +30 -0
  279. package/dist/surfaces/merge.js +105 -0
  280. package/dist/surfaces/ownership.d.ts +190 -0
  281. package/dist/surfaces/ownership.js +795 -0
  282. package/dist/surfaces/projection.d.ts +136 -0
  283. package/dist/surfaces/projection.js +681 -0
  284. package/dist/surfaces/render.d.ts +118 -0
  285. package/dist/surfaces/render.js +633 -0
  286. package/dist/surfaces/restrictions.d.ts +130 -0
  287. package/dist/surfaces/restrictions.js +447 -0
  288. package/dist/surfaces/selftest.d.ts +162 -0
  289. package/dist/surfaces/selftest.js +393 -0
  290. package/dist/surfaces/skill-contract.d.ts +85 -0
  291. package/dist/surfaces/skill-contract.js +449 -0
  292. package/dist/surfaces/sync.d.ts +57 -0
  293. package/dist/surfaces/sync.js +164 -0
  294. package/dist/team-metadata.d.ts +41 -0
  295. package/dist/team-metadata.js +512 -0
  296. package/dist/testing/gates.d.ts +91 -0
  297. package/dist/testing/gates.js +182 -0
  298. package/dist/testing/hooks.d.ts +59 -0
  299. package/dist/testing/hooks.js +139 -0
  300. package/dist/testing/verdict.d.ts +29 -0
  301. package/dist/testing/verdict.js +62 -0
  302. package/dist/work-orders/application.d.ts +99 -0
  303. package/dist/work-orders/application.js +383 -0
  304. package/dist/work-orders/composition.d.ts +124 -0
  305. package/dist/work-orders/composition.js +1010 -0
  306. package/dist/work-orders/contract.d.ts +61 -0
  307. package/dist/work-orders/contract.js +122 -0
  308. package/dist/work-orders/store.d.ts +158 -0
  309. package/dist/work-orders/store.js +197 -0
  310. package/docs/README.md +65 -0
  311. package/docs/architecture.md +136 -0
  312. package/docs/capability-matrix.md +50 -0
  313. package/docs/cli-reference.md +599 -0
  314. package/docs/command-list.md +51 -0
  315. package/docs/compose-patterns.md +99 -0
  316. package/docs/concepts.md +171 -0
  317. package/docs/configuration-essentials.md +172 -0
  318. package/docs/configuration-reference.md +621 -0
  319. package/docs/environment.md +760 -0
  320. package/docs/extending.md +43 -0
  321. package/docs/faq.md +111 -0
  322. package/docs/getting-started.md +608 -0
  323. package/docs/harness-surfaces.md +433 -0
  324. package/docs/joining-a-team.md +76 -0
  325. package/docs/release-policy.md +49 -0
  326. package/docs/safety-and-autonomy.md +419 -0
  327. package/docs/troubleshooting.md +361 -0
  328. package/docs/tutorial.md +170 -0
  329. package/docs/work-and-browser.md +254 -0
  330. package/libexec/browser-operation.cjs +186 -0
  331. package/libexec/fence-marker.cjs +101 -0
  332. package/libexec/fence-marker.d.cts +24 -0
  333. package/libexec/fenced-group-runner.cjs +77 -0
  334. package/libexec/fenced-supervisor.cjs +137 -0
  335. package/libexec/generated-filesystem.cjs +731 -0
  336. package/libexec/install-filesystem.cjs +225 -0
  337. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  338. package/libexec/rulesync-generator.cjs +743 -0
  339. package/libexec/surface-generator-worker.cjs +266 -0
  340. package/libexec/surface-output-reader.cjs +99 -0
  341. package/libexec/surface-scratch-cleanup.cjs +14 -0
  342. package/libexec/validate-harness-evidence.d.mts +183 -0
  343. package/libexec/validate-harness-evidence.mjs +1312 -0
  344. package/package.json +74 -4
  345. package/surfaces/README.md +33 -0
  346. package/surfaces/agents/evaluator.agent.md +76 -0
  347. package/surfaces/guards/bash-guard.sh +48 -0
  348. package/surfaces/guards/claude.adapter.json +25 -0
  349. package/surfaces/guards/codex.adapter.json +24 -0
  350. package/surfaces/guards/opencode.adapter.json +25 -0
  351. package/surfaces/references/browser.md +63 -0
  352. package/surfaces/references/test-data-and-personas.md +84 -0
  353. package/surfaces/references/testing-tiers.md +11 -0
  354. package/surfaces/skills/cockpit-browser.skill.md +54 -0
  355. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  356. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  357. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  358. package/surfaces/skills/cockpit-work.skill.md +34 -0
  359. package/surfaces/skills/collection.json +5 -0
  360. package/surfaces/skills/procedures/explain.md +61 -0
  361. package/surfaces/skills/procedures/fix.md +81 -0
  362. package/surfaces/skills/procedures/setup.md +379 -0
  363. package/surfaces/skills/procedures/work.md +105 -0
@@ -0,0 +1,354 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { ENVIRONMENT_CODES, snapshotLifecyclePlan, } from './contract.js';
3
+ import { consumeLifecycleStageProjection } from './lifecycle-stage.js';
4
+ import { consumePortLeaseProjection } from './ports.js';
5
+ import { isRuntimeTopologyEvidence, isRuntimeServiceEvidence, } from './runtime.js';
6
+ const SHA256 = /^[a-f0-9]{64}$/;
7
+ const SERVICE_ID = /^[a-z0-9][a-z0-9_.-]*$/;
8
+ const MAX_BASIS_BYTES = 1_048_576;
9
+ const MAX_SERVICES = 4_096;
10
+ const MAX_EDGES = 16_384;
11
+ const MAX_VALIDITY_MS = 300_000;
12
+ const DOMAIN = 'cockpit-lifecycle-work-basis/v1';
13
+ const admittedUpPlans = new WeakMap();
14
+ const issuedPlans = new WeakMap();
15
+ function refusal(code, message, target) {
16
+ return {
17
+ kind: 'refusal',
18
+ diagnostics: [{ severity: 'error', code, message, target }],
19
+ };
20
+ }
21
+ function codePointCompare(left, right) {
22
+ const a = Array.from(left, (value) => value.codePointAt(0));
23
+ const b = Array.from(right, (value) => value.codePointAt(0));
24
+ for (let index = 0; index < Math.min(a.length, b.length); index += 1) {
25
+ if (a[index] !== b[index])
26
+ return a[index] - b[index];
27
+ }
28
+ return a.length - b.length;
29
+ }
30
+ function canonicalValue(value) {
31
+ if (Array.isArray(value))
32
+ return value.map(canonicalValue);
33
+ if (value !== null && typeof value === 'object') {
34
+ return Object.fromEntries(Object.entries(value)
35
+ .sort(([left], [right]) => codePointCompare(left, right))
36
+ .map(([key, item]) => [key, canonicalValue(item)]));
37
+ }
38
+ return value;
39
+ }
40
+ function unique(values, key) {
41
+ return new Set(values.map(key)).size === values.length;
42
+ }
43
+ function canonicalSet(values, key) {
44
+ if (!unique(values, key))
45
+ return undefined;
46
+ return [...values].sort((left, right) => codePointCompare(key(left), key(right)));
47
+ }
48
+ function canonicalExecution(value) {
49
+ const paths = canonicalSet(value.paths, String);
50
+ const ports = unique(value.ports, String) ? [...value.ports].sort((left, right) => left - right) : undefined;
51
+ const consumedFiles = canonicalSet(value.consumedFiles, (item) => item.path);
52
+ const expected = canonicalSet(value.expected, (item) => JSON.stringify(canonicalValue(item)));
53
+ const filesystemChecks = canonicalSet(value.filesystemChecks, (item) => item.path);
54
+ if (!paths || !ports || !expected || !consumedFiles || !filesystemChecks)
55
+ return undefined;
56
+ const compensation = value.compensation.map(canonicalExecution);
57
+ if (compensation.some((item) => item === undefined))
58
+ return undefined;
59
+ return {
60
+ argv: [...value.argv], argv0: value.argv0, cwd: value.cwd, env: { ...value.env },
61
+ stdoutLimitBytes: value.stdoutLimitBytes,
62
+ stderrLimitBytes: value.stderrLimitBytes, paths, ports, expected: expected.map((item) => ({ ...item })),
63
+ consumedFiles: consumedFiles.map((item) => ({ ...item, argvIndexes: [...item.argvIndexes] })),
64
+ filesystemChecks: filesystemChecks.map((item) => ({ ...item })), compensation,
65
+ };
66
+ }
67
+ function workBasis(verb, semantics, ports, context = {}) {
68
+ const order = [...semantics.topology.order];
69
+ if (order.length > MAX_SERVICES || !unique(order, String) || order.some((service) => !SERVICE_ID.test(service))
70
+ || semantics.topology.services.length !== order.length || semantics.services.length !== order.length)
71
+ return undefined;
72
+ const serviceIds = new Set(order);
73
+ if (!unique(semantics.topology.services, ({ id }) => id)
74
+ || semantics.topology.services.some(({ id }) => !serviceIds.has(id)))
75
+ return undefined;
76
+ const topologyById = new Map(semantics.topology.services.map((service) => [service.id, service]));
77
+ let edgeCount = 0;
78
+ const topologyServices = [];
79
+ const serviceSemantics = [];
80
+ for (let index = 0; index < order.length; index += 1) {
81
+ const service = topologyById.get(order[index]);
82
+ const runtimeService = semantics.services[index];
83
+ if (!service || !runtimeService || service.id !== order[index] || runtimeService.id !== order[index]
84
+ || service.dependsOn.some((dependency) => !serviceIds.has(dependency)))
85
+ return undefined;
86
+ const dependencies = canonicalSet(service.dependsOn, String);
87
+ const mounts = canonicalSet(service.bindMountSources, String);
88
+ if (!dependencies || !mounts)
89
+ return undefined;
90
+ edgeCount += dependencies.length;
91
+ if (edgeCount > MAX_EDGES)
92
+ return undefined;
93
+ const start = canonicalExecution(runtimeService.start);
94
+ const status = canonicalExecution(runtimeService.status);
95
+ const identity = canonicalExecution(runtimeService.identity);
96
+ const inspect = canonicalExecution(runtimeService.inspect);
97
+ if (!start || !status || !identity || !inspect)
98
+ return undefined;
99
+ topologyServices.push({ id: service.id, dependsOn: dependencies, bindMountSources: mounts, healthcheck: service.healthcheck });
100
+ serviceSemantics.push({ id: runtimeService.id, start, status, identity, inspect, healthAcceptance: { ...runtimeService.healthAcceptance } });
101
+ }
102
+ const expectedMountSources = canonicalSet(semantics.runtimeChecks.expectedMountSources, String);
103
+ if (!expectedMountSources || ports.lease.stackId !== semantics.stackId
104
+ || !unique(ports.entrypoints, (entrypoint) => entrypoint.name))
105
+ return undefined;
106
+ // The basis names the work, so saved progress stays valid while the work is the same. Budgets
107
+ // (cold start, step timeouts) and the lifecycle stage are left out: the first `up` itself moves
108
+ // the stage to steady, and the next `up` read that as different work, re-ran every start as a
109
+ // no-op and reported a fresh start with an invented cold-start time. The leased ports stand in
110
+ // for the entrypoint URLs derived from them, which only name those ports.
111
+ const basis = canonicalValue({
112
+ domain: DOMAIN, verb, stackId: semantics.stackId, configSha256: semantics.configSha256,
113
+ runtimeVersion: semantics.runtimeVersion, composeVersion: semantics.composeVersion,
114
+ projectName: semantics.projectName,
115
+ runtimeChecks: { expectedMountSources },
116
+ topology: { order, services: topologyServices }, services: serviceSemantics,
117
+ ports: { ...ports.lease.ports },
118
+ ...(context.reclaim === undefined ? {} : {
119
+ reclaim: {
120
+ planDigest: context.reclaim.planDigest,
121
+ commitments: context.reclaim.commitments.map(({ targetId, format, sha256, body }) => ({
122
+ targetId, format, sha256, body,
123
+ })),
124
+ },
125
+ }),
126
+ });
127
+ const serialized = JSON.stringify(basis);
128
+ if (Buffer.byteLength(serialized, 'utf8') > MAX_BASIS_BYTES)
129
+ return undefined;
130
+ return createHash('sha256').update(Buffer.from(serialized, 'utf8')).digest('hex');
131
+ }
132
+ function consumePlannerEvidence(runtimeProjection, portProjection) {
133
+ const runtime = isRuntimeTopologyEvidence(runtimeProjection.topology) ? runtimeProjection : undefined;
134
+ const ports = consumePortLeaseProjection(portProjection);
135
+ if (!runtime || !ports || runtime.semantics.stackId !== ports.lease.stackId
136
+ || !Number.isSafeInteger(ports.ownership.holderCount) || ports.ownership.holderCount < 0
137
+ || ports.ownership.holderIds.length !== ports.ownership.holderCount
138
+ || !unique(ports.ownership.holderIds, String)
139
+ || !ports.ownership.holderIds.includes(ports.ownership.holderId))
140
+ return undefined;
141
+ return { runtime, ports };
142
+ }
143
+ function validProgress(progress) {
144
+ return progress === null || SHA256.test(progress.workBasisSha256) && SHA256.test(progress.operationGeneration)
145
+ && progress.completedServices.length <= MAX_SERVICES
146
+ && progress.completedServices.every((item) => SERVICE_ID.test(item.service) && SHA256.test(item.containerId));
147
+ }
148
+ function completedPrefix(evidence, progress, runtime) {
149
+ if (evidence.length !== progress.completedServices.length)
150
+ return undefined;
151
+ for (let index = 0; index < evidence.length; index += 1) {
152
+ const item = evidence[index];
153
+ const completed = progress.completedServices[index];
154
+ const service = runtime.semantics.services[index];
155
+ if (!item || !completed || !service
156
+ || item.stackId !== runtime.semantics.stackId || item.configSha256 !== runtime.semantics.configSha256
157
+ || item.batchId !== runtime.topology.batchId || item.executableSha256 !== runtime.topology.executableSha256
158
+ || item.runtimeVersion !== runtime.semantics.runtimeVersion || item.composeVersion !== runtime.semantics.composeVersion
159
+ || item.projectName !== runtime.semantics.projectName || item.service !== service.id
160
+ || item.service !== completed.service || item.containerId !== completed.containerId
161
+ || item.state !== service.healthAcceptance.state || item.health !== service.healthAcceptance.health)
162
+ return undefined;
163
+ }
164
+ return evidence;
165
+ }
166
+ function lifecyclePlan(verb, workBasisSha256, operationGeneration, completedServices, steps, completedStepCount, compensation) {
167
+ const plan = snapshotLifecyclePlan({
168
+ verb,
169
+ progress: { workBasisSha256, operationGeneration, completedServices },
170
+ steps,
171
+ resumeBoundary: {
172
+ completedStepIds: steps.slice(0, completedStepCount).map(({ id }) => id),
173
+ nextStepId: steps[completedStepCount]?.id ?? null,
174
+ },
175
+ compensation,
176
+ diagnostics: [],
177
+ });
178
+ return plan;
179
+ }
180
+ function issue(plan, issuance) {
181
+ issuedPlans.set(plan, issuance);
182
+ return plan;
183
+ }
184
+ export function consumeLifecycleIssuance(plan) {
185
+ if (!plan || typeof plan !== 'object')
186
+ return undefined;
187
+ const issuance = issuedPlans.get(plan);
188
+ if (!issuance)
189
+ return undefined;
190
+ issuedPlans.delete(plan);
191
+ return issuance;
192
+ }
193
+ export function admitUpProgress(input) {
194
+ if (!SHA256.test(input.operationGeneration)) {
195
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'lifecycle planning evidence is invalid', 'up');
196
+ }
197
+ const stage = consumeLifecycleStageProjection(input.lifecycleStage);
198
+ const evidence = consumePlannerEvidence(input.runtime, input.ports);
199
+ if (!stage || !evidence || stage.stackId !== evidence.runtime.semantics.stackId) {
200
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'lifecycle planning evidence is invalid', 'up');
201
+ }
202
+ const basis = workBasis('up', evidence.runtime.semantics, evidence.ports);
203
+ if (!basis)
204
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'lifecycle work evidence is invalid', 'up');
205
+ const prior = input.progress;
206
+ if (!validProgress(prior) || prior !== null && (prior.workBasisSha256 !== basis
207
+ || prior.operationGeneration !== input.operationGeneration)) {
208
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_PROGRESS_INVALID, 'lifecycle progress does not match the current work', 'up-progress');
209
+ }
210
+ const progress = prior ?? {
211
+ workBasisSha256: basis,
212
+ operationGeneration: input.operationGeneration,
213
+ completedServices: [],
214
+ };
215
+ const authority = {};
216
+ admittedUpPlans.set(authority, { ...evidence, progress, mode: prior === null ? 'start' : 'resume' });
217
+ return { kind: 'admitted', authority };
218
+ }
219
+ export function planAdmittedUp(input) {
220
+ const evidence = admittedUpPlans.get(input.authority);
221
+ admittedUpPlans.delete(input.authority);
222
+ const now = Date.now();
223
+ const window = evidence?.runtime.topology.observationWindow;
224
+ if (!evidence || !window
225
+ || !Number.isFinite(Date.parse(window.startedAt)) || !Number.isFinite(Date.parse(window.expiresAt))
226
+ || now < Date.parse(window.startedAt) || now > Date.parse(window.expiresAt)) {
227
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'lifecycle planning authority is unavailable or expired', 'up');
228
+ }
229
+ const { progress } = evidence;
230
+ const completedEvidence = input.completedServices;
231
+ if (completedEvidence.length > MAX_SERVICES || !completedEvidence.every((item) => isRuntimeServiceEvidence(item))) {
232
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'completed service evidence is invalid', 'up-evidence');
233
+ }
234
+ const completed = completedPrefix(completedEvidence, progress, evidence.runtime);
235
+ const order = evidence.runtime.semantics.topology.order;
236
+ if (!completed || completed.length > order.length
237
+ || completed.some((item, index) => item.service !== order[index])) {
238
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_PROGRESS_INVALID, 'completed services are not the current dependency prefix', 'up-progress');
239
+ }
240
+ const steps = [
241
+ { id: 'lifecycle:preflight', kind: 'preflight' },
242
+ { id: 'lifecycle:claim:acquire', kind: 'claim', action: 'acquire' },
243
+ ...order.map((service) => ({ id: `lifecycle:service:${service}`, kind: 'service', service })),
244
+ {
245
+ id: 'lifecycle:entrypoints', kind: 'publish-entrypoints',
246
+ values: evidence.ports.entrypoints.map((entrypoint) => ({ ...entrypoint })),
247
+ },
248
+ ];
249
+ const compensation = evidence.ports.ownership.change === 'acquired'
250
+ ? [{
251
+ step: { id: 'lifecycle:claim:release', kind: 'claim', action: 'release' },
252
+ ownership: {
253
+ stackId: evidence.ports.lease.stackId, holderId: evidence.ports.ownership.holderId,
254
+ recordRevision: evidence.ports.ownership.recordRevision, change: 'acquired',
255
+ },
256
+ }] : [];
257
+ const complete = completed.length === order.length && evidence.mode === 'resume';
258
+ const completedStepCount = complete ? steps.length : 2 + completed.length;
259
+ const plan = lifecyclePlan('up', progress.workBasisSha256, progress.operationGeneration, progress.completedServices, steps, completedStepCount, compensation);
260
+ if (!plan)
261
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'lifecycle plan could not be represented', 'up');
262
+ issue(plan, {
263
+ topology: evidence.runtime.topology, firstIncompleteServiceIndex: completed.length,
264
+ portOwnership: evidence.ports.ownership, drainRequest: null, reclaim: null,
265
+ });
266
+ if (complete)
267
+ return { kind: 'noop', plan };
268
+ return { kind: 'execute', mode: evidence.mode, plan };
269
+ }
270
+ function validDrainInputs(generation, runtimeStopValidForMs, reclaimValidForMs) {
271
+ const validity = (ms) => Number.isSafeInteger(ms) && ms >= 1 && ms <= MAX_VALIDITY_MS;
272
+ return SHA256.test(generation) && validity(runtimeStopValidForMs)
273
+ && (reclaimValidForMs === undefined || validity(reclaimValidForMs));
274
+ }
275
+ function drainRequest(purpose, evidence, generation, runtimeStopValidForMs, reclaimValidForMs, reclaim) {
276
+ const operationBasis = workBasis(purpose, evidence.runtime.semantics, evidence.ports, reclaim === undefined ? {} : { reclaim });
277
+ const targetIds = [
278
+ evidence.runtime.semantics.stackId,
279
+ ...(reclaim?.commitments.map(({ targetId }) => targetId) ?? []),
280
+ ].sort();
281
+ const actions = [
282
+ { stage: 'runtime-stop', targetId: evidence.runtime.semantics.stackId, validForMs: runtimeStopValidForMs },
283
+ ...(reclaim?.commitments.map(({ targetId, ...targetCommitment }) => ({
284
+ stage: 'reclaim', targetId, validForMs: reclaimValidForMs, targetCommitment: { ...targetCommitment },
285
+ })) ?? []),
286
+ ];
287
+ return {
288
+ purpose, stackId: evidence.runtime.semantics.stackId,
289
+ holderId: evidence.ports.ownership.holderId, requesterId: evidence.ports.ownership.holderId,
290
+ configSha256: evidence.runtime.semantics.configSha256,
291
+ planDigest: reclaim?.planDigest ?? operationBasis,
292
+ operationBasis, generation,
293
+ targetIds, actions, expectedCoordinationRevision: evidence.ports.ownership.recordRevision,
294
+ };
295
+ }
296
+ function passivePlan(verb, evidence, generation, steps, request, reclaim) {
297
+ const basis = workBasis(verb, evidence.runtime.semantics, evidence.ports, reclaim === null ? {} : { reclaim });
298
+ if (!basis)
299
+ return undefined;
300
+ const plan = lifecyclePlan(verb, basis, generation, [], steps, 0, []);
301
+ if (!plan)
302
+ return undefined;
303
+ return issue(plan, {
304
+ topology: evidence.runtime.topology, firstIncompleteServiceIndex: 0,
305
+ portOwnership: evidence.ports.ownership, drainRequest: request, reclaim,
306
+ });
307
+ }
308
+ export function planSleep(input) {
309
+ if (!validDrainInputs(input.operationGeneration, input.runtimeStopValidForMs)) {
310
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'sleep planning evidence is invalid', 'sleep');
311
+ }
312
+ const evidence = consumePlannerEvidence(input.runtime, input.ports);
313
+ if (!evidence)
314
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'sleep planning evidence is invalid', 'sleep');
315
+ if (evidence.ports.ownership.holderCount > 1) {
316
+ const steps = [{ id: 'lifecycle:claim:release', kind: 'claim', action: 'release' }];
317
+ const plan = passivePlan('sleep', evidence, input.operationGeneration, steps, null, null);
318
+ return plan ? { kind: 'release-only', plan }
319
+ : refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'sleep plan could not be represented', 'sleep');
320
+ }
321
+ const request = drainRequest('sleep', evidence, input.operationGeneration, input.runtimeStopValidForMs);
322
+ const plan = passivePlan('sleep', evidence, input.operationGeneration, [{ id: 'lifecycle:preflight', kind: 'preflight' }], request, null);
323
+ return plan ? { kind: 'drain', plan, request }
324
+ : refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, 'sleep plan could not be represented', 'sleep');
325
+ }
326
+ function planDestructive(verb, input) {
327
+ if (!validDrainInputs(input.operationGeneration, input.runtimeStopValidForMs, input.reclaimValidForMs)) {
328
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, `${verb} planning evidence is invalid`, verb);
329
+ }
330
+ const evidence = consumePlannerEvidence(input.runtime, input.ports);
331
+ const reclaim = input.reclaim;
332
+ if (!evidence || reclaim.purpose !== verb || reclaim.stackId !== evidence.runtime.semantics.stackId
333
+ || reclaim.configSha256 !== evidence.runtime.semantics.configSha256
334
+ || verb === 'reset' && reclaim.commitments.length === 0
335
+ || !unique(reclaim.commitments, ({ targetId }) => targetId)
336
+ || reclaim.commitments.some(({ targetId }, index) => index > 0
337
+ && reclaim.commitments[index - 1].targetId >= targetId)
338
+ || reclaim.commitments.some(({ targetId }) => targetId === evidence.runtime.semantics.stackId)) {
339
+ return refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, `${verb} requires valid runtime, port, and reclaim evidence`, verb);
340
+ }
341
+ if (evidence.ports.ownership.holderCount !== 1) {
342
+ return refusal(ENVIRONMENT_CODES.CLAIM_CO_TENANT, `${verb} requires exact exclusive ownership`, verb);
343
+ }
344
+ const request = drainRequest(verb, evidence, input.operationGeneration, input.runtimeStopValidForMs, input.reclaimValidForMs, reclaim);
345
+ const plan = passivePlan(verb, evidence, input.operationGeneration, [{ id: 'lifecycle:preflight', kind: 'preflight' }], request, reclaim);
346
+ return plan ? { kind: 'drain', plan, request }
347
+ : refusal(ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID, `${verb} plan could not be represented`, verb);
348
+ }
349
+ export function planDown(input) {
350
+ return planDestructive('down', input);
351
+ }
352
+ export function planResetLifecycle(input) {
353
+ return planDestructive('reset', input);
354
+ }
@@ -0,0 +1,132 @@
1
+ import { type ExecuteProbeOutcome } from '../environment-exec/execute.js';
2
+ import { ENVIRONMENT_CODES, type ExecutionFailureCode, type ExecutionStep, type StackId } from './contract.js';
3
+ import { type CapturedRuntimeEvidence } from './evidence.js';
4
+ import { type ComposeArtifact, type RuntimeAdapterAuthority, type RuntimeServiceFailureEvidence, type RuntimeServiceObservation } from './runtime.js';
5
+ import { type ResolvedExecutable } from './executable.js';
6
+ export interface LogRequest {
7
+ runtime: 'docker-compose';
8
+ executable: ResolvedExecutable;
9
+ cwd: string;
10
+ stackId: StackId;
11
+ configSha256: string;
12
+ batchId: string;
13
+ containerId: string;
14
+ runtimeVersion: string;
15
+ composeVersion: string;
16
+ restartBatches?: readonly [string, string];
17
+ projectName: string;
18
+ composeFiles: readonly ComposeArtifact[];
19
+ services: readonly string[];
20
+ service: string;
21
+ since: string;
22
+ tail: number;
23
+ follow: boolean;
24
+ timeoutMs: number;
25
+ outputLimitBytes: number;
26
+ env: Readonly<Record<string, string>>;
27
+ }
28
+ export type LogPlan = {
29
+ kind: 'planned';
30
+ step: ExecutionStep;
31
+ } | {
32
+ kind: 'unavailable';
33
+ code: typeof ENVIRONMENT_CODES.RUNTIME_UNAVAILABLE | typeof ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE;
34
+ reason: string;
35
+ };
36
+ export declare function planLogs(rawInput: LogRequest, ownComposeAuthority?: Extract<RuntimeAdapterAuthority, {
37
+ ownComposeFiles: true;
38
+ }>): LogPlan;
39
+ export interface FailureLogRequest {
40
+ readonly evidence: RuntimeServiceObservation | RuntimeServiceFailureEvidence;
41
+ readonly tail: number;
42
+ readonly timeoutMs: number;
43
+ readonly outputLimitBytes: number;
44
+ }
45
+ export type FailureLogPlan = {
46
+ readonly kind: 'planned';
47
+ readonly step: ExecutionStep;
48
+ } | {
49
+ readonly kind: 'unavailable';
50
+ readonly reason: string;
51
+ };
52
+ export declare function planFailureLogs(input: FailureLogRequest): FailureLogPlan;
53
+ export type LogExecution = ExecuteProbeOutcome;
54
+ export type LogRecord = Readonly<{
55
+ stackId: StackId;
56
+ configSha256: string;
57
+ batchId: string;
58
+ containerId: string;
59
+ service: string;
60
+ runtimeVersion: string;
61
+ executableSha256: string;
62
+ timestamp: string;
63
+ message: string;
64
+ stream: 'stdout' | 'stderr';
65
+ restart: boolean;
66
+ }>;
67
+ export type EarlyFailureLogRecord = Readonly<Omit<LogRecord, 'containerId' | 'stream'> & {
68
+ containerId: null;
69
+ stream: 'combined';
70
+ }>;
71
+ export type FailureLogRecord = LogRecord | EarlyFailureLogRecord;
72
+ export type FailureLogAdmission = {
73
+ readonly kind: 'complete';
74
+ readonly records: readonly FailureLogRecord[];
75
+ } | {
76
+ readonly kind: 'unavailable';
77
+ readonly records: readonly FailureLogRecord[];
78
+ } | {
79
+ readonly kind: 'unavailable';
80
+ readonly code: ExecutionFailureCode;
81
+ readonly service: string;
82
+ readonly records: readonly FailureLogRecord[];
83
+ };
84
+ export declare function admitFailureLogs(input: {
85
+ readonly plan: FailureLogPlan;
86
+ readonly outcome: ExecuteProbeOutcome;
87
+ }): FailureLogAdmission;
88
+ /**
89
+ * The bounded message a failed service's diagnostic carries. A restart policy replays the same crash
90
+ * on every start, which filled the excerpt with one line repeated; each distinct line is shown once,
91
+ * where it last occurred, with its count. A line is labelled with its stream only when the runtime
92
+ * reported which stream it was.
93
+ */
94
+ export declare function failureLogExcerpt(service: string, records: readonly FailureLogRecord[]): string;
95
+ export interface RestartWindow {
96
+ readonly before: CapturedRuntimeEvidence;
97
+ readonly after: CapturedRuntimeEvidence;
98
+ }
99
+ export declare function collectLogs(plan: Extract<LogPlan, {
100
+ kind: 'planned';
101
+ }>, execute: (step: ExecutionStep, options: {
102
+ signal?: AbortSignal;
103
+ }) => Promise<LogExecution>, signal?: AbortSignal, restart?: RestartWindow): Promise<{
104
+ kind: 'unavailable';
105
+ code: "EVIDENCE_UNAVAILABLE";
106
+ reason: string;
107
+ records: never[];
108
+ } | {
109
+ kind: 'unavailable';
110
+ code: "EXECUTION_ABORTED" | "EXECUTION_PRECONDITION_CHANGED" | "EXECUTION_SPAWN_FAILED" | "EXECUTION_STAGING_CLEANUP_FAILED" | "EXECUTION_STAGING_FAILED" | "EXECUTION_STDERR_LIMIT" | "EXECUTION_STDOUT_LIMIT" | "EXECUTION_STEP_FAILED" | "EXECUTION_TERMINATION_UNCONFIRMED" | "EXECUTION_TIMEOUT";
111
+ reason: string;
112
+ records: never[];
113
+ truncated?: undefined;
114
+ } | {
115
+ reason?: undefined;
116
+ code?: undefined;
117
+ kind: "cancelled" | "complete";
118
+ records: Readonly<{
119
+ stackId: StackId;
120
+ configSha256: string;
121
+ batchId: string;
122
+ containerId: string;
123
+ service: string;
124
+ runtimeVersion: string;
125
+ executableSha256: string;
126
+ timestamp: string;
127
+ message: string;
128
+ stream: 'stdout' | 'stderr';
129
+ restart: boolean;
130
+ }>[];
131
+ truncated: boolean;
132
+ }>;