@kungfu-tech/buildchain 3.0.9-alpha.9 → 4.0.0-alpha.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 (262) hide show
  1. package/AGENTS.md +39 -0
  2. package/README.md +17 -13
  3. package/actions/promote-buildchain-ref/README.md +0 -10
  4. package/actions/release-tail/README.md +6 -10
  5. package/architecture/internal-capabilities.json +502 -0
  6. package/architecture/maintainability-baseline.json +59 -0
  7. package/architecture/maintainability-policy.json +1384 -0
  8. package/architecture/release-tail-contract-inventory.json +587 -0
  9. package/architecture/v3-core-mechanism-inventory.json +1043 -0
  10. package/architecture/v3-core-mechanism-inventory.md +67 -0
  11. package/architecture/v4-adopter-delivery-parity.json +47 -0
  12. package/architecture/v4-architecture-constitution.md +210 -0
  13. package/architecture/v4-bootstrap-authority.json +56 -0
  14. package/architecture/v4-canonical-contract-fixtures.json +105 -0
  15. package/architecture/v4-capability-state-machine-manifest.json +480 -0
  16. package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
  17. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
  18. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
  19. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
  20. package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
  21. package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
  22. package/architecture/v4-exception-ledger.json +5 -0
  23. package/architecture/v4-exception-ledger.schema.json +56 -0
  24. package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
  25. package/architecture/v4-platform-stage-checkpoints.json +97 -0
  26. package/architecture/v4-provider-operation-journal-contract.json +113 -0
  27. package/architecture/v4-release-activation-shadow-domain.json +61 -0
  28. package/architecture/v4-release-train-parity.json +68 -0
  29. package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
  30. package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
  31. package/architecture/v4-stable-publication-fence.json +66 -0
  32. package/architecture/v4-stage-capsule-contract.json +90 -0
  33. package/architecture/v4-stage-capsule-qualification.json +99 -0
  34. package/architecture/v4-stage-capsule-resume-planner.json +52 -0
  35. package/architecture/v4-stage-capsule-store-contract.json +72 -0
  36. package/bin/buildchain.mjs +15 -10
  37. package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
  38. package/contracts/buildchain-v2-residuals-v1.json +2 -2
  39. package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
  40. package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
  41. package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
  42. package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
  43. package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
  44. package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
  45. package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
  46. package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
  47. package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
  48. package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
  49. package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
  50. package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
  51. package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
  52. package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
  53. package/contracts/v4-host-contract-v1.schema.json +135 -0
  54. package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
  55. package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
  56. package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
  57. package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
  58. package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
  59. package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
  60. package/contracts/v4-stage-capsule-v1.schema.json +178 -0
  61. package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
  62. package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
  63. package/crates/buildchain-v4-bridge/src/main.rs +495 -0
  64. package/dist/site/agent-index.json +0 -4
  65. package/dist/site/artifact-schemas.json +0 -8
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -386
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -53
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -167
  72. package/dist/site/kfd-upstream-aggregate.json +9 -9
  73. package/dist/site/manual-registry.json +18 -49
  74. package/dist/site/node-api-registry.json +4345 -7345
  75. package/dist/site/page-registry.json +278 -346
  76. package/dist/site/public-surface-audit.json +85 -404
  77. package/dist/site/publication-authority-registry.json +11 -1
  78. package/dist/site/publication-registry.json +4 -4
  79. package/dist/site/release-provenance.json +3 -9
  80. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  81. package/dist/site/site-manifest.json +22 -38
  82. package/dist/site/workflow-registry.json +78 -35
  83. package/docs/MAP.md +8 -5
  84. package/docs/auditable-demo.md +2 -2
  85. package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
  86. package/docs/cli-reference.md +15 -213
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +29 -194
  90. package/docs/engineering-housekeeper.md +12 -4
  91. package/docs/getting-started.md +1 -1
  92. package/docs/install.md +5 -5
  93. package/docs/kfd-support.md +2 -7
  94. package/docs/lifecycle-protocol.md +2 -4
  95. package/docs/node-api-reference.md +414 -554
  96. package/docs/release-flow.md +31 -31
  97. package/docs/release-governance.md +16 -28
  98. package/docs/release-passport.md +2 -15
  99. package/docs/release-tail-contract.md +13 -6
  100. package/docs/release-tail-provider-plane.md +13 -19
  101. package/docs/release-train.md +4 -4
  102. package/docs/reusable-build-surface.md +14 -27
  103. package/docs/site-bundle-contract.md +1 -5
  104. package/docs/stable-candidate-patrol.md +7 -7
  105. package/docs/v4-canonical-contracts.md +92 -0
  106. package/docs/v4-delivery-warrant-read-candidate.md +73 -0
  107. package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
  108. package/docs/v4-production-release.md +63 -0
  109. package/docs/v4-stage-capsule.md +193 -0
  110. package/docs/versioning.md +3 -5
  111. package/package.json +19 -19
  112. package/packages/core/adopter-delivery-gate.js +576 -0
  113. package/packages/core/adopter-delivery-json.js +66 -0
  114. package/packages/core/artifact-signing.js +0 -61
  115. package/packages/core/artifact-verification-envelope.js +5 -5
  116. package/packages/core/build-facts.js +12 -4
  117. package/packages/core/buildchain-agent-manuals.js +0 -2
  118. package/packages/core/buildchain-channel-identity.js +3 -2
  119. package/packages/core/buildchain-config.js +4 -69
  120. package/packages/core/buildchain-contract.js +232 -46
  121. package/packages/core/buildchain-kfd-claims.js +1 -1
  122. package/packages/core/channel-candidate.js +0 -8
  123. package/packages/core/channel-promotion-baseline.js +0 -52
  124. package/packages/core/controller-evidence.js +3 -4
  125. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  126. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  127. package/packages/core/dev-delivery-warrant-settlement.js +20 -67
  128. package/packages/core/dev-delivery-warrant.js +50 -138
  129. package/packages/core/diagnostics.js +3 -8
  130. package/packages/core/github-governance-authority.js +3 -1
  131. package/packages/core/kfd-adopter-category-driver.js +167 -0
  132. package/packages/core/kfd-adopter-manifest.js +47 -46
  133. package/packages/core/kfd-gate.js +15 -45
  134. package/packages/core/paper-agent-entry.js +7 -16
  135. package/packages/core/paper-fleet.js +2 -2
  136. package/packages/core/paper-repository.js +2 -3
  137. package/packages/core/paper-scaffold-content.js +2 -23
  138. package/packages/core/paper.js +11 -43
  139. package/packages/core/publication-reproducibility.js +4 -4
  140. package/packages/core/release-line-bootstrap.js +21 -8
  141. package/packages/core/release-passport-contract.js +5 -5
  142. package/packages/core/release-passport.js +20 -131
  143. package/packages/core/self-dogfood-version.js +48 -35
  144. package/packages/core/spawn-command.js +232 -8
  145. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  146. package/packages/core/v4-canonical-contracts.js +284 -0
  147. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  149. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  150. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  151. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  152. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  153. package/packages/core/v4-provider-operation-journal.js +531 -0
  154. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  155. package/packages/core/v4-release-activation-shadow.js +519 -0
  156. package/packages/core/v4-stable-publication-fence.js +357 -0
  157. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  158. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  159. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  160. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  161. package/packages/core/v4-stage-capsule-store.js +401 -0
  162. package/packages/core/v4-stage-capsule.js +319 -0
  163. package/scripts/assemble-self-publication-admission.mjs +1 -1
  164. package/scripts/audit-publication-control-plane.mjs +5 -5
  165. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  166. package/scripts/auditable-demo-platform.mjs +2 -2
  167. package/scripts/auditable-demo-renditions.mjs +1 -1
  168. package/scripts/auditable-demo.mjs +2 -2
  169. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  170. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  171. package/scripts/aws-macos-jit-controller.mjs +37 -275
  172. package/scripts/aws-macos-jit-core.mjs +3 -41
  173. package/scripts/aws-macos-jit.mjs +0 -12
  174. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  175. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  176. package/scripts/aws-windows-jit-controller.mjs +3 -3
  177. package/scripts/build-contract-core.mjs +3 -8
  178. package/scripts/build-standalone-binary.mjs +3 -14
  179. package/scripts/buildchain-channel-router.mjs +4 -0
  180. package/scripts/buildchain-cli-help.mjs +7 -16
  181. package/scripts/buildchain-contract-lock.mjs +0 -6
  182. package/scripts/check-action-bundles.mjs +3 -4
  183. package/scripts/check-internal-architecture.mjs +7 -6
  184. package/scripts/check-inventory.mjs +30 -25
  185. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  186. package/scripts/create-release-bundle.mjs +8 -4
  187. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  188. package/scripts/dev-delivery-proof.mjs +2 -64
  189. package/scripts/dev-delivery-warrant.mjs +61 -86
  190. package/scripts/dev-pr-auto-merge.mjs +4 -30
  191. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  192. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  193. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  194. package/scripts/generate-channel-build-workflow.mjs +54 -24
  195. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  196. package/scripts/generate-site-bundle.mjs +8 -27
  197. package/scripts/git-fetch-process-tree.mjs +34 -1
  198. package/scripts/init-repo.mjs +64 -159
  199. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  200. package/scripts/locked-source-checkout.mjs +3 -4
  201. package/scripts/maintainability-metrics.mjs +8 -2
  202. package/scripts/npm-publish-dry-run.mjs +2 -2
  203. package/scripts/npm-publish-transaction.mjs +2 -2
  204. package/scripts/publication-commit-evidence.mjs +23 -69
  205. package/scripts/release-candidate-resolver.mjs +11 -17
  206. package/scripts/release-tail.mjs +3 -49
  207. package/scripts/resume-from-candidate-run.mjs +9 -123
  208. package/scripts/run-lifecycle-core.mjs +12 -13
  209. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  210. package/scripts/site-capability-metadata.mjs +3 -20
  211. package/scripts/stable-candidate-qualification.mjs +10 -10
  212. package/scripts/v4-architecture.mjs +12 -2
  213. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  214. package/scripts/v4-bridge-evidence.mjs +141 -0
  215. package/scripts/v4-host-adapter.mjs +182 -0
  216. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  217. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  218. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  219. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  220. package/scripts/verify-golden-path.mjs +5 -5
  221. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  222. package/scripts/web-surface-core.mjs +2 -8
  223. package/scripts/workflow-call-contract.mjs +5 -184
  224. package/contracts/dev-delivery-authority-v2.schema.json +0 -253
  225. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  226. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  227. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  228. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  229. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  230. package/contracts/next-development-request-v1.schema.json +0 -66
  231. package/contracts/next-development-transition-v1.schema.json +0 -292
  232. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  233. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +0 -442
  234. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  235. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  236. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  237. package/docs/dev-delivery-qualification-landing-adr.md +0 -137
  238. package/docs/next-development-transition.md +0 -119
  239. package/docs/publication-rehearsal.md +0 -94
  240. package/packages/core/buildchain-compatibility-proof.js +0 -631
  241. package/packages/core/dev-delivery-authority.js +0 -996
  242. package/packages/core/dev-delivery-native-proof.js +0 -418
  243. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  244. package/packages/core/next-development-candidate-reservation.js +0 -186
  245. package/packages/core/next-development-controller.js +0 -726
  246. package/packages/core/next-development-projection.js +0 -288
  247. package/packages/core/next-development-transition.js +0 -738
  248. package/packages/core/publication-rehearsal-projection.js +0 -173
  249. package/packages/core/publication-rehearsal-runtime.js +0 -921
  250. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  251. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  252. package/scripts/dev-delivery-authority.mjs +0 -368
  253. package/scripts/dev-delivery-native-run.mjs +0 -235
  254. package/scripts/dev-delivery-two-phase-resume.mjs +0 -90
  255. package/scripts/dev-delivery-two-phase.mjs +0 -577
  256. package/scripts/generate-next-development-guidance.mjs +0 -49
  257. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  258. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  259. package/scripts/next-development-self-dogfood.mjs +0 -532
  260. package/scripts/next-development-transition.mjs +0 -47
  261. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  262. package/templates/native-dev-delivery.yml +0 -86
