@kungfu-tech/buildchain 3.0.9-alpha.8 → 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 (255) 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 -6
  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 -3
  65. package/dist/site/artifact-schemas.json +0 -6
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -270
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -30
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -142
  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 +1882 -4118
  75. package/dist/site/page-registry.json +278 -230
  76. package/dist/site/public-surface-audit.json +87 -185
  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 -7
  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 +80 -35
  83. package/docs/MAP.md +8 -4
  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 -92
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +28 -100
  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 -523
  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 -3
  111. package/package.json +19 -17
  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-config.js +4 -69
  119. package/packages/core/buildchain-contract.js +232 -46
  120. package/packages/core/buildchain-kfd-claims.js +1 -1
  121. package/packages/core/channel-candidate.js +0 -8
  122. package/packages/core/channel-promotion-baseline.js +0 -52
  123. package/packages/core/controller-evidence.js +3 -4
  124. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  125. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  126. package/packages/core/dev-delivery-warrant-settlement.js +1 -5
  127. package/packages/core/dev-delivery-warrant.js +12 -52
  128. package/packages/core/diagnostics.js +3 -8
  129. package/packages/core/github-governance-authority.js +3 -1
  130. package/packages/core/kfd-adopter-category-driver.js +167 -0
  131. package/packages/core/kfd-adopter-manifest.js +47 -46
  132. package/packages/core/kfd-gate.js +15 -45
  133. package/packages/core/paper-agent-entry.js +7 -16
  134. package/packages/core/paper-fleet.js +2 -2
  135. package/packages/core/paper-repository.js +2 -3
  136. package/packages/core/paper-scaffold-content.js +2 -23
  137. package/packages/core/paper.js +11 -43
  138. package/packages/core/publication-reproducibility.js +4 -4
  139. package/packages/core/release-line-bootstrap.js +21 -8
  140. package/packages/core/release-passport-contract.js +5 -5
  141. package/packages/core/release-passport.js +20 -131
  142. package/packages/core/self-dogfood-version.js +48 -35
  143. package/packages/core/spawn-command.js +232 -8
  144. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  145. package/packages/core/v4-canonical-contracts.js +284 -0
  146. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  147. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  148. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  149. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  150. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  151. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  152. package/packages/core/v4-provider-operation-journal.js +531 -0
  153. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  154. package/packages/core/v4-release-activation-shadow.js +519 -0
  155. package/packages/core/v4-stable-publication-fence.js +357 -0
  156. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  157. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  158. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  159. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  160. package/packages/core/v4-stage-capsule-store.js +401 -0
  161. package/packages/core/v4-stage-capsule.js +319 -0
  162. package/scripts/assemble-self-publication-admission.mjs +1 -1
  163. package/scripts/audit-publication-control-plane.mjs +5 -5
  164. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  165. package/scripts/auditable-demo-platform.mjs +2 -2
  166. package/scripts/auditable-demo-renditions.mjs +1 -1
  167. package/scripts/auditable-demo.mjs +2 -2
  168. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  169. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  170. package/scripts/aws-macos-jit-controller.mjs +37 -275
  171. package/scripts/aws-macos-jit-core.mjs +3 -41
  172. package/scripts/aws-macos-jit.mjs +0 -12
  173. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  174. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  175. package/scripts/aws-windows-jit-controller.mjs +3 -3
  176. package/scripts/build-contract-core.mjs +3 -8
  177. package/scripts/build-standalone-binary.mjs +3 -14
  178. package/scripts/buildchain-channel-router.mjs +4 -0
  179. package/scripts/buildchain-cli-help.mjs +7 -13
  180. package/scripts/buildchain-contract-lock.mjs +0 -6
  181. package/scripts/check-action-bundles.mjs +3 -4
  182. package/scripts/check-internal-architecture.mjs +7 -6
  183. package/scripts/check-inventory.mjs +30 -25
  184. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  185. package/scripts/create-release-bundle.mjs +8 -4
  186. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  187. package/scripts/dev-delivery-proof.mjs +2 -54
  188. package/scripts/dev-delivery-warrant.mjs +59 -77
  189. package/scripts/dev-pr-auto-merge.mjs +4 -30
  190. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  191. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  192. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  193. package/scripts/generate-channel-build-workflow.mjs +54 -24
  194. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  195. package/scripts/generate-site-bundle.mjs +5 -21
  196. package/scripts/git-fetch-process-tree.mjs +34 -1
  197. package/scripts/init-repo.mjs +64 -159
  198. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  199. package/scripts/locked-source-checkout.mjs +3 -4
  200. package/scripts/maintainability-metrics.mjs +8 -2
  201. package/scripts/npm-publish-dry-run.mjs +2 -2
  202. package/scripts/npm-publish-transaction.mjs +2 -2
  203. package/scripts/publication-commit-evidence.mjs +23 -69
  204. package/scripts/release-candidate-resolver.mjs +11 -17
  205. package/scripts/release-tail.mjs +3 -49
  206. package/scripts/resume-from-candidate-run.mjs +9 -123
  207. package/scripts/run-lifecycle-core.mjs +12 -13
  208. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  209. package/scripts/site-capability-metadata.mjs +2 -7
  210. package/scripts/stable-candidate-qualification.mjs +10 -10
  211. package/scripts/v4-architecture.mjs +12 -2
  212. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  213. package/scripts/v4-bridge-evidence.mjs +141 -0
  214. package/scripts/v4-host-adapter.mjs +182 -0
  215. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  216. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  217. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  218. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  219. package/scripts/verify-golden-path.mjs +5 -5
  220. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  221. package/scripts/web-surface-core.mjs +2 -8
  222. package/scripts/workflow-call-contract.mjs +5 -184
  223. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  224. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  225. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  226. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  227. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  228. package/contracts/next-development-request-v1.schema.json +0 -66
  229. package/contracts/next-development-transition-v1.schema.json +0 -292
  230. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  231. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  232. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  233. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  234. package/docs/next-development-transition.md +0 -119
  235. package/docs/publication-rehearsal.md +0 -94
  236. package/packages/core/buildchain-compatibility-proof.js +0 -631
  237. package/packages/core/dev-delivery-native-proof.js +0 -333
  238. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  239. package/packages/core/next-development-candidate-reservation.js +0 -186
  240. package/packages/core/next-development-controller.js +0 -726
  241. package/packages/core/next-development-projection.js +0 -288
  242. package/packages/core/next-development-transition.js +0 -738
  243. package/packages/core/publication-rehearsal-projection.js +0 -173
  244. package/packages/core/publication-rehearsal-runtime.js +0 -921
  245. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  246. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  247. package/scripts/dev-delivery-native-run.mjs +0 -187
  248. package/scripts/dev-delivery-two-phase.mjs +0 -598
  249. package/scripts/generate-next-development-guidance.mjs +0 -49
  250. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  251. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  252. package/scripts/next-development-self-dogfood.mjs +0 -532
  253. package/scripts/next-development-transition.mjs +0 -47
  254. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  255. package/templates/native-dev-delivery.yml +0 -82
@@ -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
+ }