@kungfu-tech/buildchain 4.0.2-alpha.8 → 4.0.2
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.
- package/AGENTS.md +10 -1
- package/CONTRIBUTING.md +24 -0
- package/README.md +2 -2
- package/actions/promote-buildchain-ref/README.md +1 -1
- package/actions/v4-release-candidate-promote/README.md +28 -0
- package/architecture/agent-change-map.md +64 -7
- package/architecture/ci-lane-change-budget.json +366 -0
- package/architecture/internal-capabilities.json +53 -8
- package/architecture/maintainability-debt.json +147 -93
- package/architecture/maintainability-policy.json +32 -28
- package/architecture/release-tail-contract-inventory.json +6 -6
- package/architecture/v4-architecture-constitution.md +23 -20
- package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
- package/architecture/v4-delivery-authority-parity.json +2 -2
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
- package/architecture/v4-floating-consumer-policy.json +2 -2
- package/architecture/v4-next-development-parity.json +5 -5
- package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
- package/architecture/v4-platform-stage-checkpoints.json +1 -1
- package/architecture/v4-provider-operation-journal-contract.json +5 -2
- package/architecture/v4-publication-facade-patches.json +64 -0
- package/architecture/v4-release-activation-shadow-domain.json +5 -2
- package/architecture/v4-release-topology.json +74 -39
- package/architecture/v4-rust-wasm-production-authority.json +58 -0
- package/architecture/v4-stable-publication-fence.json +5 -2
- package/architecture/v4-stage-capsule-qualification.json +2 -2
- package/architecture/v4-tail-reseal-parity.json +8 -6
- package/architecture/v4-universal-workflow-bootstrap.json +171 -0
- package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
- package/architecture/v4-universal-workflow-train-admission.json +40 -0
- package/architecture/workflow-taxonomy.json +1451 -0
- package/bin/buildchain.mjs +7 -7
- package/contracts/buildchain-v2-residuals-v1.json +57 -48
- package/contracts/dev-delivery-authority-v2.schema.json +16 -2
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
- package/dist/site/buildchain-contract.json +93 -48
- package/dist/site/buildchain-site.json +222 -69
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/controller-registry.json +50 -13
- package/dist/site/kfd-claims.json +2585 -1000
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +13 -13
- package/dist/site/node-api-registry.json +120 -115
- package/dist/site/page-registry.json +204 -51
- package/dist/site/public-surface-audit.json +3205 -1219
- package/dist/site/publication-authority-registry.json +1124 -362
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
- package/dist/site/site-manifest.json +17 -17
- package/dist/site/workflow-registry.json +5061 -1659
- package/docs/MAP.md +1 -0
- package/docs/auditable-demo.md +1 -1
- package/docs/cli.md +21 -8
- package/docs/dev-delivery-warrant.md +1 -1
- package/docs/engineering-housekeeper.md +3 -3
- package/docs/kfd-support.md +26 -2
- package/docs/next-development-transition.md +2 -2
- package/docs/node-api-reference.md +190 -190
- package/docs/publication-authority.md +2 -2
- package/docs/release-candidate.md +3 -3
- package/docs/release-flow.md +67 -19
- package/docs/release-governance.md +8 -8
- package/docs/release-passport.md +27 -2
- package/docs/reusable-build-surface.md +16 -0
- package/docs/v4-adopter-delivery.md +2 -2
- package/docs/v4-production-release.md +71 -8
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/docs/v4-stage-capsule.md +2 -2
- package/docs/v4-tail-reseal.md +1 -1
- package/docs/workflow-catalog.md +154 -0
- package/docs/workflow-path-migration.md +109 -0
- package/package.json +10 -6
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-contract.js +1 -1
- package/packages/core/buildchain-kfd-claims.js +2 -2
- package/packages/core/buildchain-publication-authority.js +42 -26
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/ci-lane-change-budget.js +14 -1
- package/packages/core/controller-evidence.js +4 -1
- package/packages/core/dev-delivery-candidate-identity.js +40 -6
- package/packages/core/dev-delivery-warrant-state.js +3 -4
- package/packages/core/dev-delivery-warrant.js +12 -2
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/kfd-adopter-manifest.js +46 -47
- package/packages/core/next-development-projection.js +2 -2
- package/packages/core/paper-agent-entry.js +30 -4
- package/packages/core/paper-fleet.js +1 -1
- package/packages/core/paper-runtime-channels.js +348 -0
- package/packages/core/paper-scaffold-content.js +10 -0
- package/packages/core/paper.js +37 -71
- package/packages/core/release-line-dry-run.js +1 -1
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +5 -4
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/v4-canonical-contracts.js +10 -75
- package/packages/core/v4-domain-wasm-artifact.js +7 -0
- package/packages/core/v4-domain-wasm.js +216 -0
- package/packages/core/v4-floating-consumer-evidence.js +1 -1
- package/packages/core/v4-floating-consumer-policy.js +1 -1
- package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
- package/packages/core/v4-product-publication.js +19 -349
- package/packages/core/v4-protected-publication-source.js +19 -21
- package/packages/core/v4-provider-operation-journal.js +18 -487
- package/packages/core/v4-provider-readback-idempotency.js +12 -97
- package/packages/core/v4-release-activation-shadow.js +13 -500
- package/packages/core/v4-release-invocation.js +28 -389
- package/packages/core/v4-stable-publication-fence.js +13 -342
- package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
- package/scripts/binary-publication-evidence.mjs +135 -0
- package/scripts/build-contract-core.mjs +1 -14
- package/scripts/build-v4-domain-wasm.mjs +189 -0
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/check-ci-lane-change-budget.mjs +4 -1
- package/scripts/check-core-mechanism-inventory.mjs +4 -3
- package/scripts/check-inventory.mjs +35 -44
- package/scripts/check-maintainability.mjs +16 -113
- package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
- package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
- package/scripts/check-v4-release-topology.mjs +90 -33
- package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
- package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
- package/scripts/check-workflow-taxonomy.mjs +6 -0
- package/scripts/copy-v4-domain-wasm.mjs +14 -0
- package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
- package/scripts/dev-delivery-authority.mjs +8 -8
- package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
- package/scripts/dev-delivery-warrant-options.mjs +14 -9
- package/scripts/dev-delivery-warrant-store.mjs +73 -7
- package/scripts/dev-delivery-warrant-transition.mjs +109 -0
- package/scripts/dev-delivery-warrant.mjs +76 -99
- package/scripts/dev-pr-auto-merge.mjs +15 -15
- package/scripts/generate-channel-build-workflow.mjs +7 -2
- package/scripts/generate-channel-promotion-workflow.mjs +7 -5
- package/scripts/generate-site-bundle.mjs +11 -11
- package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
- package/scripts/generate-workflow-taxonomy.mjs +25 -0
- package/scripts/github-output.mjs +31 -0
- package/scripts/maintainability-metrics.mjs +16 -5
- package/scripts/maintainability-public-surface.mjs +115 -0
- package/scripts/next-development-review.mjs +307 -0
- package/scripts/paper-work-fleet-cli.mjs +2 -0
- package/scripts/release-asset-client.mjs +91 -0
- package/scripts/release-candidate-resolver.mjs +9 -9
- package/scripts/source-verification-evidence.mjs +344 -0
- package/scripts/stable-candidate-qualification.mjs +1 -1
- package/scripts/universal-facade-maintainability.mjs +82 -0
- package/scripts/v4-product-publication-intent.mjs +13 -6
- package/scripts/v4-publication-settlement.mjs +211 -0
- package/scripts/v4-universal-workflow-backflow.mjs +212 -0
- package/scripts/v4-universal-workflow-engine.mjs +618 -0
- package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
- package/scripts/verify-version-state-delta.mjs +173 -0
- package/scripts/workflow-taxonomy.mjs +507 -0
- package/templates/native-dev-delivery.yml +4 -7
- package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
- package/templates/universal-buildchain-bootstrap.yml +28 -0
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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";
|
|
1
|
+
import { V4ContractFault } from "./v4-canonical-contracts.js";
|
|
2
|
+
import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
20
3
|
|
|
21
4
|
export const V4_RELEASE_ACTIVATION_REQUEST_CONTRACT =
|
|
22
5
|
"buildchain-v4-release-activation-request/v1";
|
|
@@ -25,495 +8,25 @@ export const V4_RELEASE_ACTIVATION_PLAN_CONTRACT =
|
|
|
25
8
|
export const V4_RELEASE_ACTIVATION_STATE_CONTRACT =
|
|
26
9
|
"buildchain-v4-release-activation-state/v1";
|
|
27
10
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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);
|
|
11
|
+
function project(request) {
|
|
12
|
+
try {
|
|
13
|
+
return invokeV4DomainWasm("release-activation", request);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error instanceof V4DomainWasmFault) {
|
|
16
|
+
throw new V4ContractFault(error.code, error.path, error.message);
|
|
17
|
+
}
|
|
18
|
+
throw error;
|
|
311
19
|
}
|
|
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
20
|
}
|
|
341
21
|
|
|
342
22
|
export function planV4ReleaseActivation(request) {
|
|
343
|
-
|
|
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;
|
|
23
|
+
return project(request).plan;
|
|
436
24
|
}
|
|
437
25
|
|
|
438
26
|
export function foldV4ReleaseActivation(request) {
|
|
439
|
-
|
|
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
|
-
};
|
|
27
|
+
return project(request).state;
|
|
512
28
|
}
|
|
513
29
|
|
|
514
30
|
export function projectV4ReleaseActivation(request) {
|
|
515
|
-
return
|
|
516
|
-
plan: planV4ReleaseActivation(request),
|
|
517
|
-
state: foldV4ReleaseActivation(request),
|
|
518
|
-
};
|
|
31
|
+
return project(request);
|
|
519
32
|
}
|