@b00dea/cockpit 0.0.0-bootstrap.0 → 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 +21 -1
  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 +76 -1
  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,761 @@
1
+ import { dirname, isAbsolute, normalize } from 'node:path';
2
+ import { isProxy } from 'node:util/types';
3
+ import { isEntrypointKind } from '../entrypoint-kinds.js';
4
+ import { exactKeys } from '../exact-keys.js';
5
+ const JSON_LIMITS = { bytes: 1_048_576, nodes: 65_536, entries: 4_096, scalarBytes: 65_536, depth: 64 };
6
+ function reserveBytes(state, bytes) {
7
+ if (state.bytes + bytes > state.byteLimit)
8
+ return false;
9
+ state.bytes += bytes;
10
+ return true;
11
+ }
12
+ function snapshotJsonValue(value, state, depth) {
13
+ if (state.nodes >= JSON_LIMITS.nodes || depth > JSON_LIMITS.depth)
14
+ return undefined;
15
+ state.nodes += 1;
16
+ if (value === null || typeof value === 'boolean' || typeof value === 'number') {
17
+ if (typeof value === 'number' && !Number.isFinite(value))
18
+ return undefined;
19
+ const encoded = JSON.stringify(value);
20
+ return reserveBytes(state, Buffer.byteLength(encoded)) ? value : undefined;
21
+ }
22
+ if (typeof value === 'string') {
23
+ const bytes = Buffer.byteLength(value);
24
+ return bytes <= state.scalarLimit && reserveBytes(state, Buffer.byteLength(JSON.stringify(value))) ? value : undefined;
25
+ }
26
+ if (typeof value !== 'object' || isProxy(value) || state.ancestors.has(value))
27
+ return undefined;
28
+ if (!reserveBytes(state, 2))
29
+ return undefined;
30
+ const ancestors = state.ancestors;
31
+ ancestors.add(value);
32
+ try {
33
+ if (Array.isArray(value)) {
34
+ const descriptors = Object.getOwnPropertyDescriptors(value);
35
+ const keys = Reflect.ownKeys(value);
36
+ const length = descriptors.length.value;
37
+ if (typeof length !== 'number' || length > state.entryLimit || keys.length !== length + 1
38
+ || keys.some((key) => typeof key !== 'string' || key !== 'length' && !/^(?:0|[1-9]\d*)$/.test(key))
39
+ || !reserveBytes(state, Math.max(0, length - 1)))
40
+ return undefined;
41
+ const result = [];
42
+ for (let index = 0; index < length; index += 1) {
43
+ const descriptor = descriptors[String(index)];
44
+ if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor))
45
+ return undefined;
46
+ const item = snapshotJsonValue(descriptor.value, state, depth + 1);
47
+ if (item === undefined)
48
+ return undefined;
49
+ result.push(item);
50
+ }
51
+ return result;
52
+ }
53
+ const prototype = Object.getPrototypeOf(value);
54
+ if (prototype !== Object.prototype && prototype !== null)
55
+ return undefined;
56
+ const result = Object.create(null);
57
+ const descriptors = Object.getOwnPropertyDescriptors(value);
58
+ const ownKeys = Reflect.ownKeys(value);
59
+ if (ownKeys.some((key) => typeof key !== 'string'))
60
+ return undefined;
61
+ const keys = ownKeys.sort();
62
+ if (keys.length > state.entryLimit || !reserveBytes(state, Math.max(0, keys.length - 1)))
63
+ return undefined;
64
+ for (const key of keys) {
65
+ const descriptor = descriptors[key];
66
+ if (!descriptor.enumerable || !('value' in descriptor))
67
+ return undefined;
68
+ if (Buffer.byteLength(key) > JSON_LIMITS.scalarBytes || !reserveBytes(state, Buffer.byteLength(JSON.stringify(key)) + 1))
69
+ return undefined;
70
+ const item = snapshotJsonValue(descriptor.value, state, depth + 1);
71
+ if (item === undefined)
72
+ return undefined;
73
+ Object.defineProperty(result, key, { enumerable: true, value: item });
74
+ }
75
+ return result;
76
+ }
77
+ catch { // A throwing accessor or proxy trap makes the value unsnapshottable; the caller refuses it.
78
+ return undefined;
79
+ }
80
+ finally {
81
+ ancestors.delete(value);
82
+ }
83
+ }
84
+ export function snapshotJson(value) {
85
+ return snapshotJsonWithEntryLimit(value, JSON_LIMITS.entries);
86
+ }
87
+ function snapshotJsonWithEntryLimit(value, entryLimit) {
88
+ return snapshotJsonValue(value, {
89
+ bytes: 0, nodes: 0, entryLimit, byteLimit: JSON_LIMITS.bytes,
90
+ scalarLimit: JSON_LIMITS.scalarBytes, ancestors: new WeakSet(),
91
+ }, 0);
92
+ }
93
+ export function snapshotGeneratedJson(value) {
94
+ return snapshotJsonValue(value, {
95
+ bytes: 0, nodes: 0, entryLimit: JSON_LIMITS.entries, byteLimit: 33_554_432,
96
+ scalarLimit: 16_777_216, ancestors: new WeakSet(),
97
+ }, 0);
98
+ }
99
+ const OBSERVATION_LIFECYCLE_STAGES = ['bootstrap', 'steady'];
100
+ const SETUP_ACTION_KINDS = ['clone', 'wire-remote', 'report'];
101
+ // Build tools and tool servers resolve their caches and locale from these; none carries a credential.
102
+ // Every other parent variable stays out of product test stages, verification commands and MCP servers,
103
+ // because they run repository code and the environment of an agent session routinely holds tokens.
104
+ export const INHERITED_TOOL_ENVIRONMENT = Object.freeze(['HOME', 'USER', 'LOGNAME', 'TMPDIR', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ']);
105
+ // The only parent variables a Docker or Compose step receives: where the client finds the daemon and
106
+ // how it authenticates to it. Anything else could reconfigure Compose or the process it starts.
107
+ export const DOCKER_CLIENT_ENVIRONMENT = new Set(['PATH', 'DOCKER_HOST', 'DOCKER_CONTEXT', 'DOCKER_TLS_VERIFY', 'DOCKER_CERT_PATH']);
108
+ // Names that reconfigure the Docker client, the dynamic loader, Node or a shell; a stack-declared
109
+ // variable may never take one of them.
110
+ export const HOST_PROCESS_CONTROL_ENV = /^(?:DOCKER_|COMPOSE_|LD_|DYLD_|LIBPATH$|SHLIB_PATH$|NODE_OPTIONS$|NODE_PATH$|BASH_ENV$|ENV$|PATH$|IFS$)/;
111
+ export const OBSERVATION_PRODUCER_BYTE_LIMIT = 256;
112
+ export const OBSERVATION_REASON_BYTE_LIMIT = 1_024;
113
+ export const ENVIRONMENT_CODES = Object.freeze({
114
+ CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
115
+ CONFIG_UNREADABLE: 'CONFIG_UNREADABLE',
116
+ CONFIG_ENCODING_INVALID: 'CONFIG_ENCODING_INVALID',
117
+ CONFIG_PARSE_INVALID: 'CONFIG_PARSE_INVALID',
118
+ CONFIG_SCHEMA_INVALID: 'CONFIG_SCHEMA_INVALID',
119
+ GENERATED_HOST_PATH_UNMOUNTED: 'GENERATED_HOST_PATH_UNMOUNTED',
120
+ STATE_ROOT_UNAVAILABLE: 'STATE_ROOT_UNAVAILABLE',
121
+ STATE_FORMAT_UNSUPPORTED: 'STATE_FORMAT_UNSUPPORTED',
122
+ STATE_RECORD_MALFORMED: 'STATE_RECORD_MALFORMED',
123
+ STATE_LOCKED: 'STATE_LOCKED',
124
+ STATE_DURABILITY_INDETERMINATE: 'STATE_DURABILITY_INDETERMINATE',
125
+ SETUP_CONFIG_REQUIRED: 'SETUP_CONFIG_REQUIRED',
126
+ SETUP_OPTION_DUPLICATE: 'SETUP_OPTION_DUPLICATE',
127
+ SETUP_POSITIONAL_UNSUPPORTED: 'SETUP_POSITIONAL_UNSUPPORTED',
128
+ SETUP_PATH_OUTSIDE_ROOT: 'SETUP_PATH_OUTSIDE_ROOT',
129
+ SETUP_PATH_SYMLINK: 'SETUP_PATH_SYMLINK',
130
+ SETUP_PATH_TYPE_INVALID: 'SETUP_PATH_TYPE_INVALID',
131
+ SETUP_PARENT_MISSING: 'SETUP_PARENT_MISSING',
132
+ SETUP_REMOTE_MISMATCH: 'SETUP_REMOTE_MISMATCH',
133
+ SETUP_REMOTE_UNRESOLVABLE: 'SETUP_REMOTE_UNRESOLVABLE',
134
+ SETUP_MANUAL_MISSING: 'SETUP_MANUAL_MISSING',
135
+ SETUP_CLONE_FAILED: 'SETUP_CLONE_FAILED',
136
+ SETUP_NONE_ABSENT: 'SETUP_NONE_ABSENT',
137
+ SETUP_NONE_DIRECTORY: 'SETUP_NONE_DIRECTORY',
138
+ SETUP_NONE_REPOSITORY: 'SETUP_NONE_REPOSITORY',
139
+ SETUP_POSTCHECK_FAILED: 'SETUP_POSTCHECK_FAILED',
140
+ SETUP_INSTRUCTION_POINTER_OFFERED: 'SETUP_INSTRUCTION_POINTER_OFFERED',
141
+ SETUP_INSTRUCTION_POINTER_INVALID: 'SETUP_INSTRUCTION_POINTER_INVALID',
142
+ SETUP_INSTRUCTION_FILES_OFFERED: 'SETUP_INSTRUCTION_FILES_OFFERED',
143
+ SETUP_INSTRUCTION_FILES_INVALID: 'SETUP_INSTRUCTION_FILES_INVALID',
144
+ CONFIG_CHANGED_DURING_EXECUTION: 'CONFIG_CHANGED_DURING_EXECUTION',
145
+ EXECUTION_SPAWN_FAILED: 'EXECUTION_SPAWN_FAILED',
146
+ EXECUTION_PRECONDITION_CHANGED: 'EXECUTION_PRECONDITION_CHANGED',
147
+ EXECUTION_STAGING_FAILED: 'EXECUTION_STAGING_FAILED',
148
+ EXECUTION_STAGING_CLEANUP_FAILED: 'EXECUTION_STAGING_CLEANUP_FAILED',
149
+ EXECUTION_TIMEOUT: 'EXECUTION_TIMEOUT',
150
+ EXECUTION_STDOUT_LIMIT: 'EXECUTION_STDOUT_LIMIT',
151
+ EXECUTION_STDERR_LIMIT: 'EXECUTION_STDERR_LIMIT',
152
+ EXECUTION_STEP_FAILED: 'EXECUTION_STEP_FAILED',
153
+ EXECUTION_ABORTED: 'EXECUTION_ABORTED',
154
+ EXECUTION_TERMINATION_UNCONFIRMED: 'EXECUTION_TERMINATION_UNCONFIRMED',
155
+ EXECUTION_COMPENSATION_TIMEOUT: 'EXECUTION_COMPENSATION_TIMEOUT',
156
+ EXECUTION_COMPENSATION_STEP_FAILED: 'EXECUTION_COMPENSATION_STEP_FAILED',
157
+ LIFECYCLE_EVIDENCE_INVALID: 'LIFECYCLE_EVIDENCE_INVALID',
158
+ LIFECYCLE_PROGRESS_INVALID: 'LIFECYCLE_PROGRESS_INVALID',
159
+ STACK_RECORDED_UNDER_EARLIER_NAME: 'STACK_RECORDED_UNDER_EARLIER_NAME',
160
+ PORT_FAMILY_COLLISION: 'PORT_FAMILY_COLLISION',
161
+ PORT_LISTENER_EVIDENCE_INVALID: 'PORT_LISTENER_EVIDENCE_INVALID',
162
+ PORT_FAMILY_OUT_OF_RANGE: 'PORT_FAMILY_OUT_OF_RANGE',
163
+ PORT_LEASE_EXHAUSTED: 'PORT_LEASE_EXHAUSTED',
164
+ PORT_LOCAL_VALUE_CORRECTED: 'PORT_LOCAL_VALUE_CORRECTED',
165
+ PORT_EXTERNAL_REGISTRATION_GAP: 'PORT_EXTERNAL_REGISTRATION_GAP',
166
+ CLAIM_CO_TENANT: 'CLAIM_CO_TENANT',
167
+ CLAIM_LIVENESS_UNKNOWN: 'CLAIM_LIVENESS_UNKNOWN',
168
+ DRAIN_ATTEMPT_REPAIR_REQUIRED: 'DRAIN_ATTEMPT_REPAIR_REQUIRED',
169
+ INSTALL_POLICY_OBSERVATION_UNAVAILABLE: 'INSTALL_POLICY_OBSERVATION_UNAVAILABLE',
170
+ INSTALL_POLICY_OBSERVATION_INVALID: 'INSTALL_POLICY_OBSERVATION_INVALID',
171
+ INSTALL_POLICY_MISSING: 'INSTALL_POLICY_MISSING',
172
+ INSTALL_POLICY_AMBIGUOUS: 'INSTALL_POLICY_AMBIGUOUS',
173
+ TEMPLATE_NOT_FOUND: 'TEMPLATE_NOT_FOUND',
174
+ TEMPLATE_NOT_TRACKED: 'TEMPLATE_NOT_TRACKED',
175
+ TEMPLATE_IGNORED: 'TEMPLATE_IGNORED',
176
+ TEMPLATE_PATH_OUTSIDE_ROOT: 'TEMPLATE_PATH_OUTSIDE_ROOT',
177
+ ENVIRONMENT_FILE_NOT_FOUND: 'ENVIRONMENT_FILE_NOT_FOUND',
178
+ ENVIRONMENT_FILE_UNREADABLE: 'ENVIRONMENT_FILE_UNREADABLE',
179
+ ENVIRONMENT_FILE_TOO_LARGE: 'ENVIRONMENT_FILE_TOO_LARGE',
180
+ ENVIRONMENT_FILE_MALFORMED: 'ENVIRONMENT_FILE_MALFORMED',
181
+ INSTANCE_NOT_IGNORED: 'INSTANCE_NOT_IGNORED',
182
+ ENVIRONMENT_SEED_PRECONDITION_CHANGED: 'ENVIRONMENT_SEED_PRECONDITION_CHANGED',
183
+ ENVIRONMENT_SEED_FAILED: 'ENVIRONMENT_SEED_FAILED',
184
+ RUNTIME_UNAVAILABLE: 'RUNTIME_UNAVAILABLE',
185
+ RUNTIME_IMAGE_UNAVAILABLE: 'RUNTIME_IMAGE_UNAVAILABLE',
186
+ RUNTIME_UNMEASURED: 'RUNTIME_UNMEASURED',
187
+ RUNTIME_COMPOSE_REMOTE: 'RUNTIME_COMPOSE_REMOTE',
188
+ RUNTIME_PROBE_TIMEOUT: 'RUNTIME_PROBE_TIMEOUT',
189
+ LOGS_TRUNCATED: 'LOGS_TRUNCATED',
190
+ RESET_CONFIRMATION_REQUIRED: 'RESET_CONFIRMATION_REQUIRED',
191
+ RESET_CONFIRMATION_MISMATCH: 'RESET_CONFIRMATION_MISMATCH',
192
+ RESET_CO_TENANT: 'RESET_CO_TENANT',
193
+ EVIDENCE_UNAVAILABLE: 'EVIDENCE_UNAVAILABLE',
194
+ RECLAIM_LABEL_ESCAPE: 'RECLAIM_LABEL_ESCAPE',
195
+ RECLAIM_ACCOUNTING_MISMATCH: 'RECLAIM_ACCOUNTING_MISMATCH',
196
+ DOWN_RESOURCES_KEPT: 'DOWN_RESOURCES_KEPT',
197
+ CONFIG_STALE: 'CONFIG_STALE',
198
+ SIBLING_MISSING: 'SIBLING_MISSING',
199
+ GUIDE_CAP_EXCEEDED: 'GUIDE_CAP_EXCEEDED',
200
+ SIBLING_GUIDE_MISSING: 'SIBLING_GUIDE_MISSING',
201
+ MACHINE_MEMORY_BELOW_FLOOR: 'MACHINE_MEMORY_BELOW_FLOOR',
202
+ MACHINE_CPU_BELOW_FLOOR: 'MACHINE_CPU_BELOW_FLOOR',
203
+ MACHINE_DISK_BELOW_FLOOR: 'MACHINE_DISK_BELOW_FLOOR',
204
+ MACHINE_COLD_START_EXCEEDED: 'MACHINE_COLD_START_EXCEEDED',
205
+ GIT_STATE_UNHEALTHY: 'GIT_STATE_UNHEALTHY',
206
+ CHECKOUT_ADJACENCY_UNHEALTHY: 'CHECKOUT_ADJACENCY_UNHEALTHY',
207
+ GIT_COMPARISON_REMOTE_MISMATCH: 'GIT_COMPARISON_REMOTE_MISMATCH',
208
+ RUNNING_CHECKOUT_MISMATCH: 'RUNNING_CHECKOUT_MISMATCH',
209
+ ENVIRONMENT_KEYS_STALE: 'ENVIRONMENT_KEYS_STALE',
210
+ ENV_SCHEMA_UNHEALTHY: 'ENV_SCHEMA_UNHEALTHY',
211
+ ENV_SCHEMA_TOOL_MISSING: 'ENV_SCHEMA_TOOL_MISSING',
212
+ GENERATED_ENVIRONMENT_UNAVAILABLE: 'GENERATED_ENVIRONMENT_UNAVAILABLE',
213
+ CLAIM_STATE_UNHEALTHY: 'CLAIM_STATE_UNHEALTHY',
214
+ MOUNT_POSTURE_UNAVAILABLE: 'MOUNT_POSTURE_UNAVAILABLE',
215
+ STATE_UNSEEDED: 'STATE_UNSEEDED',
216
+ STACK_NOT_RUNNING: 'STACK_NOT_RUNNING',
217
+ SKILL_BUDGET_UNAVAILABLE: 'SKILL_BUDGET_UNAVAILABLE',
218
+ HARNESS_SURFACE_UNAVAILABLE: 'HARNESS_SURFACE_UNAVAILABLE',
219
+ DIRECTORY_GRANTS_UNAVAILABLE: 'DIRECTORY_GRANTS_UNAVAILABLE',
220
+ TEAM_METADATA_UNAVAILABLE: 'TEAM_METADATA_UNAVAILABLE',
221
+ COCKPIT_VERSION_MISMATCH: 'COCKPIT_VERSION_MISMATCH',
222
+ MOUNT_MATERIALIZATION_UNAVAILABLE: 'MOUNT_MATERIALIZATION_UNAVAILABLE',
223
+ ENVIRONMENT_NOT_DECLARED: 'ENVIRONMENT_NOT_DECLARED',
224
+ SERVICE_NOT_DECLARED: 'SERVICE_NOT_DECLARED',
225
+ GUARD_HOSTS_UNDECLARED: 'GUARD_HOSTS_UNDECLARED',
226
+ TESTING_GATE_UNDECLARED: 'TESTING_GATE_UNDECLARED',
227
+ EVALUATOR_UNAVAILABLE: 'EVALUATOR_UNAVAILABLE',
228
+ EVALUATOR_RUN_FAILED: 'EVALUATOR_RUN_FAILED',
229
+ EVALUATOR_FELL_BACK_TO_RUNNING_TOOL: 'EVALUATOR_FELL_BACK_TO_RUNNING_TOOL',
230
+ EVALUATOR_ANSWER_INVALID: 'EVALUATOR_ANSWER_INVALID',
231
+ TEST_GATE_UNSATISFIED: 'TEST_GATE_UNSATISFIED',
232
+ WORK_GRADE_UNSATISFIED: 'WORK_GRADE_UNSATISFIED',
233
+ WORK_CHECK_FAILED: 'WORK_CHECK_FAILED',
234
+ WORK_VERIFY_FAILED: 'WORK_VERIFY_FAILED',
235
+ WORK_PERSON_REQUIRED: 'WORK_PERSON_REQUIRED',
236
+ AUTONOMY_PERSON_REQUIRED: 'AUTONOMY_PERSON_REQUIRED',
237
+ AUTONOMY_CI_ONLY: 'AUTONOMY_CI_ONLY',
238
+ POLICY_WEAKENING_UNCONFIRMED: 'POLICY_WEAKENING_UNCONFIRMED',
239
+ WORK_ORDER_CLOSED: 'WORK_ORDER_CLOSED',
240
+ CODEX_HOOK_UNTRUSTED: 'CODEX_HOOK_UNTRUSTED',
241
+ SELFTEST_CUSTOM_PROBE_UNSUPPORTED: 'SELFTEST_CUSTOM_PROBE_UNSUPPORTED',
242
+ DECLARATION_UNCONFIRMED: 'DECLARATION_UNCONFIRMED',
243
+ COCKPIT_NOT_INSTALLED: 'COCKPIT_NOT_INSTALLED',
244
+ COCKPIT_LAUNCHER_UNPROVEN: 'COCKPIT_LAUNCHER_UNPROVEN',
245
+ SIBLING_REMOTE_UNRECORDED: 'SIBLING_REMOTE_UNRECORDED',
246
+ SECRET_FILE_TRACKED: 'SECRET_FILE_TRACKED',
247
+ SIBLING_INSTRUCTIONS_AGENTS_ONLY: 'SIBLING_INSTRUCTIONS_AGENTS_ONLY',
248
+ SIBLING_INSTRUCTIONS_CLAUDE_ONLY: 'SIBLING_INSTRUCTIONS_CLAUDE_ONLY',
249
+ SIBLING_INSTRUCTIONS_UNLINKED: 'SIBLING_INSTRUCTIONS_UNLINKED',
250
+ SIBLING_INSTRUCTIONS_MISSING: 'SIBLING_INSTRUCTIONS_MISSING',
251
+ SIBLING_INSTRUCTIONS_TOOL_ONLY: 'SIBLING_INSTRUCTIONS_TOOL_ONLY',
252
+ GUARD_SEARCH_PATH_RELATIVE: 'GUARD_SEARCH_PATH_RELATIVE',
253
+ SESSION_STACK_RETAINED: 'SESSION_STACK_RETAINED',
254
+ UPGRADE_PACKAGE_MANAGER_UNKNOWN: 'UPGRADE_PACKAGE_MANAGER_UNKNOWN',
255
+ UPGRADE_REGISTRY_UNREACHABLE: 'UPGRADE_REGISTRY_UNREACHABLE',
256
+ UPGRADE_VERSION_INVALID: 'UPGRADE_VERSION_INVALID',
257
+ UPGRADE_ALREADY_CURRENT: 'UPGRADE_ALREADY_CURRENT',
258
+ UPGRADE_INSTALL_FAILED: 'UPGRADE_INSTALL_FAILED',
259
+ UPGRADE_SYNC_FAILED: 'UPGRADE_SYNC_FAILED',
260
+ DATA_SEED_FAILED: 'DATA_SEED_FAILED',
261
+ DATA_SEED_UNAVAILABLE: 'DATA_SEED_UNAVAILABLE',
262
+ });
263
+ export const EXECUTION_FAILURE_CODES = Object.freeze([
264
+ ENVIRONMENT_CODES.EXECUTION_SPAWN_FAILED,
265
+ ENVIRONMENT_CODES.EXECUTION_PRECONDITION_CHANGED,
266
+ ENVIRONMENT_CODES.EXECUTION_STAGING_FAILED,
267
+ ENVIRONMENT_CODES.EXECUTION_STAGING_CLEANUP_FAILED,
268
+ ENVIRONMENT_CODES.EXECUTION_TIMEOUT,
269
+ ENVIRONMENT_CODES.EXECUTION_STDOUT_LIMIT,
270
+ ENVIRONMENT_CODES.EXECUTION_STDERR_LIMIT,
271
+ ENVIRONMENT_CODES.EXECUTION_STEP_FAILED,
272
+ ENVIRONMENT_CODES.EXECUTION_ABORTED,
273
+ ENVIRONMENT_CODES.EXECUTION_TERMINATION_UNCONFIRMED,
274
+ ]);
275
+ export const REFUSAL_CODES = Object.freeze([
276
+ ENVIRONMENT_CODES.CONFIG_NOT_FOUND,
277
+ ENVIRONMENT_CODES.CONFIG_UNREADABLE,
278
+ ENVIRONMENT_CODES.CONFIG_ENCODING_INVALID,
279
+ ENVIRONMENT_CODES.CONFIG_PARSE_INVALID,
280
+ ENVIRONMENT_CODES.CONFIG_SCHEMA_INVALID,
281
+ ENVIRONMENT_CODES.STATE_ROOT_UNAVAILABLE,
282
+ ENVIRONMENT_CODES.STATE_FORMAT_UNSUPPORTED,
283
+ ENVIRONMENT_CODES.STATE_RECORD_MALFORMED,
284
+ ENVIRONMENT_CODES.STATE_LOCKED,
285
+ ENVIRONMENT_CODES.STATE_DURABILITY_INDETERMINATE,
286
+ ENVIRONMENT_CODES.SETUP_CONFIG_REQUIRED,
287
+ ENVIRONMENT_CODES.SETUP_OPTION_DUPLICATE,
288
+ ENVIRONMENT_CODES.SETUP_POSITIONAL_UNSUPPORTED,
289
+ ENVIRONMENT_CODES.SETUP_PATH_OUTSIDE_ROOT,
290
+ ENVIRONMENT_CODES.SETUP_PATH_SYMLINK,
291
+ ENVIRONMENT_CODES.SETUP_PATH_TYPE_INVALID,
292
+ ENVIRONMENT_CODES.SETUP_PARENT_MISSING,
293
+ ENVIRONMENT_CODES.SETUP_REMOTE_MISMATCH,
294
+ ENVIRONMENT_CODES.SETUP_REMOTE_UNRESOLVABLE,
295
+ ENVIRONMENT_CODES.SETUP_MANUAL_MISSING,
296
+ ENVIRONMENT_CODES.SETUP_CLONE_FAILED,
297
+ ENVIRONMENT_CODES.SETUP_POSTCHECK_FAILED,
298
+ ENVIRONMENT_CODES.SETUP_INSTRUCTION_POINTER_INVALID,
299
+ ENVIRONMENT_CODES.SETUP_INSTRUCTION_FILES_INVALID,
300
+ ENVIRONMENT_CODES.CONFIG_CHANGED_DURING_EXECUTION,
301
+ ...EXECUTION_FAILURE_CODES,
302
+ ENVIRONMENT_CODES.EXECUTION_COMPENSATION_TIMEOUT,
303
+ ENVIRONMENT_CODES.EXECUTION_COMPENSATION_STEP_FAILED,
304
+ ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID,
305
+ ENVIRONMENT_CODES.LIFECYCLE_PROGRESS_INVALID,
306
+ ENVIRONMENT_CODES.STACK_RECORDED_UNDER_EARLIER_NAME,
307
+ ENVIRONMENT_CODES.PORT_FAMILY_COLLISION,
308
+ ENVIRONMENT_CODES.PORT_LISTENER_EVIDENCE_INVALID,
309
+ ENVIRONMENT_CODES.PORT_FAMILY_OUT_OF_RANGE,
310
+ ENVIRONMENT_CODES.PORT_LEASE_EXHAUSTED,
311
+ ENVIRONMENT_CODES.CLAIM_CO_TENANT,
312
+ ENVIRONMENT_CODES.CLAIM_LIVENESS_UNKNOWN,
313
+ ENVIRONMENT_CODES.DRAIN_ATTEMPT_REPAIR_REQUIRED,
314
+ ENVIRONMENT_CODES.INSTALL_POLICY_OBSERVATION_UNAVAILABLE,
315
+ ENVIRONMENT_CODES.INSTALL_POLICY_OBSERVATION_INVALID,
316
+ ENVIRONMENT_CODES.INSTALL_POLICY_MISSING,
317
+ ENVIRONMENT_CODES.INSTALL_POLICY_AMBIGUOUS,
318
+ ENVIRONMENT_CODES.TEMPLATE_NOT_FOUND,
319
+ ENVIRONMENT_CODES.TEMPLATE_NOT_TRACKED,
320
+ ENVIRONMENT_CODES.TEMPLATE_IGNORED,
321
+ ENVIRONMENT_CODES.TEMPLATE_PATH_OUTSIDE_ROOT,
322
+ ENVIRONMENT_CODES.ENVIRONMENT_FILE_NOT_FOUND,
323
+ ENVIRONMENT_CODES.ENVIRONMENT_FILE_UNREADABLE,
324
+ ENVIRONMENT_CODES.ENVIRONMENT_FILE_TOO_LARGE,
325
+ ENVIRONMENT_CODES.ENVIRONMENT_FILE_MALFORMED,
326
+ ENVIRONMENT_CODES.INSTANCE_NOT_IGNORED,
327
+ ENVIRONMENT_CODES.ENVIRONMENT_SEED_PRECONDITION_CHANGED,
328
+ ENVIRONMENT_CODES.ENVIRONMENT_SEED_FAILED,
329
+ ENVIRONMENT_CODES.RUNTIME_UNAVAILABLE,
330
+ ENVIRONMENT_CODES.RUNTIME_IMAGE_UNAVAILABLE,
331
+ ENVIRONMENT_CODES.RUNTIME_UNMEASURED,
332
+ ENVIRONMENT_CODES.RUNTIME_COMPOSE_REMOTE,
333
+ ENVIRONMENT_CODES.RUNTIME_PROBE_TIMEOUT,
334
+ ENVIRONMENT_CODES.RESET_CONFIRMATION_REQUIRED,
335
+ ENVIRONMENT_CODES.RESET_CONFIRMATION_MISMATCH,
336
+ ENVIRONMENT_CODES.RESET_CO_TENANT,
337
+ ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE,
338
+ ENVIRONMENT_CODES.RECLAIM_LABEL_ESCAPE,
339
+ ENVIRONMENT_CODES.RECLAIM_ACCOUNTING_MISMATCH,
340
+ ENVIRONMENT_CODES.DOWN_RESOURCES_KEPT,
341
+ ENVIRONMENT_CODES.GIT_COMPARISON_REMOTE_MISMATCH,
342
+ ]);
343
+ // A refusal cockpit itself words. Its message is cockpit-authored text (fixed wording, paths and
344
+ // identifiers, never parsed bytes or a child's output), so errorCause surfaces it.
345
+ export class RefusalError extends Error {
346
+ }
347
+ // A refusal names its cause in one bounded line. A RefusalError is cockpit's own wording, and a system
348
+ // error (errno code plus syscall) carries only the operation and the path, so their first line is
349
+ // surfaced. Any other message can echo the bytes being parsed or a child's output, environment-file
350
+ // values among them, so only its class is named. Only own data properties are read: a thrown value can
351
+ // be hostile, and describing it must not throw again. A RefusalError gets the wider bound because its
352
+ // wording often ends in the command that fixes it, which a cut would drop.
353
+ export function errorCause(error) {
354
+ if (isProxy(error) || !(error instanceof Error))
355
+ return 'a non-error value was thrown';
356
+ const own = (key) => Object.getOwnPropertyDescriptor(error, key)?.value;
357
+ const message = own('message');
358
+ if (typeof message === 'string') {
359
+ const line = message.split(/\r?\n|\r/, 1)[0];
360
+ if (error instanceof RefusalError)
361
+ return line.slice(0, OBSERVATION_REASON_BYTE_LIMIT);
362
+ if (typeof own('code') === 'string' && typeof own('syscall') === 'string')
363
+ return line.slice(0, 240);
364
+ }
365
+ return error instanceof TypeError ? 'TypeError' : error instanceof SyntaxError ? 'SyntaxError'
366
+ : error instanceof RangeError ? 'RangeError' : 'Error';
367
+ }
368
+ // A JSON.parse error quotes the bytes where parsing stopped, and a refusal reaches an agent that may
369
+ // not read that file; name the subject, where parsing stopped and the shape expected, never the bytes.
370
+ export function parseJsonText(text, subject, expected) {
371
+ try {
372
+ return { value: JSON.parse(text) };
373
+ }
374
+ catch (error) {
375
+ if (!(error instanceof SyntaxError))
376
+ throw error;
377
+ const position = Number(/\bposition (\d+)\b/.exec(error.message)?.[1]);
378
+ const before = Number.isSafeInteger(position) ? text.slice(0, position) : undefined;
379
+ const where = before === undefined ? '' : ` at line ${before.split('\n').length}, column ${before.length - before.lastIndexOf('\n')}`;
380
+ return { refusal: `${subject} is not valid JSON${where}; expected ${expected}` };
381
+ }
382
+ }
383
+ // For callers that refuse malformed input in their own words: unparseable text is undefined, and the
384
+ // parser's message, which quotes the bytes, is never read.
385
+ export function tryParseJson(text) {
386
+ try {
387
+ return JSON.parse(text);
388
+ }
389
+ catch (error) {
390
+ if (!(error instanceof SyntaxError))
391
+ throw error;
392
+ return undefined;
393
+ }
394
+ }
395
+ export function hasErrorCode(error, ...codes) {
396
+ if (isProxy(error) || !(error instanceof Error))
397
+ return false;
398
+ const code = Object.getOwnPropertyDescriptor(error, 'code')?.value;
399
+ return typeof code === 'string' && codes.includes(code);
400
+ }
401
+ export function isMissing(error) {
402
+ return hasErrorCode(error, 'ENOENT', 'ENOTDIR');
403
+ }
404
+ const canonicalTimestamp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
405
+ export function isCanonicalTimestamp(value) {
406
+ if (typeof value !== 'string' || !canonicalTimestamp.test(value))
407
+ return false;
408
+ const milliseconds = Date.parse(value);
409
+ return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === value;
410
+ }
411
+ // Device and inode alone do not name an object over time: ext4 hands the inode number a removal
412
+ // just freed to the next object created, so a path removed and recreated between planning and
413
+ // execution reproduces the recorded pair exactly. Birth time is fixed at creation, so it tells the
414
+ // replacement apart while still admitting the content changes a cache or its parent legitimately
415
+ // sees between planning and removal; change time would refuse those. A filesystem that records no
416
+ // birth time reports 0 for both objects, and the comparison falls back to device and inode, which
417
+ // leaves in-place recreation undetectable there.
418
+ export function filesystemObjectIdentity(status) {
419
+ return { dev: Number(status.dev), ino: Number(status.ino), birthtimeNs: String(status.birthtimeNs) };
420
+ }
421
+ export function sameFilesystemObject(status, recorded) {
422
+ return Number(status.dev) === recorded.dev && Number(status.ino) === recorded.ino
423
+ && String(status.birthtimeNs) === recorded.birthtimeNs;
424
+ }
425
+ export function isFilesystemObjectIdentity(value) {
426
+ return Number.isSafeInteger(value.dev) && value.dev >= 0
427
+ && Number.isSafeInteger(value.ino) && value.ino >= 0
428
+ && typeof value.birthtimeNs === 'string' && /^(0|-?[1-9][0-9]{0,19})$/.test(value.birthtimeNs);
429
+ }
430
+ function stringTuple(value) {
431
+ return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === 'string' && !item.includes('\0'));
432
+ }
433
+ function stringRecord(value) {
434
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
435
+ && Object.entries(value).every(([name, item]) => name.length > 0 && !name.includes('\0') && !name.includes('=')
436
+ && typeof item === 'string' && !item.includes('\0'));
437
+ }
438
+ function canonicalPaths(value) {
439
+ return Array.isArray(value) && new Set(value).size === value.length
440
+ && value.every((path) => typeof path === 'string' && isAbsolute(path) && normalize(path) === path && !path.includes('\0'));
441
+ }
442
+ function filesystemChecks(value) {
443
+ return Array.isArray(value) && value.every((candidate) => {
444
+ if (candidate === null || typeof candidate !== 'object')
445
+ return false;
446
+ const check = candidate;
447
+ const identity = check.identity;
448
+ const identityIsValid = identity === undefined || identity !== null && typeof identity === 'object'
449
+ && exactKeys(identity, ['dev', 'ino', 'birthtimeNs', 'ancestors'])
450
+ && isFilesystemObjectIdentity(identity)
451
+ && Array.isArray(identity.ancestors) && identity.ancestors.length >= 1 && identity.ancestors.length <= 64
452
+ && new Set(identity.ancestors.map((ancestor) => ancestor?.path)).size === identity.ancestors.length
453
+ && identity.ancestors.every((ancestor, index) => ancestor !== null && typeof ancestor === 'object'
454
+ && exactKeys(ancestor, ['path', 'dev', 'ino', 'birthtimeNs']) && canonicalPaths([ancestor.path])
455
+ && isFilesystemObjectIdentity(ancestor)
456
+ && (index === 0 || dirname(ancestor.path) === identity.ancestors[index - 1].path))
457
+ && typeof check.path === 'string' && dirname(check.path) === identity.ancestors.at(-1).path;
458
+ const keys = ['path', 'expected', ...(check.sha256 === undefined ? [] : ['sha256', 'maxBytes']), ...(identity === undefined ? [] : ['identity'])];
459
+ return exactKeys(candidate, keys)
460
+ && canonicalPaths([check.path]) && (check.expected === 'absent' || check.expected === 'directory' || check.expected === 'file')
461
+ && (check.sha256 === undefined
462
+ ? check.maxBytes === undefined
463
+ : check.expected === 'file' && typeof check.sha256 === 'string' && /^[a-f0-9]{64}$/.test(check.sha256)
464
+ && Number.isSafeInteger(check.maxBytes) && check.maxBytes >= 1 && check.maxBytes <= 536_870_912)
465
+ && identityIsValid && (identity === undefined || check.expected !== 'absent');
466
+ });
467
+ }
468
+ function consumedFiles(value, argv) {
469
+ if (!Array.isArray(value))
470
+ return false;
471
+ const paths = new Set();
472
+ const indexes = new Set();
473
+ let executableCount = 0;
474
+ for (const candidate of value) {
475
+ if (candidate === null || typeof candidate !== 'object')
476
+ return false;
477
+ const file = candidate;
478
+ if (!exactKeys(candidate, file.executable
479
+ ? ['path', 'sha256', 'maxBytes', 'argvIndexes', 'executable', 'executionMode']
480
+ : ['path', 'sha256', 'maxBytes', 'argvIndexes', 'executable']) || !canonicalPaths([file.path])
481
+ || typeof file.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(file.sha256) || !Array.isArray(file.argvIndexes)
482
+ || !Number.isSafeInteger(file.maxBytes) || file.maxBytes < 1 || file.maxBytes > 536_870_912
483
+ || file.argvIndexes.length === 0 || typeof file.executable !== 'boolean' || paths.has(file.path)
484
+ || (file.executable && file.executionMode !== 'verified-path'))
485
+ return false;
486
+ paths.add(file.path);
487
+ if (file.executable)
488
+ executableCount += 1;
489
+ for (const index of file.argvIndexes) {
490
+ if (!Number.isSafeInteger(index) || index < 0 || index >= argv.length || indexes.has(index)
491
+ || argv[index] !== file.path || (index === 0) !== file.executable)
492
+ return false;
493
+ indexes.add(index);
494
+ }
495
+ }
496
+ return value.length === 0 || executableCount === 1;
497
+ }
498
+ function expectedObservations(value) {
499
+ return Array.isArray(value) && value.every((candidate) => {
500
+ if (candidate === null || typeof candidate !== 'object')
501
+ return false;
502
+ const expected = candidate;
503
+ if (expected.kind === 'path')
504
+ return exactKeys(candidate, ['kind', 'target', 'state']) && canonicalPaths([expected.target])
505
+ && ['absent', 'directory', 'repository'].includes(expected.state);
506
+ return expected.kind === 'remote' && exactKeys(candidate, ['kind', 'target', 'name', 'url']) && canonicalPaths([expected.target])
507
+ && typeof expected.name === 'string' && expected.name.length > 0 && !expected.name.includes('\0')
508
+ && typeof expected.url === 'string' && expected.url.length > 0 && !expected.url.includes('\0');
509
+ });
510
+ }
511
+ // Product test stages declare up to two hours; every other owner bounds its steps far lower itself.
512
+ export const MAX_STEP_TIMEOUT_MS = 7_200_000;
513
+ function executionStepSnapshot(snapshot, traversal) {
514
+ if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot))
515
+ return undefined;
516
+ const item = snapshot;
517
+ const baseKeys = ['id', 'argv', 'argv0', 'cwd', 'env', 'timeoutMs', 'stdoutLimitBytes', 'stderrLimitBytes', 'paths', 'ports', 'labels', 'expected', 'consumedFiles', 'filesystemChecks', 'compensation'];
518
+ const optionalKeys = [item.spawnNotAfter === undefined ? undefined : 'spawnNotAfter', item.executionFence === undefined ? undefined : 'executionFence',
519
+ item.outputOverflow === undefined ? undefined : 'outputOverflow', item.failureOutput === undefined ? undefined : 'failureOutput']
520
+ .filter((key) => key !== undefined);
521
+ if (!exactKeys(snapshot, [...baseKeys, ...optionalKeys])
522
+ || typeof item.id !== 'string' || item.id.length === 0 || item.id.includes('\0') || traversal.count >= 256
523
+ || traversal.ids.has(item.id) || !stringTuple(item.argv) || typeof item.argv0 !== 'string' || item.argv0.length === 0 || item.argv0.includes('\0')
524
+ || item.argv[0].length === 0 || !canonicalPaths([item.cwd]) || !stringRecord(item.env)
525
+ || !Number.isSafeInteger(item.timeoutMs) || item.timeoutMs <= 0 || item.timeoutMs > MAX_STEP_TIMEOUT_MS
526
+ || item.outputOverflow !== undefined && item.outputOverflow !== 'retain-tail'
527
+ || item.failureOutput !== undefined && item.failureOutput !== 'stderr-tail'
528
+ || item.spawnNotAfter !== undefined && (!isCanonicalTimestamp(item.spawnNotAfter) || !Number.isFinite(Date.parse(item.spawnNotAfter)))
529
+ || !Number.isSafeInteger(item.stdoutLimitBytes) || item.stdoutLimitBytes < 0 || item.stdoutLimitBytes > 16_777_216
530
+ || !Number.isSafeInteger(item.stderrLimitBytes) || item.stderrLimitBytes < 0 || item.stderrLimitBytes > 16_777_216 || !canonicalPaths(item.paths)
531
+ || !Array.isArray(item.ports) || new Set(item.ports).size !== item.ports.length || item.ports.some((port) => !Number.isSafeInteger(port) || port < 1 || port > 65_535)
532
+ || !stringRecord(item.labels) || !expectedObservations(item.expected) || !consumedFiles(item.consumedFiles, item.argv)
533
+ || !filesystemChecks(item.filesystemChecks) || item.filesystemChecks.some((check) => item.consumedFiles.some((file) => file.path === check.path))
534
+ || item.executionFence !== undefined && (!exactKeys(item.executionFence, ['attemptId', 'markerPath', 'socketPath'])
535
+ || typeof item.executionFence.attemptId !== 'string' || !/^[a-f0-9]{64}$/.test(item.executionFence.attemptId)
536
+ || !canonicalPaths([item.executionFence.markerPath, item.executionFence.socketPath])
537
+ || item.executionFence.markerPath === item.executionFence.socketPath || Buffer.byteLength(item.executionFence.socketPath) > 103)
538
+ || !Array.isArray(item.compensation) || item.argv.length > 1_024 || Object.keys(item.env).length > 1_024 || Object.keys(item.labels).length > 1_024
539
+ || item.paths.length > 1_024 || item.ports.length > 1_024 || item.expected.length > 1_024
540
+ || item.consumedFiles.length > 1_024 || item.filesystemChecks.length > 1_024 || item.compensation.length > 1_024)
541
+ return undefined;
542
+ traversal.count += 1;
543
+ traversal.ids.add(item.id);
544
+ if (item.compensation.some((step) => executionStepSnapshot(step, traversal) === undefined))
545
+ return undefined;
546
+ return item;
547
+ }
548
+ export function snapshotExecutionStep(value) {
549
+ return executionStepSnapshot(snapshotJson(value), { count: 0, ids: new Set() });
550
+ }
551
+ export function snapshotExecutionPlan(value) {
552
+ const snapshot = snapshotJson(value);
553
+ if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot) || !exactKeys(snapshot, ['steps']))
554
+ return undefined;
555
+ const plan = snapshot;
556
+ const traversal = { count: 0, ids: new Set() };
557
+ return Array.isArray(plan.steps) && plan.steps.length <= 256
558
+ && plan.steps.every((step) => executionStepSnapshot(step, traversal) !== undefined) ? plan : undefined;
559
+ }
560
+ export function snapshotLifecyclePlan(value) {
561
+ const snapshot = snapshotJsonWithEntryLimit(value, 16_384);
562
+ if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot)
563
+ || !exactKeys(snapshot, ['verb', 'progress', 'steps', 'resumeBoundary', 'compensation', 'diagnostics']))
564
+ return undefined;
565
+ const plan = snapshot;
566
+ if (!['up', 'sleep', 'down', 'reset'].includes(plan.verb))
567
+ return undefined;
568
+ const progress = plan.progress;
569
+ if (progress === null || typeof progress !== 'object' || Array.isArray(progress)
570
+ || !exactKeys(progress, ['workBasisSha256', 'operationGeneration', 'completedServices'])
571
+ || typeof progress.workBasisSha256 !== 'string' || !/^[a-f0-9]{64}$/.test(progress.workBasisSha256)
572
+ || typeof progress.operationGeneration !== 'string' || !/^[a-f0-9]{64}$/.test(progress.operationGeneration)
573
+ || !Array.isArray(progress.completedServices) || progress.completedServices.length > 4_096)
574
+ return undefined;
575
+ const completedServices = new Set();
576
+ for (const completed of progress.completedServices) {
577
+ if (completed === null || typeof completed !== 'object' || Array.isArray(completed)
578
+ || !exactKeys(completed, ['service', 'containerId'])
579
+ || typeof completed.service !== 'string' || !/^[a-z0-9][a-z0-9_.-]*$/.test(completed.service)
580
+ || typeof completed.containerId !== 'string' || !/^[a-f0-9]{64}$/.test(completed.containerId)
581
+ || completedServices.has(completed.service))
582
+ return undefined;
583
+ completedServices.add(completed.service);
584
+ }
585
+ const stepIds = new Set();
586
+ const plannedServices = new Set();
587
+ const entrypointNames = new Set();
588
+ const captureStep = (candidate) => {
589
+ if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate))
590
+ return false;
591
+ const step = candidate;
592
+ if (typeof step.id !== 'string' || step.id.length === 0 || Buffer.byteLength(step.id) > 512 || step.id.includes('\0')
593
+ || typeof step.kind !== 'string' || stepIds.has(step.id))
594
+ return false;
595
+ let valid = false;
596
+ if (step.kind === 'preflight') {
597
+ valid = exactKeys(candidate, ['id', 'kind']);
598
+ }
599
+ else if (step.kind === 'claim') {
600
+ valid = exactKeys(candidate, ['id', 'kind', 'action']) && (step.action === 'acquire' || step.action === 'release');
601
+ }
602
+ else if (step.kind === 'prepare') {
603
+ valid = exactKeys(candidate, ['id', 'kind', 'execution']) && snapshotExecutionStep(step.execution) !== undefined;
604
+ }
605
+ else if (step.kind === 'service') {
606
+ const service = step.service;
607
+ if (typeof service !== 'string')
608
+ return false;
609
+ valid = exactKeys(candidate, ['id', 'kind', 'service'])
610
+ && /^[a-z0-9][a-z0-9_.-]*$/.test(service)
611
+ && plannedServices.size < 4_096 && !plannedServices.has(service);
612
+ if (valid)
613
+ plannedServices.add(service);
614
+ }
615
+ else if (step.kind === 'publish-entrypoints') {
616
+ if (!exactKeys(candidate, ['id', 'kind', 'values']) || !Array.isArray(step.values) || step.values.length > 4_096)
617
+ return false;
618
+ valid = step.values.every((entrypoint) => {
619
+ if (entrypoint === null || typeof entrypoint !== 'object' || Array.isArray(entrypoint)
620
+ || !exactKeys(entrypoint, ['name', 'kind', 'port', 'value']))
621
+ return false;
622
+ const value = entrypoint;
623
+ if (typeof value.name !== 'string' || !/^[a-z0-9][a-z0-9-]*$/.test(value.name)
624
+ || entrypointNames.has(value.name) || !isEntrypointKind(value.kind)
625
+ || typeof value.port !== 'string' || !/^[A-Z][A-Z0-9_]*$/.test(value.port)
626
+ || !boundedContractText(value.value, 4_096))
627
+ return false;
628
+ entrypointNames.add(value.name);
629
+ return true;
630
+ });
631
+ }
632
+ if (!valid)
633
+ return false;
634
+ stepIds.add(step.id);
635
+ return true;
636
+ };
637
+ const captureSteps = (steps) => {
638
+ if (!Array.isArray(steps) || steps.length > 16_384)
639
+ return false;
640
+ return steps.every(captureStep);
641
+ };
642
+ if (!captureSteps(plan.steps) || !Array.isArray(plan.compensation) || plan.compensation.length > 256
643
+ || !plan.compensation.every((candidate) => {
644
+ if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)
645
+ || !exactKeys(candidate, ['step', 'ownership']))
646
+ return false;
647
+ const item = candidate;
648
+ const ownership = item.ownership;
649
+ return captureStep(item.step) && item.step.kind === 'claim' && item.step.action === 'release'
650
+ && ownership !== null && typeof ownership === 'object'
651
+ && !Array.isArray(ownership) && exactKeys(ownership, ['stackId', 'holderId', 'recordRevision', 'change'])
652
+ && typeof ownership.stackId === 'string' && /^stack:[a-f0-9]{64}$/.test(ownership.stackId)
653
+ && typeof ownership.holderId === 'string' && /^holder:[a-f0-9]{64}:session$/.test(ownership.holderId)
654
+ && Number.isSafeInteger(ownership.recordRevision) && ownership.recordRevision >= 0 && ownership.change === 'acquired';
655
+ }))
656
+ return undefined;
657
+ const boundary = plan.resumeBoundary;
658
+ if (boundary === null || typeof boundary !== 'object' || Array.isArray(boundary)
659
+ || !exactKeys(boundary, ['completedStepIds', 'nextStepId']) || !Array.isArray(boundary.completedStepIds)
660
+ || boundary.completedStepIds.length > 16_384 || new Set(boundary.completedStepIds).size !== boundary.completedStepIds.length
661
+ || boundary.completedStepIds.some((id) => typeof id !== 'string' || id.length === 0 || Buffer.byteLength(id) > 512 || !stepIds.has(id))
662
+ || boundary.nextStepId !== null && (typeof boundary.nextStepId !== 'string' || boundary.nextStepId.length === 0 || Buffer.byteLength(boundary.nextStepId) > 512 || !stepIds.has(boundary.nextStepId))
663
+ || boundary.completedStepIds.some((id, index) => plan.steps[index]?.id !== id)
664
+ || boundary.nextStepId !== (plan.steps[boundary.completedStepIds.length]?.id ?? null)
665
+ || !Array.isArray(plan.diagnostics) || plan.diagnostics.length > 256
666
+ || !plan.diagnostics.every((candidate) => {
667
+ if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate))
668
+ return false;
669
+ const item = candidate;
670
+ const keys = ['severity', 'code', 'message', ...(item.target === undefined ? [] : ['target']), ...(item.fix === undefined ? [] : ['fix'])];
671
+ return exactKeys(candidate, keys) && ['error', 'warning', 'info'].includes(item.severity)
672
+ && Object.values(ENVIRONMENT_CODES).includes(item.code) && boundedContractText(item.message, 4_096)
673
+ && (item.target === undefined || boundedContractText(item.target, 4_096))
674
+ && (item.fix === undefined || boundedContractText(item.fix, 4_096));
675
+ }))
676
+ return undefined;
677
+ const completedPlanServices = plan.steps.slice(0, boundary.completedStepIds.length)
678
+ .filter((step) => step.kind === 'service');
679
+ if (progress.completedServices.length !== completedPlanServices.length
680
+ || progress.completedServices.some((completed, index) => completed.service !== completedPlanServices[index]?.service))
681
+ return undefined;
682
+ return plan;
683
+ }
684
+ function boundedContractText(value, maximum = OBSERVATION_REASON_BYTE_LIMIT) {
685
+ return typeof value === 'string' && value.length > 0 && !value.includes('\0')
686
+ && Buffer.byteLength(value, 'utf8') <= maximum;
687
+ }
688
+ function validExpectation(value) {
689
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
690
+ return false;
691
+ const candidate = value;
692
+ if (candidate.kind === 'present')
693
+ return exactKeys(value, ['kind']);
694
+ if (candidate.kind === 'one-of') {
695
+ return exactKeys(value, ['kind', 'values']) && Array.isArray(candidate.values)
696
+ && candidate.values.length > 0 && candidate.values.length <= 4_096
697
+ && candidate.values.every((item) => snapshotJson(item) !== undefined);
698
+ }
699
+ if (candidate.kind === 'minimum' || candidate.kind === 'maximum') {
700
+ return exactKeys(value, ['kind', 'value']) && Number.isSafeInteger(candidate.value);
701
+ }
702
+ return candidate.kind === 'equal' && exactKeys(value, ['kind', 'value'])
703
+ && snapshotJson(candidate.value) !== undefined;
704
+ }
705
+ export function snapshotEnvironmentObservation(value) {
706
+ const snapshot = snapshotJson(value);
707
+ if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot)
708
+ || !exactKeys(snapshot, ['code', 'owner', 'stackId', 'source', 'observed', 'expectation', 'applicability', 'freshness', 'remedy']))
709
+ return undefined;
710
+ const candidate = snapshot;
711
+ if (!Object.values(ENVIRONMENT_CODES).includes(candidate.code) || !boundedContractText(candidate.owner, OBSERVATION_PRODUCER_BYTE_LIMIT)
712
+ || !/^stack:[a-f0-9]{64}$/.test(candidate.stackId) || !boundedContractText(candidate.source)
713
+ || !boundedContractText(candidate.remedy) || !validExpectation(candidate.expectation))
714
+ return undefined;
715
+ const observed = candidate.observed;
716
+ if (observed === null || typeof observed !== 'object' || Array.isArray(observed)
717
+ || !isCanonicalTimestamp(observed.observedAt))
718
+ return undefined;
719
+ if (observed.state === 'available') {
720
+ if (!exactKeys(observed, ['state', 'value', 'observedAt']) || snapshotJson(observed.value) === undefined)
721
+ return undefined;
722
+ }
723
+ else if ((observed.state === 'unavailable' || observed.state === 'failed')) {
724
+ if (!exactKeys(observed, ['state', 'reason', 'observedAt']) || !boundedContractText(observed.reason))
725
+ return undefined;
726
+ }
727
+ else
728
+ return undefined;
729
+ const applicability = candidate.applicability;
730
+ if (applicability === null || typeof applicability !== 'object' || Array.isArray(applicability)
731
+ || !boundedContractText(applicability.posture, OBSERVATION_PRODUCER_BYTE_LIMIT))
732
+ return undefined;
733
+ if (applicability.state === 'required') {
734
+ if (!exactKeys(applicability, ['state', 'posture']))
735
+ return undefined;
736
+ }
737
+ else if (applicability.state === 'not-applicable') {
738
+ if (!exactKeys(applicability, ['state', 'posture', 'reason']) || !boundedContractText(applicability.reason))
739
+ return undefined;
740
+ }
741
+ else
742
+ return undefined;
743
+ const freshness = candidate.freshness;
744
+ if (freshness === null || typeof freshness !== 'object' || Array.isArray(freshness))
745
+ return undefined;
746
+ if (freshness.state === 'current') {
747
+ if (!exactKeys(freshness, ['state']))
748
+ return undefined;
749
+ }
750
+ else if (freshness.state === 'stale' || freshness.state === 'missing') {
751
+ if (!exactKeys(freshness, ['state', 'reason']) || !boundedContractText(freshness.reason))
752
+ return undefined;
753
+ }
754
+ else
755
+ return undefined;
756
+ return snapshot;
757
+ }
758
+ /** A command refusal carrying the diagnostics an owner raised: exit status 2 and no result. */
759
+ export function forwardedRefusal(diagnostics) {
760
+ return { kind: 'refusal', status: 2, result: null, diagnostics };
761
+ }