@kungfu-tech/buildchain 4.0.2-alpha.9 → 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,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
v4ContentRoot,
|
|
4
|
-
validateV4Clock,
|
|
5
|
-
validateV4Root,
|
|
6
|
-
} from "./v4-canonical-contracts.js";
|
|
1
|
+
import { V4ContractFault } from "./v4-canonical-contracts.js";
|
|
2
|
+
import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
7
3
|
|
|
8
4
|
export const V4_PROVIDER_OPERATION_IDENTITY_CONTRACT =
|
|
9
5
|
"buildchain-v4-provider-operation-identity/v1";
|
|
@@ -20,512 +16,47 @@ export const V4_PROVIDER_OPERATION_RECONCILIATION_CONTRACT =
|
|
|
20
16
|
export const V4_PROVIDER_OPERATION_JOURNAL_STATE_CONTRACT =
|
|
21
17
|
"buildchain-v4-provider-operation-journal-state/v1";
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"schema",
|
|
32
|
-
"sequence",
|
|
33
|
-
"priorEntryRoot",
|
|
34
|
-
"operation",
|
|
35
|
-
"operationRoot",
|
|
36
|
-
"declaredAt",
|
|
37
|
-
"inputRoot",
|
|
38
|
-
"entryRoot",
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
attempt: {
|
|
42
|
-
schema: V4_PROVIDER_OPERATION_ATTEMPT_CONTRACT,
|
|
43
|
-
domain: "provider-operation-attempt",
|
|
44
|
-
keys: [
|
|
45
|
-
"kind",
|
|
46
|
-
"schema",
|
|
47
|
-
"sequence",
|
|
48
|
-
"priorEntryRoot",
|
|
49
|
-
"operationRoot",
|
|
50
|
-
"attemptOrdinal",
|
|
51
|
-
"attemptedAt",
|
|
52
|
-
"effectRoot",
|
|
53
|
-
"entryRoot",
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
observation: {
|
|
57
|
-
schema: V4_PROVIDER_OPERATION_OBSERVATION_CONTRACT,
|
|
58
|
-
domain: "provider-operation-observation",
|
|
59
|
-
keys: [
|
|
60
|
-
"kind",
|
|
61
|
-
"schema",
|
|
62
|
-
"sequence",
|
|
63
|
-
"priorEntryRoot",
|
|
64
|
-
"operationRoot",
|
|
65
|
-
"attemptRoot",
|
|
66
|
-
"observedAt",
|
|
67
|
-
"status",
|
|
68
|
-
"evidenceRoots",
|
|
69
|
-
"entryRoot",
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
confirmation: {
|
|
73
|
-
schema: V4_PROVIDER_OPERATION_CONFIRMATION_CONTRACT,
|
|
74
|
-
domain: "provider-operation-confirmation",
|
|
75
|
-
keys: [
|
|
76
|
-
"kind",
|
|
77
|
-
"schema",
|
|
78
|
-
"sequence",
|
|
79
|
-
"priorEntryRoot",
|
|
80
|
-
"operationRoot",
|
|
81
|
-
"observationRoot",
|
|
82
|
-
"authorityRoot",
|
|
83
|
-
"confirmedAt",
|
|
84
|
-
"outcome",
|
|
85
|
-
"entryRoot",
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
reconciliation: {
|
|
89
|
-
schema: V4_PROVIDER_OPERATION_RECONCILIATION_CONTRACT,
|
|
90
|
-
domain: "provider-operation-reconciliation",
|
|
91
|
-
keys: [
|
|
92
|
-
"kind",
|
|
93
|
-
"schema",
|
|
94
|
-
"sequence",
|
|
95
|
-
"priorEntryRoot",
|
|
96
|
-
"operationRoot",
|
|
97
|
-
"observationRoot",
|
|
98
|
-
"authorityRoot",
|
|
99
|
-
"reconciledAt",
|
|
100
|
-
"disposition",
|
|
101
|
-
"entryRoot",
|
|
102
|
-
],
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
function fault(code, path, message) {
|
|
107
|
-
throw new V4ContractFault(code, path, message);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function exactKeys(value, keys, path) {
|
|
111
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
112
|
-
fault(
|
|
113
|
-
"invalid-provider-operation-shape",
|
|
114
|
-
path,
|
|
115
|
-
`${path} must be an object`,
|
|
116
|
-
);
|
|
117
|
-
const actual = Object.keys(value).sort();
|
|
118
|
-
const expected = [...keys].sort();
|
|
119
|
-
if (
|
|
120
|
-
actual.length !== expected.length ||
|
|
121
|
-
actual.some((key, index) => key !== expected[index])
|
|
122
|
-
)
|
|
123
|
-
fault(
|
|
124
|
-
"invalid-provider-operation-shape",
|
|
125
|
-
path,
|
|
126
|
-
`${path} keys are not canonical`,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function validateToken(value, path) {
|
|
131
|
-
if (typeof value !== "string" || !TOKEN.test(value))
|
|
132
|
-
fault(
|
|
133
|
-
"invalid-provider-operation-token",
|
|
134
|
-
path,
|
|
135
|
-
`${path} must be an ASCII token`,
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function validateCounter(value, path, minimum = 0) {
|
|
140
|
-
if (!Number.isSafeInteger(value) || value < minimum)
|
|
141
|
-
fault(
|
|
142
|
-
"invalid-provider-operation-counter",
|
|
143
|
-
path,
|
|
144
|
-
`${path} must be a safe integer greater than or equal to ${minimum}`,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function validateRootList(value, path) {
|
|
149
|
-
if (!Array.isArray(value) || value.length === 0)
|
|
150
|
-
fault(
|
|
151
|
-
"invalid-provider-operation-evidence",
|
|
152
|
-
path,
|
|
153
|
-
`${path} must contain at least one rooted observation`,
|
|
154
|
-
);
|
|
155
|
-
let prior = null;
|
|
156
|
-
for (const [index, root] of value.entries()) {
|
|
157
|
-
validateV4Root(root, `${path}/${index}`);
|
|
158
|
-
if (prior !== null && root <= prior)
|
|
159
|
-
fault(
|
|
160
|
-
"invalid-provider-operation-evidence",
|
|
161
|
-
`${path}/${index}`,
|
|
162
|
-
`${path} must be unique and byte-sorted`,
|
|
163
|
-
);
|
|
164
|
-
prior = root;
|
|
19
|
+
function invoke(operation, payload) {
|
|
20
|
+
try {
|
|
21
|
+
return invokeV4DomainWasm(operation, payload);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof V4DomainWasmFault) {
|
|
24
|
+
throw new V4ContractFault(error.code, error.path, error.message);
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
165
27
|
}
|
|
166
28
|
}
|
|
167
29
|
|
|
168
30
|
export function validateV4ProviderOperationIdentity(value) {
|
|
169
|
-
|
|
170
|
-
value,
|
|
171
|
-
[
|
|
172
|
-
"schema",
|
|
173
|
-
"transactionRoot",
|
|
174
|
-
"capabilityId",
|
|
175
|
-
"subjectRoot",
|
|
176
|
-
"targetRoot",
|
|
177
|
-
"authorityRoot",
|
|
178
|
-
"policyRoot",
|
|
179
|
-
],
|
|
180
|
-
"$/operation",
|
|
181
|
-
);
|
|
182
|
-
if (value.schema !== V4_PROVIDER_OPERATION_IDENTITY_CONTRACT)
|
|
183
|
-
fault(
|
|
184
|
-
"unsupported-provider-operation-version",
|
|
185
|
-
"$/operation/schema",
|
|
186
|
-
"unsupported provider operation identity schema",
|
|
187
|
-
);
|
|
188
|
-
if (
|
|
189
|
-
typeof value.capabilityId !== "string" ||
|
|
190
|
-
!CAPABILITY.test(value.capabilityId)
|
|
191
|
-
)
|
|
192
|
-
fault(
|
|
193
|
-
"invalid-provider-operation-token",
|
|
194
|
-
"$/operation/capabilityId",
|
|
195
|
-
"capabilityId must be an ASCII dotted token",
|
|
196
|
-
);
|
|
197
|
-
for (const name of [
|
|
198
|
-
"transactionRoot",
|
|
199
|
-
"subjectRoot",
|
|
200
|
-
"targetRoot",
|
|
201
|
-
"authorityRoot",
|
|
202
|
-
"policyRoot",
|
|
203
|
-
])
|
|
204
|
-
validateV4Root(value[name], `$/operation/${name}`);
|
|
31
|
+
invoke("provider-operation-identity-validate", value);
|
|
205
32
|
return value;
|
|
206
33
|
}
|
|
207
34
|
|
|
208
35
|
export function v4ProviderOperationRoot(identity) {
|
|
209
|
-
|
|
210
|
-
return v4ContentRoot("provider-operation-identity", identity);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function entryPayload(entry) {
|
|
214
|
-
const { entryRoot: _entryRoot, ...payload } = entry;
|
|
215
|
-
return payload;
|
|
36
|
+
return invoke("provider-operation-identity-root", identity).root;
|
|
216
37
|
}
|
|
217
38
|
|
|
218
39
|
export function v4ProviderOperationEntryRoot(entry) {
|
|
219
|
-
|
|
220
|
-
if (!descriptor)
|
|
221
|
-
fault(
|
|
222
|
-
"invalid-provider-operation-shape",
|
|
223
|
-
"$/kind",
|
|
224
|
-
"provider operation entry kind is unsupported",
|
|
225
|
-
);
|
|
226
|
-
return v4ContentRoot(descriptor.domain, entryPayload(entry));
|
|
40
|
+
return invoke("provider-operation-entry-root", entry).root;
|
|
227
41
|
}
|
|
228
42
|
|
|
229
43
|
export function validateV4ProviderOperationEntry(entry) {
|
|
230
|
-
|
|
231
|
-
if (!descriptor)
|
|
232
|
-
fault(
|
|
233
|
-
"invalid-provider-operation-shape",
|
|
234
|
-
"$/kind",
|
|
235
|
-
"provider operation entry kind is unsupported",
|
|
236
|
-
);
|
|
237
|
-
exactKeys(entry, descriptor.keys, "$");
|
|
238
|
-
if (entry.schema !== descriptor.schema)
|
|
239
|
-
fault(
|
|
240
|
-
"unsupported-provider-operation-version",
|
|
241
|
-
"$/schema",
|
|
242
|
-
"provider operation entry schema does not match its kind",
|
|
243
|
-
);
|
|
244
|
-
validateCounter(entry.sequence, "$/sequence");
|
|
245
|
-
if (entry.priorEntryRoot !== null)
|
|
246
|
-
validateV4Root(entry.priorEntryRoot, "$/priorEntryRoot");
|
|
247
|
-
validateV4Root(entry.operationRoot, "$/operationRoot");
|
|
248
|
-
validateV4Root(entry.entryRoot, "$/entryRoot");
|
|
249
|
-
if (entry.kind === "intent") {
|
|
250
|
-
validateV4ProviderOperationIdentity(entry.operation);
|
|
251
|
-
validateV4Clock(entry.declaredAt, "$/declaredAt");
|
|
252
|
-
validateV4Root(entry.inputRoot, "$/inputRoot");
|
|
253
|
-
if (entry.operationRoot !== v4ProviderOperationRoot(entry.operation))
|
|
254
|
-
fault(
|
|
255
|
-
"provider-operation-root-mismatch",
|
|
256
|
-
"$/operationRoot",
|
|
257
|
-
"operationRoot does not bind the logical provider operation",
|
|
258
|
-
);
|
|
259
|
-
} else if (entry.kind === "attempt") {
|
|
260
|
-
validateCounter(entry.attemptOrdinal, "$/attemptOrdinal", 1);
|
|
261
|
-
validateV4Clock(entry.attemptedAt, "$/attemptedAt");
|
|
262
|
-
validateV4Root(entry.effectRoot, "$/effectRoot");
|
|
263
|
-
} else if (entry.kind === "observation") {
|
|
264
|
-
validateV4Root(entry.attemptRoot, "$/attemptRoot");
|
|
265
|
-
validateV4Clock(entry.observedAt, "$/observedAt");
|
|
266
|
-
if (!["succeeded", "failed", "unknown"].includes(entry.status))
|
|
267
|
-
fault(
|
|
268
|
-
"invalid-provider-operation-observation",
|
|
269
|
-
"$/status",
|
|
270
|
-
"provider operation observation status is unsupported",
|
|
271
|
-
);
|
|
272
|
-
validateRootList(entry.evidenceRoots, "$/evidenceRoots");
|
|
273
|
-
} else if (entry.kind === "confirmation") {
|
|
274
|
-
validateV4Root(entry.observationRoot, "$/observationRoot");
|
|
275
|
-
validateV4Root(entry.authorityRoot, "$/authorityRoot");
|
|
276
|
-
validateV4Clock(entry.confirmedAt, "$/confirmedAt");
|
|
277
|
-
if (!["confirmed", "rejected"].includes(entry.outcome))
|
|
278
|
-
fault(
|
|
279
|
-
"invalid-provider-operation-confirmation",
|
|
280
|
-
"$/outcome",
|
|
281
|
-
"provider operation confirmation outcome is unsupported",
|
|
282
|
-
);
|
|
283
|
-
} else {
|
|
284
|
-
validateV4Root(entry.observationRoot, "$/observationRoot");
|
|
285
|
-
validateV4Root(entry.authorityRoot, "$/authorityRoot");
|
|
286
|
-
validateV4Clock(entry.reconciledAt, "$/reconciledAt");
|
|
287
|
-
if (!["retry", "confirm", "terminal"].includes(entry.disposition))
|
|
288
|
-
fault(
|
|
289
|
-
"invalid-provider-operation-reconciliation",
|
|
290
|
-
"$/disposition",
|
|
291
|
-
"provider operation reconciliation disposition is unsupported",
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
if (entry.entryRoot !== v4ProviderOperationEntryRoot(entry))
|
|
295
|
-
fault(
|
|
296
|
-
"provider-operation-entry-root-mismatch",
|
|
297
|
-
"$/entryRoot",
|
|
298
|
-
"entryRoot does not bind the canonical provider operation entry",
|
|
299
|
-
);
|
|
44
|
+
invoke("provider-operation-entry-validate", entry);
|
|
300
45
|
return entry;
|
|
301
46
|
}
|
|
302
47
|
|
|
303
|
-
function transitionFault(entry, phase) {
|
|
304
|
-
fault(
|
|
305
|
-
"impossible-provider-operation-transition",
|
|
306
|
-
`$/entries/${entry.sequence}/kind`,
|
|
307
|
-
`${entry.kind} cannot follow provider operation phase ${phase}`,
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function assertJournalCoordinates(context, entry, index) {
|
|
312
|
-
validateV4ProviderOperationEntry(entry);
|
|
313
|
-
if (entry.sequence !== index)
|
|
314
|
-
fault(
|
|
315
|
-
"provider-operation-sequence-conflict",
|
|
316
|
-
`$/entries/${index}/sequence`,
|
|
317
|
-
"provider operation sequence must be contiguous and zero-based",
|
|
318
|
-
);
|
|
319
|
-
const expectedPrior = context?.state.lastEntryRoot ?? null;
|
|
320
|
-
if (entry.priorEntryRoot !== expectedPrior)
|
|
321
|
-
fault(
|
|
322
|
-
"provider-operation-causal-link-mismatch",
|
|
323
|
-
`$/entries/${index}/priorEntryRoot`,
|
|
324
|
-
"priorEntryRoot does not bind the append-only predecessor",
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function initializeJournal(entry) {
|
|
329
|
-
if (entry.kind !== "intent") transitionFault(entry, "empty");
|
|
330
|
-
return {
|
|
331
|
-
authorityRoot: entry.operation.authorityRoot,
|
|
332
|
-
lastObservationStatus: null,
|
|
333
|
-
state: {
|
|
334
|
-
schema: V4_PROVIDER_OPERATION_JOURNAL_STATE_CONTRACT,
|
|
335
|
-
operationRoot: entry.operationRoot,
|
|
336
|
-
phase: "intended",
|
|
337
|
-
entryCount: 1,
|
|
338
|
-
attemptCount: 0,
|
|
339
|
-
lastEntryRoot: entry.entryRoot,
|
|
340
|
-
activeAttemptRoot: null,
|
|
341
|
-
lastObservationRoot: null,
|
|
342
|
-
confirmationRoot: null,
|
|
343
|
-
reconciliationRoot: null,
|
|
344
|
-
},
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
function applyAttempt(context, entry, index) {
|
|
349
|
-
const { state } = context;
|
|
350
|
-
if (!["intended", "retryable"].includes(state.phase))
|
|
351
|
-
transitionFault(entry, state.phase);
|
|
352
|
-
if (entry.attemptOrdinal !== state.attemptCount + 1)
|
|
353
|
-
fault(
|
|
354
|
-
"provider-operation-attempt-conflict",
|
|
355
|
-
`$/entries/${index}/attemptOrdinal`,
|
|
356
|
-
"attemptOrdinal must append exactly one logical retry attempt",
|
|
357
|
-
);
|
|
358
|
-
state.phase = "attempting";
|
|
359
|
-
state.attemptCount += 1;
|
|
360
|
-
state.activeAttemptRoot = entry.entryRoot;
|
|
361
|
-
state.lastObservationRoot = null;
|
|
362
|
-
context.lastObservationStatus = null;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function applyObservation(context, entry, index) {
|
|
366
|
-
const { state } = context;
|
|
367
|
-
if (state.phase !== "attempting") transitionFault(entry, state.phase);
|
|
368
|
-
if (entry.attemptRoot !== state.activeAttemptRoot)
|
|
369
|
-
fault(
|
|
370
|
-
"provider-operation-causal-link-mismatch",
|
|
371
|
-
`$/entries/${index}/attemptRoot`,
|
|
372
|
-
"observation must bind the active rooted attempt",
|
|
373
|
-
);
|
|
374
|
-
state.phase = "observed";
|
|
375
|
-
state.lastObservationRoot = entry.entryRoot;
|
|
376
|
-
context.lastObservationStatus = entry.status;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function applyReconciliation(context, entry, index) {
|
|
380
|
-
const { state } = context;
|
|
381
|
-
if (entry.authorityRoot !== context.authorityRoot)
|
|
382
|
-
fault(
|
|
383
|
-
"provider-operation-authority-escalation",
|
|
384
|
-
`$/entries/${index}/authorityRoot`,
|
|
385
|
-
"reconciliation cannot change the declared authority root",
|
|
386
|
-
);
|
|
387
|
-
if (state.phase !== "observed") transitionFault(entry, state.phase);
|
|
388
|
-
if (entry.observationRoot !== state.lastObservationRoot)
|
|
389
|
-
fault(
|
|
390
|
-
"provider-operation-causal-link-mismatch",
|
|
391
|
-
`$/entries/${index}/observationRoot`,
|
|
392
|
-
"reconciliation must bind the latest rooted observation",
|
|
393
|
-
);
|
|
394
|
-
if (
|
|
395
|
-
(entry.disposition === "retry" &&
|
|
396
|
-
context.lastObservationStatus === "succeeded") ||
|
|
397
|
-
(entry.disposition === "confirm" &&
|
|
398
|
-
context.lastObservationStatus !== "succeeded")
|
|
399
|
-
)
|
|
400
|
-
fault(
|
|
401
|
-
"invalid-provider-operation-reconciliation",
|
|
402
|
-
`$/entries/${index}/disposition`,
|
|
403
|
-
"reconciliation disposition conflicts with the rooted observation",
|
|
404
|
-
);
|
|
405
|
-
state.phase =
|
|
406
|
-
entry.disposition === "retry"
|
|
407
|
-
? "retryable"
|
|
408
|
-
: entry.disposition === "confirm"
|
|
409
|
-
? "confirmable"
|
|
410
|
-
: "terminal";
|
|
411
|
-
state.reconciliationRoot = entry.entryRoot;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function applyConfirmation(context, entry, index) {
|
|
415
|
-
const { state } = context;
|
|
416
|
-
if (entry.authorityRoot !== context.authorityRoot)
|
|
417
|
-
fault(
|
|
418
|
-
"provider-operation-authority-escalation",
|
|
419
|
-
`$/entries/${index}/authorityRoot`,
|
|
420
|
-
"confirmation cannot change the declared authority root",
|
|
421
|
-
);
|
|
422
|
-
if (["confirmed", "rejected"].includes(state.phase))
|
|
423
|
-
fault(
|
|
424
|
-
"conflicting-provider-operation-confirmation",
|
|
425
|
-
`$/entries/${index}`,
|
|
426
|
-
"a terminal provider operation cannot receive another confirmation",
|
|
427
|
-
);
|
|
428
|
-
if (
|
|
429
|
-
!["observed", "confirmable"].includes(state.phase) ||
|
|
430
|
-
context.lastObservationStatus !== "succeeded" ||
|
|
431
|
-
entry.observationRoot !== state.lastObservationRoot
|
|
432
|
-
)
|
|
433
|
-
fault(
|
|
434
|
-
"confirmation-without-rooted-observation",
|
|
435
|
-
`$/entries/${index}/observationRoot`,
|
|
436
|
-
"confirmation requires the latest successful rooted observation",
|
|
437
|
-
);
|
|
438
|
-
state.phase = entry.outcome;
|
|
439
|
-
state.confirmationRoot = entry.entryRoot;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
function applyJournalEntry(context, entry, index) {
|
|
443
|
-
if (entry.operationRoot !== context.state.operationRoot)
|
|
444
|
-
fault(
|
|
445
|
-
"provider-operation-identity-drift",
|
|
446
|
-
`$/entries/${index}/operationRoot`,
|
|
447
|
-
"retry records must preserve logical operation identity",
|
|
448
|
-
);
|
|
449
|
-
if (entry.kind === "intent") transitionFault(entry, context.state.phase);
|
|
450
|
-
if (entry.kind === "attempt") applyAttempt(context, entry, index);
|
|
451
|
-
else if (entry.kind === "observation")
|
|
452
|
-
applyObservation(context, entry, index);
|
|
453
|
-
else if (entry.kind === "reconciliation")
|
|
454
|
-
applyReconciliation(context, entry, index);
|
|
455
|
-
else applyConfirmation(context, entry, index);
|
|
456
|
-
context.state.entryCount += 1;
|
|
457
|
-
context.state.lastEntryRoot = entry.entryRoot;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
48
|
export function foldV4ProviderOperationJournal(entries) {
|
|
461
|
-
|
|
462
|
-
fault(
|
|
463
|
-
"invalid-provider-operation-journal",
|
|
464
|
-
"$/entries",
|
|
465
|
-
"provider operation journal must contain an intent",
|
|
466
|
-
);
|
|
467
|
-
let context = null;
|
|
468
|
-
for (const [index, entry] of entries.entries()) {
|
|
469
|
-
assertJournalCoordinates(context, entry, index);
|
|
470
|
-
if (index === 0) context = initializeJournal(entry);
|
|
471
|
-
else applyJournalEntry(context, entry, index);
|
|
472
|
-
}
|
|
473
|
-
return context.state;
|
|
49
|
+
return invoke("provider-operation-journal", entries).state;
|
|
474
50
|
}
|
|
475
51
|
|
|
476
52
|
export function v4ProviderOperationJournalRoot(entries) {
|
|
477
|
-
|
|
478
|
-
return v4ContentRoot("provider-operation-journal", entries);
|
|
53
|
+
return invoke("provider-operation-journal", entries).journalRoot;
|
|
479
54
|
}
|
|
480
55
|
|
|
481
56
|
export function v4ProviderOperationJournalStateRoot(entries) {
|
|
482
|
-
return
|
|
483
|
-
"provider-operation-journal-state",
|
|
484
|
-
foldV4ProviderOperationJournal(entries),
|
|
485
|
-
);
|
|
57
|
+
return invoke("provider-operation-journal", entries).stateRoot;
|
|
486
58
|
}
|
|
487
59
|
|
|
488
60
|
export function projectV4ProviderOperationFixtures(fixtures) {
|
|
489
|
-
|
|
490
|
-
fixtures,
|
|
491
|
-
["schemaVersion", "contract", "validCases", "invalidCases"],
|
|
492
|
-
"$",
|
|
493
|
-
);
|
|
494
|
-
if (
|
|
495
|
-
fixtures.schemaVersion !== 1 ||
|
|
496
|
-
fixtures.contract !==
|
|
497
|
-
"buildchain-v4-provider-operation-journal-fixtures/v1" ||
|
|
498
|
-
!Array.isArray(fixtures.validCases) ||
|
|
499
|
-
!Array.isArray(fixtures.invalidCases)
|
|
500
|
-
)
|
|
501
|
-
fault(
|
|
502
|
-
"unsupported-provider-operation-version",
|
|
503
|
-
"$/schemaVersion",
|
|
504
|
-
"unsupported provider operation fixture contract",
|
|
505
|
-
);
|
|
506
|
-
const validCases = fixtures.validCases.map(({ id, entries }) => {
|
|
507
|
-
const state = foldV4ProviderOperationJournal(entries);
|
|
508
|
-
return {
|
|
509
|
-
id,
|
|
510
|
-
operationRoot: state.operationRoot,
|
|
511
|
-
entryRoots: entries.map((entry) => entry.entryRoot),
|
|
512
|
-
journalRoot: v4ProviderOperationJournalRoot(entries),
|
|
513
|
-
state,
|
|
514
|
-
stateRoot: v4ProviderOperationJournalStateRoot(entries),
|
|
515
|
-
};
|
|
516
|
-
});
|
|
517
|
-
const invalidCases = fixtures.invalidCases.map(({ id, entries }) => {
|
|
518
|
-
try {
|
|
519
|
-
foldV4ProviderOperationJournal(entries);
|
|
520
|
-
} catch (error) {
|
|
521
|
-
if (error instanceof V4ContractFault) return { id, fault: error.code };
|
|
522
|
-
throw error;
|
|
523
|
-
}
|
|
524
|
-
fault(
|
|
525
|
-
"invalid-provider-operation-fixture",
|
|
526
|
-
"$/invalidCases",
|
|
527
|
-
`fixture ${id} unexpectedly passed`,
|
|
528
|
-
);
|
|
529
|
-
});
|
|
530
|
-
return { validCases, invalidCases };
|
|
61
|
+
return invoke("provider-operation-fixtures", fixtures);
|
|
531
62
|
}
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
V4ContractFault,
|
|
3
3
|
v4ContentRoot,
|
|
4
|
-
validateV4Clock,
|
|
5
4
|
validateV4Root,
|
|
6
5
|
} from "./v4-canonical-contracts.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
v4ProviderOperationJournalStateRoot,
|
|
10
|
-
v4ProviderOperationEntryRoot,
|
|
11
|
-
validateV4ProviderOperationEntry,
|
|
12
|
-
} from "./v4-provider-operation-journal.js";
|
|
6
|
+
import { v4ProviderOperationJournalStateRoot } from "./v4-provider-operation-journal.js";
|
|
7
|
+
import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
13
8
|
|
|
14
9
|
export const V4_PROVIDER_READBACK_SAMPLE_CONTRACT =
|
|
15
10
|
"buildchain-v4-provider-readback-sample/v1";
|
|
@@ -252,97 +247,17 @@ export function adaptV4OciManifestReadback(response, context) {
|
|
|
252
247
|
}
|
|
253
248
|
|
|
254
249
|
export function foldV4ProviderReadbackSamples(samples, coordinates) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
);
|
|
266
|
-
if (!Number.isSafeInteger(coordinates.sequence) || coordinates.sequence < 0)
|
|
267
|
-
fault(
|
|
268
|
-
"malformed-provider-readback",
|
|
269
|
-
"$/coordinates/sequence",
|
|
270
|
-
"readback sequence must be a non-negative safe integer",
|
|
271
|
-
);
|
|
272
|
-
for (const key of ["priorEntryRoot", "operationRoot", "attemptRoot"])
|
|
273
|
-
validateV4Root(coordinates[key], `$/coordinates/${key}`);
|
|
274
|
-
validateV4Clock(coordinates.observedAt, "$/coordinates/observedAt");
|
|
275
|
-
if (!Array.isArray(samples) || samples.length === 0)
|
|
276
|
-
fault(
|
|
277
|
-
"malformed-provider-readback",
|
|
278
|
-
"$/samples",
|
|
279
|
-
"at least one rooted provider readback sample is required",
|
|
280
|
-
);
|
|
281
|
-
const unique = new Map();
|
|
282
|
-
for (const [index, sample] of samples.entries()) {
|
|
283
|
-
validateSample(sample, `$/samples/${index}`);
|
|
284
|
-
if (
|
|
285
|
-
sample.operationRoot !== coordinates.operationRoot ||
|
|
286
|
-
sample.attemptRoot !== coordinates.attemptRoot
|
|
287
|
-
)
|
|
288
|
-
fault(
|
|
289
|
-
"provider-readback-coordinate-mismatch",
|
|
290
|
-
`$/samples/${index}`,
|
|
291
|
-
"provider readback sample does not bind the journal coordinates",
|
|
292
|
-
);
|
|
293
|
-
unique.set(sample.sampleRoot, sample);
|
|
250
|
+
try {
|
|
251
|
+
return invokeV4DomainWasm("provider-readback-fold", {
|
|
252
|
+
samples,
|
|
253
|
+
coordinates,
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
if (error instanceof V4DomainWasmFault) {
|
|
257
|
+
throw new V4ContractFault(error.code, error.path, error.message);
|
|
258
|
+
}
|
|
259
|
+
throw error;
|
|
294
260
|
}
|
|
295
|
-
const folded = [...unique.values()].sort((left, right) =>
|
|
296
|
-
left.sampleRoot.localeCompare(right.sampleRoot),
|
|
297
|
-
);
|
|
298
|
-
const states = new Set(folded.map((sample) => sample.state));
|
|
299
|
-
if (states.has("already-applied") && states.size !== 1)
|
|
300
|
-
fault(
|
|
301
|
-
"conflicting-provider-readback",
|
|
302
|
-
"$/samples",
|
|
303
|
-
"successful and unresolved readbacks cannot describe one attempt",
|
|
304
|
-
);
|
|
305
|
-
const targets = new Set(
|
|
306
|
-
folded.map((sample) => sample.observedTargetRoot).filter(Boolean),
|
|
307
|
-
);
|
|
308
|
-
if (targets.size > 1)
|
|
309
|
-
fault(
|
|
310
|
-
"conflicting-provider-readback",
|
|
311
|
-
"$/samples",
|
|
312
|
-
"provider readbacks disagree about the observed target",
|
|
313
|
-
);
|
|
314
|
-
const classification = states.has("already-applied")
|
|
315
|
-
? "already-applied"
|
|
316
|
-
: states.has("eventually-visible")
|
|
317
|
-
? "eventually-visible"
|
|
318
|
-
: "not-found";
|
|
319
|
-
const readbackRoots = folded.map((sample) => sample.sampleRoot);
|
|
320
|
-
const observation = {
|
|
321
|
-
kind: "observation",
|
|
322
|
-
schema: V4_PROVIDER_OPERATION_OBSERVATION_CONTRACT,
|
|
323
|
-
sequence: coordinates.sequence,
|
|
324
|
-
priorEntryRoot: coordinates.priorEntryRoot,
|
|
325
|
-
operationRoot: coordinates.operationRoot,
|
|
326
|
-
attemptRoot: coordinates.attemptRoot,
|
|
327
|
-
observedAt: coordinates.observedAt,
|
|
328
|
-
status: classification === "already-applied" ? "succeeded" : "unknown",
|
|
329
|
-
evidenceRoots: readbackRoots,
|
|
330
|
-
entryRoot:
|
|
331
|
-
"sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
|
332
|
-
};
|
|
333
|
-
observation.entryRoot = v4ProviderOperationEntryRoot(observation);
|
|
334
|
-
validateV4ProviderOperationEntry(observation);
|
|
335
|
-
const projection = {
|
|
336
|
-
schema: V4_PROVIDER_READBACK_FOLD_CONTRACT,
|
|
337
|
-
classification,
|
|
338
|
-
readbackRoots,
|
|
339
|
-
observation,
|
|
340
|
-
projectionRoot:
|
|
341
|
-
"sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
|
342
|
-
};
|
|
343
|
-
const { projectionRoot: _projectionRoot, ...payload } = projection;
|
|
344
|
-
projection.projectionRoot = v4ContentRoot("provider-readback-fold", payload);
|
|
345
|
-
return projection;
|
|
346
261
|
}
|
|
347
262
|
|
|
348
263
|
const ADAPTERS = Object.freeze({
|