@@ -0,0 +1,519 @@
1
+ import {
2
+ V4ContractFault,
3
+ v4ContentRoot,
4
+ validateV4Clock,
5
+ validateV4Root,
6
+ } from "./v4-canonical-contracts.js";
7
+ import {
8
+ V4_PROVIDER_OPERATION_ATTEMPT_CONTRACT,
9
+ V4_PROVIDER_OPERATION_CONFIRMATION_CONTRACT,
10
+ V4_PROVIDER_OPERATION_INTENT_CONTRACT,
11
+ V4_PROVIDER_OPERATION_OBSERVATION_CONTRACT,
12
+ V4_PROVIDER_OPERATION_RECONCILIATION_CONTRACT,
13
+ foldV4ProviderOperationJournal,
14
+ v4ProviderOperationEntryRoot,
15
+ v4ProviderOperationJournalRoot,
16
+ v4ProviderOperationJournalStateRoot,
17
+ v4ProviderOperationRoot,
18
+ validateV4ProviderOperationIdentity,
19
+ } from "./v4-provider-operation-journal.js";
20
+
21
+ export const V4_RELEASE_ACTIVATION_REQUEST_CONTRACT =
22
+ "buildchain-v4-release-activation-request/v1";
23
+ export const V4_RELEASE_ACTIVATION_PLAN_CONTRACT =
24
+ "buildchain-v4-release-activation-plan/v1";
25
+ export const V4_RELEASE_ACTIVATION_STATE_CONTRACT =
26
+ "buildchain-v4-release-activation-state/v1";
27
+
28
+ const TOKEN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
29
+
30
+ function fault(code, path, message) {
31
+ throw new V4ContractFault(code, path, message);
32
+ }
33
+
34
+ function exactKeys(value, expected, path) {
35
+ if (!value || typeof value !== "object" || Array.isArray(value))
36
+ fault(
37
+ "invalid-release-activation-shape",
38
+ path,
39
+ `${path} must be an object`,
40
+ );
41
+ const actual = Object.keys(value).sort();
42
+ const canonical = [...expected].sort();
43
+ if (
44
+ actual.length !== canonical.length ||
45
+ actual.some((key, index) => key !== canonical[index])
46
+ )
47
+ fault(
48
+ "invalid-release-activation-shape",
49
+ path,
50
+ `${path} keys do not match the closed activation contract`,
51
+ );
52
+ }
53
+
54
+ function token(value, path) {
55
+ if (typeof value !== "string" || !TOKEN.test(value))
56
+ fault(
57
+ "invalid-release-activation-token",
58
+ path,
59
+ `${path} must be an ASCII token`,
60
+ );
61
+ }
62
+
63
+ function normalizeTokens(values, path) {
64
+ if (!Array.isArray(values))
65
+ fault("invalid-release-activation-shape", path, `${path} must be an array`);
66
+ for (const [index, value] of values.entries())
67
+ token(value, `${path}/${index}`);
68
+ const sorted = [...values].sort();
69
+ if (new Set(sorted).size !== sorted.length)
70
+ fault(
71
+ "duplicate-release-activation-dependency",
72
+ path,
73
+ `${path} must not contain duplicate values`,
74
+ );
75
+ return sorted;
76
+ }
77
+
78
+ function normalizeRoots(values, path) {
79
+ if (!Array.isArray(values) || values.length === 0)
80
+ fault(
81
+ "unrooted-release-activation-observation",
82
+ path,
83
+ `${path} must contain rooted provider-neutral evidence`,
84
+ );
85
+ for (const [index, value] of values.entries())
86
+ validateV4Root(value, `${path}/${index}`);
87
+ const sorted = [...values].sort();
88
+ if (new Set(sorted).size !== sorted.length)
89
+ fault(
90
+ "duplicate-release-activation-observation-root",
91
+ path,
92
+ `${path} must not contain duplicate roots`,
93
+ );
94
+ return sorted;
95
+ }
96
+
97
+ function validateCoordinates(request) {
98
+ validateV4Root(request.transactionRoot, "$/transactionRoot");
99
+ if (request.qualificationRoot === null)
100
+ fault(
101
+ "missing-release-activation-qualification",
102
+ "$/qualificationRoot",
103
+ "release activation requires an explicit qualification root",
104
+ );
105
+ validateV4Root(request.qualificationRoot, "$/qualificationRoot");
106
+ validateV4Root(request.authorityRoot, "$/authorityRoot");
107
+ validateV4Root(request.policyRoot, "$/policyRoot");
108
+ validateV4Clock(request.declaredAt, "$/declaredAt");
109
+ }
110
+
111
+ function normalizeSteps(request) {
112
+ if (!Array.isArray(request.steps) || request.steps.length === 0)
113
+ fault(
114
+ "invalid-release-activation-plan",
115
+ "$/steps",
116
+ "release activation requires at least one step",
117
+ );
118
+ const normalized = request.steps.map((step, index) => {
119
+ const path = `$/steps/${index}`;
120
+ exactKeys(
121
+ step,
122
+ ["id", "dependencies", "operation", "compensationBoundaryRoot"],
123
+ path,
124
+ );
125
+ token(step.id, `${path}/id`);
126
+ validateV4ProviderOperationIdentity(step.operation);
127
+ validateV4Root(
128
+ step.compensationBoundaryRoot,
129
+ `${path}/compensationBoundaryRoot`,
130
+ );
131
+ if (
132
+ step.operation.transactionRoot !== request.transactionRoot ||
133
+ step.operation.authorityRoot !== request.authorityRoot ||
134
+ step.operation.policyRoot !== request.policyRoot
135
+ )
136
+ fault(
137
+ "release-activation-authority-mismatch",
138
+ `${path}/operation`,
139
+ "step operation coordinates must match the qualified activation request",
140
+ );
141
+ const operationRoot = v4ProviderOperationRoot(step.operation);
142
+ const payload = {
143
+ id: step.id,
144
+ dependencies: normalizeTokens(step.dependencies, `${path}/dependencies`),
145
+ operation: structuredClone(step.operation),
146
+ operationRoot,
147
+ compensationBoundaryRoot: step.compensationBoundaryRoot,
148
+ };
149
+ return {
150
+ ...payload,
151
+ stepRoot: v4ContentRoot("release-activation-step", payload),
152
+ };
153
+ });
154
+ normalized.sort((left, right) =>
155
+ left.id < right.id ? -1 : left.id > right.id ? 1 : 0,
156
+ );
157
+ if (new Set(normalized.map(({ id }) => id)).size !== normalized.length)
158
+ fault(
159
+ "duplicate-release-activation-step",
160
+ "$/steps",
161
+ "release activation step ids must be unique",
162
+ );
163
+ if (
164
+ new Set(normalized.map(({ operationRoot }) => operationRoot)).size !==
165
+ normalized.length
166
+ )
167
+ fault(
168
+ "conflicting-release-activation-operation",
169
+ "$/steps",
170
+ "one logical provider operation cannot be owned by multiple activation steps",
171
+ );
172
+ const byId = new Map(normalized.map((step) => [step.id, step]));
173
+ for (const step of normalized)
174
+ for (const dependency of step.dependencies)
175
+ if (!byId.has(dependency) || dependency === step.id)
176
+ fault(
177
+ "invalid-release-activation-dependency",
178
+ `$/steps/${step.id}/dependencies`,
179
+ "dependencies must name another declared activation step",
180
+ );
181
+ const visiting = new Set();
182
+ const visited = new Set();
183
+ const visit = (step) => {
184
+ if (visiting.has(step.id))
185
+ fault(
186
+ "release-activation-dependency-cycle",
187
+ `$/steps/${step.id}/dependencies`,
188
+ "release activation dependencies must be acyclic",
189
+ );
190
+ if (visited.has(step.id)) return;
191
+ visiting.add(step.id);
192
+ for (const dependency of step.dependencies) visit(byId.get(dependency));
193
+ visiting.delete(step.id);
194
+ visited.add(step.id);
195
+ };
196
+ for (const step of normalized) visit(step);
197
+ return normalized;
198
+ }
199
+
200
+ function normalizeEvent(event, index, steps) {
201
+ const path = `$/events/${index}`;
202
+ const common = ["kind", "stepId", "ordinal"];
203
+ const specific = {
204
+ attempt: ["attemptedAt", "effectRoot"],
205
+ observation: ["observedAt", "status", "evidenceRoots"],
206
+ reconciliation: ["reconciledAt", "disposition", "authorityRoot"],
207
+ confirmation: ["confirmedAt", "outcome", "authorityRoot"],
208
+ };
209
+ if (!specific[event?.kind])
210
+ fault(
211
+ "invalid-release-activation-event",
212
+ `${path}/kind`,
213
+ "release activation event kind is unsupported",
214
+ );
215
+ exactKeys(event, [...common, ...specific[event.kind]], path);
216
+ token(event.stepId, `${path}/stepId`);
217
+ if (!steps.has(event.stepId))
218
+ fault(
219
+ "invalid-release-activation-event",
220
+ `${path}/stepId`,
221
+ "event must name a declared activation step",
222
+ );
223
+ if (!Number.isSafeInteger(event.ordinal) || event.ordinal < 1)
224
+ fault(
225
+ "invalid-release-activation-ordinal",
226
+ `${path}/ordinal`,
227
+ "event ordinal must be a positive safe integer",
228
+ );
229
+ const normalized = structuredClone(event);
230
+ if (event.kind === "attempt") {
231
+ validateV4Clock(event.attemptedAt, `${path}/attemptedAt`);
232
+ validateV4Root(event.effectRoot, `${path}/effectRoot`);
233
+ } else if (event.kind === "observation") {
234
+ validateV4Clock(event.observedAt, `${path}/observedAt`);
235
+ if (!["succeeded", "failed", "unknown"].includes(event.status))
236
+ fault(
237
+ "invalid-release-activation-observation",
238
+ `${path}/status`,
239
+ "observation status is unsupported",
240
+ );
241
+ normalized.evidenceRoots = normalizeRoots(
242
+ event.evidenceRoots,
243
+ `${path}/evidenceRoots`,
244
+ );
245
+ } else if (event.kind === "reconciliation") {
246
+ validateV4Clock(event.reconciledAt, `${path}/reconciledAt`);
247
+ validateV4Root(event.authorityRoot, `${path}/authorityRoot`);
248
+ if (!["retry", "confirm", "terminal"].includes(event.disposition))
249
+ fault(
250
+ "invalid-release-activation-reconciliation",
251
+ `${path}/disposition`,
252
+ "reconciliation disposition is unsupported",
253
+ );
254
+ } else {
255
+ validateV4Clock(event.confirmedAt, `${path}/confirmedAt`);
256
+ validateV4Root(event.authorityRoot, `${path}/authorityRoot`);
257
+ if (!["confirmed", "rejected"].includes(event.outcome))
258
+ fault(
259
+ "invalid-release-activation-confirmation",
260
+ `${path}/outcome`,
261
+ "confirmation outcome is unsupported",
262
+ );
263
+ }
264
+ if (
265
+ "authorityRoot" in normalized &&
266
+ normalized.authorityRoot !== steps.get(event.stepId).operation.authorityRoot
267
+ )
268
+ fault(
269
+ "release-activation-authority-mismatch",
270
+ `${path}/authorityRoot`,
271
+ "journal authority cannot differ from the planned operation authority",
272
+ );
273
+ return normalized;
274
+ }
275
+
276
+ function normalizeEvents(request, steps) {
277
+ if (!Array.isArray(request.events))
278
+ fault(
279
+ "invalid-release-activation-shape",
280
+ "$/events",
281
+ "events must be an array",
282
+ );
283
+ const unique = new Map();
284
+ for (const [index, event] of request.events.entries()) {
285
+ const normalized = normalizeEvent(event, index, steps);
286
+ const key = `${normalized.stepId}:${normalized.ordinal}`;
287
+ const retained = unique.get(key);
288
+ if (retained && JSON.stringify(retained) !== JSON.stringify(normalized))
289
+ fault(
290
+ "conflicting-release-activation-event",
291
+ `$/events/${index}`,
292
+ "one step ordinal cannot carry conflicting journal facts",
293
+ );
294
+ unique.set(key, retained ?? normalized);
295
+ }
296
+ const events = [...unique.values()].sort((left, right) => {
297
+ if (left.stepId !== right.stepId)
298
+ return left.stepId < right.stepId ? -1 : 1;
299
+ return left.ordinal - right.ordinal;
300
+ });
301
+ const expected = new Map();
302
+ for (const event of events) {
303
+ const ordinal = (expected.get(event.stepId) ?? 0) + 1;
304
+ if (event.ordinal !== ordinal)
305
+ fault(
306
+ "release-activation-event-gap",
307
+ `$/events/${event.stepId}/${event.ordinal}`,
308
+ "deduplicated event ordinals must be contiguous per step",
309
+ );
310
+ expected.set(event.stepId, ordinal);
311
+ }
312
+ return events;
313
+ }
314
+
315
+ function normalizeRequest(request) {
316
+ exactKeys(
317
+ request,
318
+ [
319
+ "schema",
320
+ "declaredAt",
321
+ "transactionRoot",
322
+ "qualificationRoot",
323
+ "authorityRoot",
324
+ "policyRoot",
325
+ "steps",
326
+ "events",
327
+ ],
328
+ "$",
329
+ );
330
+ if (request.schema !== V4_RELEASE_ACTIVATION_REQUEST_CONTRACT)
331
+ fault(
332
+ "unsupported-release-activation-version",
333
+ "$/schema",
334
+ "unsupported release activation request schema",
335
+ );
336
+ validateCoordinates(request);
337
+ const steps = normalizeSteps(request);
338
+ const byId = new Map(steps.map((step) => [step.id, step]));
339
+ return { steps, events: normalizeEvents(request, byId) };
340
+ }
341
+
342
+ export function planV4ReleaseActivation(request) {
343
+ const { steps } = normalizeRequest(request);
344
+ const payload = {
345
+ schema: V4_RELEASE_ACTIVATION_PLAN_CONTRACT,
346
+ mode: "production",
347
+ productionAuthority: "v4",
348
+ declaredAt: request.declaredAt,
349
+ transactionRoot: request.transactionRoot,
350
+ qualificationRoot: request.qualificationRoot,
351
+ authorityRoot: request.authorityRoot,
352
+ policyRoot: request.policyRoot,
353
+ steps,
354
+ };
355
+ return {
356
+ ...payload,
357
+ planRoot: v4ContentRoot("release-activation-plan", payload),
358
+ };
359
+ }
360
+
361
+ function rootedEntry(entry) {
362
+ return { ...entry, entryRoot: v4ProviderOperationEntryRoot(entry) };
363
+ }
364
+
365
+ function materializeJournal(request, step, events) {
366
+ const entries = [];
367
+ const append = (entry) => {
368
+ entries.push(rootedEntry(entry));
369
+ return entries.at(-1);
370
+ };
371
+ append({
372
+ kind: "intent",
373
+ schema: V4_PROVIDER_OPERATION_INTENT_CONTRACT,
374
+ sequence: 0,
375
+ priorEntryRoot: null,
376
+ operation: structuredClone(step.operation),
377
+ operationRoot: step.operationRoot,
378
+ declaredAt: request.declaredAt,
379
+ inputRoot: request.qualificationRoot,
380
+ });
381
+ let attemptOrdinal = 0;
382
+ let attemptRoot = null;
383
+ let observationRoot = null;
384
+ for (const event of events) {
385
+ const common = {
386
+ sequence: entries.length,
387
+ priorEntryRoot: entries.at(-1).entryRoot,
388
+ operationRoot: step.operationRoot,
389
+ };
390
+ if (event.kind === "attempt") {
391
+ attemptOrdinal += 1;
392
+ const entry = append({
393
+ kind: "attempt",
394
+ schema: V4_PROVIDER_OPERATION_ATTEMPT_CONTRACT,
395
+ ...common,
396
+ attemptOrdinal,
397
+ attemptedAt: event.attemptedAt,
398
+ effectRoot: event.effectRoot,
399
+ });
400
+ attemptRoot = entry.entryRoot;
401
+ observationRoot = null;
402
+ } else if (event.kind === "observation") {
403
+ const entry = append({
404
+ kind: "observation",
405
+ schema: V4_PROVIDER_OPERATION_OBSERVATION_CONTRACT,
406
+ ...common,
407
+ attemptRoot: attemptRoot ?? request.qualificationRoot,
408
+ observedAt: event.observedAt,
409
+ status: event.status,
410
+ evidenceRoots: event.evidenceRoots,
411
+ });
412
+ observationRoot = entry.entryRoot;
413
+ } else if (event.kind === "reconciliation") {
414
+ append({
415
+ kind: "reconciliation",
416
+ schema: V4_PROVIDER_OPERATION_RECONCILIATION_CONTRACT,
417
+ ...common,
418
+ observationRoot: observationRoot ?? request.qualificationRoot,
419
+ authorityRoot: event.authorityRoot,
420
+ reconciledAt: event.reconciledAt,
421
+ disposition: event.disposition,
422
+ });
423
+ } else {
424
+ append({
425
+ kind: "confirmation",
426
+ schema: V4_PROVIDER_OPERATION_CONFIRMATION_CONTRACT,
427
+ ...common,
428
+ observationRoot: observationRoot ?? request.qualificationRoot,
429
+ authorityRoot: event.authorityRoot,
430
+ confirmedAt: event.confirmedAt,
431
+ outcome: event.outcome,
432
+ });
433
+ }
434
+ }
435
+ return entries;
436
+ }
437
+
438
+ export function foldV4ReleaseActivation(request) {
439
+ const normalized = normalizeRequest(request);
440
+ const plan = planV4ReleaseActivation(request);
441
+ const events = new Map(normalized.steps.map(({ id }) => [id, []]));
442
+ for (const event of normalized.events) events.get(event.stepId).push(event);
443
+ const confirmed = new Set();
444
+ const failedSteps = [];
445
+ const readbackSteps = [];
446
+ const stepStates = normalized.steps.map((step) => {
447
+ const retained = events.get(step.id);
448
+ if (retained.length === 0)
449
+ return {
450
+ stepId: step.id,
451
+ operationRoot: step.operationRoot,
452
+ phase: "planned",
453
+ journalRoot: null,
454
+ journalStateRoot: null,
455
+ entryCount: 0,
456
+ attemptCount: 0,
457
+ confirmationRoot: null,
458
+ };
459
+ const entries = materializeJournal(request, step, retained);
460
+ const state = foldV4ProviderOperationJournal(entries);
461
+ if (state.phase === "confirmed") confirmed.add(step.id);
462
+ if (["rejected", "terminal"].includes(state.phase))
463
+ failedSteps.push(step.id);
464
+ if (["attempting", "observed", "confirmable"].includes(state.phase))
465
+ readbackSteps.push(step.id);
466
+ return {
467
+ stepId: step.id,
468
+ operationRoot: step.operationRoot,
469
+ phase: state.phase,
470
+ journalRoot: v4ProviderOperationJournalRoot(entries),
471
+ journalStateRoot: v4ProviderOperationJournalStateRoot(entries),
472
+ entryCount: state.entryCount,
473
+ attemptCount: state.attemptCount,
474
+ confirmationRoot: state.confirmationRoot,
475
+ };
476
+ });
477
+ const eligibleSteps =
478
+ failedSteps.length === 0
479
+ ? normalized.steps
480
+ .filter((step, index) => {
481
+ const phase = stepStates[index].phase;
482
+ return (
483
+ ["planned", "intended", "retryable"].includes(phase) &&
484
+ step.dependencies.every((dependency) => confirmed.has(dependency))
485
+ );
486
+ })
487
+ .map(({ id }) => id)
488
+ : [];
489
+ const confirmedSteps = [...confirmed].sort();
490
+ const phase =
491
+ failedSteps.length > 0
492
+ ? "blocked"
493
+ : confirmedSteps.length === normalized.steps.length
494
+ ? "complete"
495
+ : "active";
496
+ const payload = {
497
+ schema: V4_RELEASE_ACTIVATION_STATE_CONTRACT,
498
+ mode: "production",
499
+ productionAuthority: "v4",
500
+ planRoot: plan.planRoot,
501
+ phase,
502
+ stepStates,
503
+ confirmedSteps,
504
+ failedSteps,
505
+ readbackSteps,
506
+ eligibleSteps,
507
+ };
508
+ return {
509
+ ...payload,
510
+ stateRoot: v4ContentRoot("release-activation-state", payload),
511
+ };
512
+ }
513
+
514
+ export function projectV4ReleaseActivation(request) {
515
+ return {
516
+ plan: planV4ReleaseActivation(request),
517
+ state: foldV4ReleaseActivation(request),
518
+ };
519
+ }