@apexops/contracts 0.10.0-next.4 → 0.11.0-next.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 (77) hide show
  1. package/README.md +28 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/archetype-source.d.ts +70 -0
  4. package/dist/archetype-source.d.ts.map +1 -0
  5. package/dist/archetype-source.js +58 -0
  6. package/dist/archetype-source.js.map +1 -0
  7. package/dist/artifacts.d.ts +64 -0
  8. package/dist/artifacts.d.ts.map +1 -1
  9. package/dist/artifacts.js +69 -0
  10. package/dist/artifacts.js.map +1 -1
  11. package/dist/common.d.ts +2 -0
  12. package/dist/common.d.ts.map +1 -1
  13. package/dist/common.js +1 -0
  14. package/dist/common.js.map +1 -1
  15. package/dist/evidence.d.ts.map +1 -1
  16. package/dist/evidence.js +2 -0
  17. package/dist/evidence.js.map +1 -1
  18. package/dist/governance-observation.d.ts +15 -0
  19. package/dist/governance-observation.d.ts.map +1 -0
  20. package/dist/governance-observation.js +15 -0
  21. package/dist/governance-observation.js.map +1 -0
  22. package/dist/index.d.ts +627 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +47 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/native-validation.d.ts +136 -0
  27. package/dist/native-validation.d.ts.map +1 -0
  28. package/dist/native-validation.js +276 -0
  29. package/dist/native-validation.js.map +1 -0
  30. package/dist/onboarding.d.ts +184 -3
  31. package/dist/onboarding.d.ts.map +1 -1
  32. package/dist/onboarding.js +122 -6
  33. package/dist/onboarding.js.map +1 -1
  34. package/dist/policy-validation.d.ts +45 -0
  35. package/dist/policy-validation.d.ts.map +1 -0
  36. package/dist/policy-validation.js +194 -0
  37. package/dist/policy-validation.js.map +1 -0
  38. package/dist/runtime.d.ts +94 -2
  39. package/dist/runtime.d.ts.map +1 -1
  40. package/dist/runtime.js +53 -4
  41. package/dist/runtime.js.map +1 -1
  42. package/dist/targets.d.ts +158 -1
  43. package/dist/targets.d.ts.map +1 -1
  44. package/dist/targets.js +168 -2
  45. package/dist/targets.js.map +1 -1
  46. package/dist/test/contracts.test.js +769 -4
  47. package/dist/test/contracts.test.js.map +1 -1
  48. package/package.json +2 -2
  49. package/schemas/archetype-batch-config-v1.schema.json +51 -0
  50. package/schemas/archetype-batch-plan-v1.schema.json +227 -0
  51. package/schemas/archetype-source-proposal-v1.schema.json +113 -0
  52. package/schemas/architecture-v1.schema.json +278 -0
  53. package/schemas/bootstrap-plan-v1.schema.json +206 -0
  54. package/schemas/contract-metadata.json +85 -0
  55. package/schemas/cost-estimate-v1.schema.json +54 -1
  56. package/schemas/diagnosis-v1.schema.json +323 -0
  57. package/schemas/governance-constraints-v1.schema.json +13 -0
  58. package/schemas/governance-observation-receipt-v1.schema.json +60 -0
  59. package/schemas/governance-provision-plan-v1.schema.json +307 -0
  60. package/schemas/governance-setup-config-v1.schema.json +80 -0
  61. package/schemas/governance-setup-plan-v1.schema.json +217 -0
  62. package/schemas/iac-binding-v1.schema.json +60 -0
  63. package/schemas/input-request-v1.schema.json +296 -2
  64. package/schemas/logical-resource-manifest-v1.schema.json +4 -0
  65. package/schemas/native-validation-receipt-v1.schema.json +862 -0
  66. package/schemas/onboarding-config-v1.schema.json +15 -12
  67. package/schemas/policy-property-map-v1.schema.json +17 -0
  68. package/schemas/policy-validation-v1.schema.json +278 -0
  69. package/schemas/project-config-v1.schema.json +14 -1
  70. package/schemas/repeat-guard-records-v1.schema.json +76 -0
  71. package/schemas/repository-publish-config-v1.schema.json +52 -0
  72. package/schemas/repository-publish-plan-v1.schema.json +265 -0
  73. package/schemas/requirements-amendment-v1.schema.json +213 -0
  74. package/schemas/requirements-change-proposal-v1.schema.json +196 -0
  75. package/schemas/review-capture-v1.schema.json +67 -0
  76. package/schemas/review-findings-v1.schema.json +103 -0
  77. package/schemas/review-request-v1.schema.json +111 -0
@@ -4,7 +4,7 @@ import { describe, it } from "node:test";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { FormatRegistry } from "@sinclair/typebox";
6
6
  import { Value } from "@sinclair/typebox/value";
7
- import { ApprovalEvidenceV1Schema, ArchitectureV1Schema, CapabilityPackManifestV1Schema, CONTRACT_VERSION, CostEstimateV1Schema, CustomizationLockV1Schema, DeploymentPreviewV1Schema, DiagnosisV1Schema, EnvironmentInputsV1Schema, ExecutionPlanAttestationV1Schema, GovernanceConstraintsV1Schema, hasValidInputRequestQuestions, IacHandoffV1Schema, ImprovementDecisionV1Schema, ImprovementObservationV1Schema, ImprovementPolicyV1Schema, ImprovementProposalV1Schema, ImprovementRecurrenceV1Schema, InputRequestV1Schema, InputSubmissionV1Schema, LogicalResourceManifestV1Schema, LiveQualificationV1Schema, LIVE_QUALIFICATION_SCENARIO_IDS, OnboardingConfigV1Schema, PolicyPropertyMapV1Schema, PricingEvidenceV1Schema, PricingRequestV1Schema, QualityReportV1Schema, QualityMeasurementsV1Schema, ArchitectureAvailabilityV1Schema, RequirementsV1Schema, ReviewFindingsV1Schema, RuntimeBundleLockV1Schema, ScenarioV1Schema, TelemetryV1Schema, WorkloadDecisionManifestV1Schema, contractMetadata, contractSchemas, hasCompleteContractMetadata, hasOnlyTypedSecretReferences, hasValidLiveQualification, hasValidCostArithmetic, hasValidLogicalResourceReferences, hasValidPreviewApprovalBinding, calculatePricingEvidenceId, calculatePricingRequestId, hasValidPricingEvidence, schemaById, } from "../index.js";
7
+ import { ApprovalEvidenceV1Schema, ArchitectureV1Schema, CapabilityPackManifestV1Schema, CONTRACT_VERSION, CostEstimateV1Schema, CustomizationLockV1Schema, DeploymentPreviewV1Schema, DiagnosisV1Schema, EnvironmentInputsV1Schema, ExecutionPlanAttestationV1Schema, GovernanceConstraintsV1Schema, GovernanceObservationReceiptV1Schema, hasValidInputRequestQuestions, isGovernanceObservationCurrent, IacBindingV1Schema, IacHandoffV1Schema, ImprovementDecisionV1Schema, ImprovementObservationV1Schema, ImprovementPolicyV1Schema, ImprovementProposalV1Schema, ImprovementRecurrenceV1Schema, InputRequestV1Schema, InputSubmissionV1Schema, LogicalResourceManifestV1Schema, NativeValidationReceiptV1Schema, NATIVE_VALIDATION_COMMANDS, calculateNativeValidationCommandHash, calculateNativeValidationReceiptHash, calculatePolicyValidationDigest, hasValidArchetypeSourceProposal, hasValidNativeValidationReceipt, LiveQualificationV1Schema, LIVE_QUALIFICATION_SCENARIO_IDS, OnboardingConfigV1Schema, BootstrapPlanV1Schema, GovernanceSetupConfigV1Schema, GovernanceSetupPlanV1Schema, ArchetypeBatchConfigV1Schema, PolicyPropertyMapV1Schema, PricingEvidenceV1Schema, PricingRequestV1Schema, QualityReportV1Schema, QualityMeasurementsV1Schema, ArchitectureAvailabilityV1Schema, RequirementsV1Schema, RequirementsAmendmentV1Schema, RequirementsChangeProposalV1Schema, RepeatGuardRecordsV1Schema, ReviewCaptureV1Schema, ReviewRequestV1Schema, ReviewFindingsV1Schema, RuntimeBundleLockV1Schema, ScenarioV1Schema, TelemetryV1Schema, WorkloadDecisionManifestV1Schema, contractMetadata, contractSchemas, hasCompleteContractMetadata, hasOnlyTypedSecretReferences, hasValidLiveQualification, hasValidCostArithmetic, hasValidLogicalResourceReferences, hasValidPreviewApprovalBinding, calculatePricingEvidenceId, calculatePricingRequestId, hasValidPricingEvidence, schemaById, } from "../index.js";
8
8
  import { CONTRACT_METADATA_FILENAME, JSON_SCHEMA_DIALECT, createContractMetadataFile, createContractSchemaFiles, } from "../schema-export.js";
9
9
  const hash = "a".repeat(64);
10
10
  const otherHash = "b".repeat(64);
@@ -14,6 +14,452 @@ const completion = "2026-07-13T14:00:00.000Z";
14
14
  FormatRegistry.Set("date-time", (value) => Number.isFinite(Date.parse(value)));
15
15
  FormatRegistry.Set("date", (value) => /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(`${value}T00:00:00Z`)));
16
16
  describe("Wave 1 contracts", () => {
17
+ it("requires compact, strictly typed governance observation bindings without raw baseline data", () => {
18
+ const receipt = {
19
+ schemaVersion: CONTRACT_VERSION,
20
+ projectId: "demo",
21
+ runId: "run-1",
22
+ targetScope: "/subscriptions/11111111-1111-1111-1111-111111111111",
23
+ governanceHash: hash,
24
+ snapshotDigest: otherHash,
25
+ contentHash: hash,
26
+ observedAt: timestamp,
27
+ expiresAt: expiry,
28
+ rawSourceDigest: otherHash,
29
+ };
30
+ assert.equal(Value.Check(GovernanceObservationReceiptV1Schema, receipt), true);
31
+ for (const field of Object.keys(receipt)) {
32
+ const incomplete = { ...receipt };
33
+ delete incomplete[field];
34
+ assert.equal(Value.Check(GovernanceObservationReceiptV1Schema, incomplete), false, field);
35
+ }
36
+ for (const invalid of [
37
+ { ...receipt, baseline: {} },
38
+ { ...receipt, rawSourceDigest: "invalid" },
39
+ { ...receipt, observedAt: "invalid" },
40
+ { ...receipt, targetScope: "" },
41
+ ])
42
+ assert.equal(Value.Check(GovernanceObservationReceiptV1Schema, invalid), false);
43
+ assert.equal(schemaById[GovernanceObservationReceiptV1Schema.$id], GovernanceObservationReceiptV1Schema);
44
+ assert.equal(contractMetadata[GovernanceObservationReceiptV1Schema.$id]?.maxBytes, 16_384);
45
+ });
46
+ it("uses precise elapsed UTC age and rejects malformed governance observation dates", () => {
47
+ const observed = "2026-09-01T00:00:00Z";
48
+ assert.equal(isGovernanceObservationCurrent(observed, "2026-09-30T23:59:59.999Z"), true);
49
+ assert.equal(isGovernanceObservationCurrent(observed, "2026-10-01T00:00:00Z"), false);
50
+ assert.equal(isGovernanceObservationCurrent("2026-09-01T02:00:00+02:00", "2026-10-01T00:00:00Z"), false);
51
+ assert.equal(isGovernanceObservationCurrent(observed, "2026-08-31T23:59:59Z"), false);
52
+ for (const invalid of ["2026-09-01", "2026-09-01T00:00:00", "2026-02-30T00:00:00Z", "invalid"]) {
53
+ assert.equal(isGovernanceObservationCurrent(invalid, "2026-09-02T00:00:00Z"), false, invalid);
54
+ assert.equal(isGovernanceObservationCurrent(observed, invalid), false, invalid);
55
+ }
56
+ });
57
+ it("requires Bicep format, build and lint rather than accepting build-only receipts", () => {
58
+ assert.deepEqual(NATIVE_VALIDATION_COMMANDS.bicep.map(({ validatorId }) => validatorId), ["bicep:format", "bicep:build", "bicep:lint"]);
59
+ });
60
+ for (const track of ["bicep", "terraform"]) {
61
+ it(`validates strict source-bound native validation receipts for ${track}`, () => {
62
+ const body = {
63
+ schemaVersion: CONTRACT_VERSION,
64
+ projectId: "project",
65
+ runId: "run",
66
+ track,
67
+ sourceHash: hash,
68
+ treeHash: otherHash,
69
+ policyHash: hash,
70
+ inputHash: hash,
71
+ outcome: "pass",
72
+ commands: NATIVE_VALIDATION_COMMANDS[track].map((command) => ({
73
+ validatorId: command.validatorId,
74
+ commandHash: calculateNativeValidationCommandHash(command),
75
+ exitCode: 0,
76
+ signal: null,
77
+ timedOut: false,
78
+ outputTruncated: false,
79
+ })),
80
+ };
81
+ const receipt = { ...body, receiptHash: calculateNativeValidationReceiptHash(body) };
82
+ assert.equal(Value.Check(NativeValidationReceiptV1Schema, receipt), true);
83
+ assert.equal(hasValidNativeValidationReceipt(receipt, body), true);
84
+ const applicable = {
85
+ ...body,
86
+ policyApplicability: { status: "no-actionable-mappings", policyMapContentHash: body.policyHash },
87
+ };
88
+ assert.equal(hasValidNativeValidationReceipt({ ...applicable, receiptHash: calculateNativeValidationReceiptHash(applicable) }, body), true);
89
+ for (const mutation of [
90
+ { ...applicable, policyApplicability: { ...applicable.policyApplicability, policyMapContentHash: otherHash } },
91
+ { ...applicable, policyApplicability: { ...applicable.policyApplicability, status: "compliant" } },
92
+ ])
93
+ assert.equal(hasValidNativeValidationReceipt({ ...mutation, receiptHash: calculatePolicyValidationDigest(mutation) }, body), false);
94
+ if (track === "bicep") {
95
+ const routing = {
96
+ ...body,
97
+ storageDiagnostics: {
98
+ storage: {
99
+ coverage: "bicep-storage-service-diagnostics-v1",
100
+ fullBaselineEvaluated: false,
101
+ sourceHash: body.sourceHash,
102
+ inputHash: otherHash,
103
+ bindingHash: hash,
104
+ outcome: "pass",
105
+ reason: "matched",
106
+ },
107
+ },
108
+ };
109
+ assert.equal(hasValidNativeValidationReceipt({ ...routing, receiptHash: calculateNativeValidationReceiptHash(routing) }, body), true);
110
+ for (const patch of [
111
+ { sourceHash: otherHash },
112
+ { fullBaselineEvaluated: true },
113
+ { outcome: "fail" },
114
+ { reason: "workspace-mismatch" },
115
+ ]) {
116
+ const altered = {
117
+ ...routing,
118
+ storageDiagnostics: { storage: { ...routing.storageDiagnostics.storage, ...patch } },
119
+ };
120
+ assert.equal(hasValidNativeValidationReceipt({ ...altered, receiptHash: calculatePolicyValidationDigest(altered) }, body), false);
121
+ }
122
+ const parityBody = {
123
+ ...body,
124
+ resourceParity: {
125
+ coverage: "bicep-symbolic-resource-parity-v1",
126
+ sourceHash: body.sourceHash,
127
+ manifestHash: hash,
128
+ inputHash: otherHash,
129
+ outcome: "pass",
130
+ reason: "matched",
131
+ },
132
+ };
133
+ assert.equal(hasValidNativeValidationReceipt({ ...parityBody, receiptHash: calculateNativeValidationReceiptHash(parityBody) }, body), true);
134
+ for (const patch of [
135
+ { sourceHash: otherHash },
136
+ { outcome: "fail" },
137
+ { reason: "coverage-mismatch" },
138
+ { coverage: "full" },
139
+ ]) {
140
+ const altered = { ...parityBody, resourceParity: { ...parityBody.resourceParity, ...patch } };
141
+ assert.equal(hasValidNativeValidationReceipt({ ...altered, receiptHash: calculatePolicyValidationDigest(altered) }, body), false);
142
+ }
143
+ const baselineBody = {
144
+ ...parityBody,
145
+ resourceParity: { ...parityBody.resourceParity, bindingHash: hash },
146
+ securityBaseline: {
147
+ coverage: "bicep-storage-only-baseline-v1",
148
+ sourceHash: body.sourceHash,
149
+ inputHash: otherHash,
150
+ manifestHash: hash,
151
+ bindingHash: hash,
152
+ outcome: "pass",
153
+ reason: "matched",
154
+ },
155
+ };
156
+ assert.equal(hasValidNativeValidationReceipt({ ...baselineBody, receiptHash: calculateNativeValidationReceiptHash(baselineBody) }, body), true);
157
+ for (const patch of [
158
+ { bindingHash: otherHash },
159
+ { manifestHash: otherHash },
160
+ { inputHash: hash },
161
+ { sourceHash: otherHash },
162
+ { reason: "storage-controls" },
163
+ { outcome: "unsupported" },
164
+ { coverage: "full" },
165
+ ]) {
166
+ const changed = { ...baselineBody, securityBaseline: { ...baselineBody.securityBaseline, ...patch } };
167
+ assert.equal(hasValidNativeValidationReceipt({ ...changed, receiptHash: calculatePolicyValidationDigest(changed) }, body), false);
168
+ }
169
+ const withoutParity = { ...baselineBody };
170
+ delete withoutParity.resourceParity;
171
+ assert.equal(hasValidNativeValidationReceipt({ ...withoutParity, receiptHash: calculateNativeValidationReceiptHash(withoutParity) }, body), false);
172
+ const controls = [
173
+ ["properties.minimumTlsVersion", "TLS1_2"],
174
+ ["properties.supportsHttpsTrafficOnly", true],
175
+ ["properties.allowBlobPublicAccess", false],
176
+ ["properties.allowSharedKeyAccess", false],
177
+ ];
178
+ const diagnostics = {
179
+ storage: {
180
+ coverage: "storage-account-property-hardening-v1",
181
+ fullBaselineEvaluated: false,
182
+ sourceHash: hash,
183
+ inputHash: otherHash,
184
+ bindingHash: hash,
185
+ outcome: "pass",
186
+ results: controls.map(([propertyPath, expected]) => ({
187
+ propertyPath,
188
+ expectedValueDigest: calculatePolicyValidationDigest(expected),
189
+ observedValueDigest: calculatePolicyValidationDigest(expected),
190
+ outcome: "pass",
191
+ reason: "matched",
192
+ })),
193
+ },
194
+ };
195
+ const check = (storageSecurity) => {
196
+ const changed = { ...body, storageSecurity };
197
+ return hasValidNativeValidationReceipt({ ...changed, receiptHash: calculateNativeValidationReceiptHash(changed) }, body);
198
+ };
199
+ assert.equal(check(diagnostics), true);
200
+ for (const mutation of [
201
+ "path",
202
+ "expected",
203
+ "duplicate",
204
+ "reason",
205
+ "mismatch-digests",
206
+ "missing-observed",
207
+ "mixed-inputs",
208
+ ]) {
209
+ const changed = structuredClone(diagnostics);
210
+ const result = changed.storage.results[0];
211
+ if (mutation === "path")
212
+ result.propertyPath = "unrelated";
213
+ else if (mutation === "expected")
214
+ result.expectedValueDigest = result.observedValueDigest = hash;
215
+ else if (mutation === "duplicate")
216
+ changed.storage.results[1] = { ...result };
217
+ else if (mutation === "mixed-inputs")
218
+ changed.other = { ...changed.storage, inputHash: hash };
219
+ else {
220
+ changed.storage.outcome = result.outcome = "fail";
221
+ result.reason = mutation === "reason" ? "unsupported-expression" : "value-mismatch";
222
+ if (mutation === "missing-observed")
223
+ delete result.observedValueDigest;
224
+ }
225
+ assert.equal(check(changed), false, mutation);
226
+ }
227
+ }
228
+ assert.equal(schemaById[NativeValidationReceiptV1Schema.$id], NativeValidationReceiptV1Schema);
229
+ assert.equal(contractMetadata[NativeValidationReceiptV1Schema.$id]?.maxBytes, 8_404_992);
230
+ assert.equal(calculateNativeValidationReceiptHash(Object.fromEntries(Object.entries(body).reverse())), receipt.receiptHash);
231
+ for (const key of ["projectId", "runId", "track", "sourceHash", "treeHash", "policyHash", "inputHash"]) {
232
+ assert.equal(hasValidNativeValidationReceipt(receipt, { ...body, [key]: "different" }), false, key);
233
+ assert.equal(hasValidNativeValidationReceipt({ ...receipt, [key]: "different" }, body), false, key);
234
+ }
235
+ for (const invalid of [
236
+ { ...receipt, receiptHash: otherHash },
237
+ { ...receipt, schemaVersion: "2.0.0" },
238
+ { ...receipt, stdout: "private-source" },
239
+ { ...receipt, rootPath: "/private/path" },
240
+ { ...receipt, compliance: "pass" },
241
+ { ...receipt, outcome: "block" },
242
+ { ...receipt, commands: [] },
243
+ { ...receipt, commands: [...receipt.commands, ...receipt.commands, ...receipt.commands, ...receipt.commands] },
244
+ ...[
245
+ { stdout: "private-source" },
246
+ { stderr: "private-diagnostic" },
247
+ { path: "/private/path" },
248
+ { exitCode: 1 },
249
+ { signal: "SIGTERM" },
250
+ { timedOut: true },
251
+ { outputTruncated: true },
252
+ { validatorId: "bicep:lint" },
253
+ { commandHash: "invalid" },
254
+ ].map((extra) => ({
255
+ ...receipt,
256
+ commands: [{ ...receipt.commands[0], ...extra }, ...receipt.commands.slice(1)],
257
+ })),
258
+ ]) {
259
+ assert.equal(hasValidNativeValidationReceipt(invalid, body), false);
260
+ }
261
+ for (const commands of [
262
+ body.commands.slice(1),
263
+ body.commands.filter(({ validatorId }) => validatorId === "bicep:build"),
264
+ [...body.commands, body.commands[0]],
265
+ body.commands.map((command) => ({ ...command, commandHash: otherHash })),
266
+ body.commands.map((command) => ({ ...command, validatorId: "terraform:validate" })),
267
+ ]) {
268
+ const tampered = { ...body, commands };
269
+ assert.equal(hasValidNativeValidationReceipt({ ...tampered, receiptHash: calculateNativeValidationReceiptHash(tampered) }, body), false);
270
+ }
271
+ if (body.commands.length > 1) {
272
+ const reordered = { ...body, commands: [...body.commands].reverse() };
273
+ assert.equal(hasValidNativeValidationReceipt({ ...reordered, receiptHash: calculateNativeValidationReceiptHash(reordered) }, body), false);
274
+ }
275
+ });
276
+ }
277
+ it("binds archetype origin proposals without accepting imported authority", () => {
278
+ const body = {
279
+ schemaVersion: "1.0.0",
280
+ repositoryPath: "/source/coe",
281
+ revision: "a".repeat(40),
282
+ selectedPath: "archetypes/storage",
283
+ authorityImported: false,
284
+ requiresConsumerReview: true,
285
+ files: [{ path: "main.bicep", hash, bytes: 10 }],
286
+ excluded: [],
287
+ };
288
+ const proposal = { ...body, contentHash: calculatePolicyValidationDigest(body) };
289
+ assert.equal(hasValidArchetypeSourceProposal(proposal), true);
290
+ for (const changed of [
291
+ { ...body, authorityImported: true },
292
+ { ...body, requiresConsumerReview: false },
293
+ { ...body, revision: "HEAD" },
294
+ { ...body, selectedPath: "../outside" },
295
+ { ...body, files: [{ path: "/absolute", hash, bytes: 10 }] },
296
+ { ...body, files: [{ path: "nested/../outside", hash, bytes: 10 }] },
297
+ { ...body, files: [{ path: "main.bicep", hash, bytes: 1_048_577 }] },
298
+ { ...body, excluded: [{ path: "MAIN.bicep", reason: "source-authority" }] },
299
+ { ...body, approval: true },
300
+ ])
301
+ assert.equal(hasValidArchetypeSourceProposal({ ...changed, contentHash: calculatePolicyValidationDigest(changed) }), false);
302
+ assert.equal(hasValidArchetypeSourceProposal({ ...proposal, revision: "b".repeat(40) }), false);
303
+ });
304
+ it("bounds requirements amendments without allowing identity or requirement-ID replacement", () => {
305
+ const amendment = {
306
+ schemaVersion: "1.0.0",
307
+ baseRequirementsHash: "a".repeat(64),
308
+ updates: [{ id: "REQ-1", changes: { statement: "Updated objective" } }],
309
+ additions: [],
310
+ removals: [],
311
+ fields: { budgetAndOperations: "EUR 500" },
312
+ };
313
+ assert.equal(Value.Check(RequirementsAmendmentV1Schema, amendment), true);
314
+ for (const changed of [
315
+ { ...amendment, baseRequirementsHash: "invalid" },
316
+ { ...amendment, updates: Array.from({ length: 129 }, () => amendment.updates[0]) },
317
+ { ...amendment, updates: [{ id: "REQ-1", changes: {} }] },
318
+ { ...amendment, updates: [{ id: "REQ-1", changes: { id: "REQ-2" } }] },
319
+ ...["schemaVersion", "projectId", "environment", "requirements"].map((key) => ({
320
+ ...amendment,
321
+ fields: { [key]: "changed" },
322
+ })),
323
+ { ...amendment, approved: true },
324
+ ])
325
+ assert.equal(Value.Check(RequirementsAmendmentV1Schema, changed), false);
326
+ });
327
+ it("keeps requirements change proposals bounded and distinct from deployment authority", () => {
328
+ const proposal = {
329
+ schemaVersion: "1.0.0",
330
+ projectId: "demo",
331
+ runId: "run-1",
332
+ expectedHead: hash,
333
+ ownerEpoch: 0,
334
+ sourceRequirementsHash: hash,
335
+ candidateHash: hash,
336
+ reason: "Change budget",
337
+ mode: "revise",
338
+ addedRequirementIds: [],
339
+ removedRequirementIds: [],
340
+ changedRequirementIds: ["budget"],
341
+ retainedRequirementIds: ["availability"],
342
+ changedFields: [],
343
+ invalidatedNodes: ["requirements"],
344
+ invalidatedGates: [1, 2, 3, 4],
345
+ requiresReassessment: ["cost", "policy", "security", "dependencies", "code", "documents"],
346
+ filesModified: false,
347
+ deploymentAuthorized: false,
348
+ proposalHash: hash,
349
+ };
350
+ assert.equal(Value.Check(RequirementsChangeProposalV1Schema, proposal), true);
351
+ assert.equal(Value.Check(RequirementsChangeProposalV1Schema, { ...proposal, mode: "adopt", sourceRequirementsHash: null }), true);
352
+ for (const changed of [
353
+ { ...proposal, deploymentAuthorized: true },
354
+ { ...proposal, filesModified: true },
355
+ { ...proposal, ownerEpoch: -1 },
356
+ { ...proposal, expectedHead: "HEAD" },
357
+ { ...proposal, invalidatedGates: [5] },
358
+ { ...proposal, changedRequirementIds: ["same", "same"] },
359
+ { ...proposal, reason: "x".repeat(2049) },
360
+ { ...proposal, approval: true },
361
+ ])
362
+ assert.equal(Value.Check(RequirementsChangeProposalV1Schema, changed), false);
363
+ });
364
+ it("requires explicit alternatives and all WAF impacts for structured Architecture decisions", () => {
365
+ const record = {
366
+ id: "ADR-0001",
367
+ title: "Service selection",
368
+ context: "Workload constraints",
369
+ decision: "Selected service",
370
+ requirementIds: ["REQ-1"],
371
+ alternatives: [
372
+ { option: "Alternative A", benefits: "Simple", drawbacks: "Capacity", rejectionReason: "Cannot meet demand" },
373
+ {
374
+ option: "Alternative B",
375
+ benefits: "Flexible",
376
+ drawbacks: "Operations",
377
+ rejectionReason: "Requires unavailable staffing",
378
+ },
379
+ ],
380
+ positiveConsequences: ["Meets demand"],
381
+ negativeConsequences: ["Higher baseline cost"],
382
+ wafImpacts: {
383
+ security: "Identity controls",
384
+ reliability: "Recovery design",
385
+ "performance-efficiency": "Capacity",
386
+ "cost-optimization": "Cost trade-off",
387
+ "operational-excellence": "Staffing",
388
+ },
389
+ complianceConsiderations: "Review against target policy",
390
+ implementationNotes: "Bind selected service in plan",
391
+ };
392
+ const schema = ArchitectureV1Schema.properties.decisionRecords.items;
393
+ assert.equal(Value.Check(schema, record), true);
394
+ for (const changed of [
395
+ { ...record, alternatives: [] },
396
+ { ...record, negativeConsequences: [] },
397
+ { ...record, wafImpacts: { security: "Only one pillar" } },
398
+ { ...record, approval: true },
399
+ { ...record, id: "../escape" },
400
+ ])
401
+ assert.equal(Value.Check(schema, changed), false);
402
+ });
403
+ it("operational handoff describes procedures without asserting unobserved execution", () => {
404
+ const procedure = {
405
+ applicability: "applicable",
406
+ owner: "Operations",
407
+ prerequisites: ["Approved maintenance"],
408
+ steps: ["Follow resource-specific procedure"],
409
+ verification: "Verify expected health",
410
+ executionStatus: "untested",
411
+ };
412
+ const handoff = {
413
+ owner: "Operations",
414
+ escalation: "On-call escalation",
415
+ maintenanceWindow: "Sunday 02:00 UTC",
416
+ accessPrerequisites: ["Read-only monitoring role"],
417
+ configurationReferences: [{ name: "SERVICE_ENDPOINT", source: "Deployment output reference" }],
418
+ healthChecks: [
419
+ { resourceId: "/resource", check: "Inspect health endpoint", expectedOutcome: "Healthy", evidenceRefs: [] },
420
+ ],
421
+ monitoring: "Review target workspace alerts",
422
+ incidentResponse: procedure,
423
+ rollback: procedure,
424
+ recovery: {
425
+ applicability: "not-applicable",
426
+ rationale: "Stateless component; persistent data is externally owned",
427
+ },
428
+ limitations: ["Procedures have not been exercised"],
429
+ };
430
+ const schema = DiagnosisV1Schema.properties.operationalHandoff;
431
+ assert.equal(Value.Check(schema, handoff), true);
432
+ for (const changed of [
433
+ { ...handoff, recovery: { applicability: "not-applicable" } },
434
+ { ...handoff, rollback: { ...procedure, executionStatus: "tested" } },
435
+ { ...handoff, healthChecks: [] },
436
+ { ...handoff, approval: true },
437
+ ])
438
+ assert.equal(Value.Check(schema, changed), false);
439
+ });
440
+ it("bounds native diagnostic scope references without arbitrary expressions", () => {
441
+ const source = {
442
+ schemaVersion: "1.0.0",
443
+ projectId: "demo",
444
+ runId: "run",
445
+ track: "bicep",
446
+ intentHash: hash,
447
+ resourceBindings: {
448
+ diagnostic: {
449
+ implementation: "native:Microsoft.Insights/diagnosticSettings@2021-05-01-preview",
450
+ version: "2021-05-01-preview",
451
+ scopeLogicalId: "storage",
452
+ parameters: {},
453
+ },
454
+ },
455
+ };
456
+ assert.equal(Value.Check(IacBindingV1Schema, source), true);
457
+ for (const scopeLogicalId of ["../outside", "[resourceId('x')]", "foreign/id", "", "x".repeat(257)])
458
+ assert.equal(Value.Check(IacBindingV1Schema, {
459
+ ...source,
460
+ resourceBindings: { diagnostic: { ...source.resourceBindings.diagnostic, scopeLogicalId } },
461
+ }), false);
462
+ });
17
463
  it("uses one explicit persisted contract version", () => {
18
464
  const lock = {
19
465
  schemaVersion: CONTRACT_VERSION,
@@ -49,15 +495,151 @@ describe("Wave 1 contracts", () => {
49
495
  };
50
496
  assert.equal(Value.Check(RequirementsV1Schema, requirements), true);
51
497
  });
498
+ it("validates optional strict bounded intended physical resource scope on bindings", () => {
499
+ const primary = {
500
+ resourceId: "/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/workload/providers/Microsoft.Storage/storageAccounts/storage",
501
+ type: "Microsoft.Storage/storageAccounts",
502
+ ownership: "managed",
503
+ role: "primary",
504
+ };
505
+ const resourceBinding = {
506
+ implementation: "avm:br/public:avm/res/storage/storage-account@0.9.0",
507
+ version: "0.9.0",
508
+ parameters: {},
509
+ };
510
+ const binding = {
511
+ schemaVersion: CONTRACT_VERSION,
512
+ projectId: "demo",
513
+ runId: "run-test",
514
+ track: "bicep",
515
+ intentHash: hash,
516
+ resourceBindings: { storage: resourceBinding },
517
+ };
518
+ const withResources = (physicalResources) => ({
519
+ ...binding,
520
+ resourceBindings: { storage: { ...resourceBinding, physicalResources } },
521
+ });
522
+ assert.equal(Value.Check(IacBindingV1Schema, binding), true);
523
+ assert.equal(Value.Check(IacBindingV1Schema, withResources([primary])), true);
524
+ assert.equal(Value.Check(IacBindingV1Schema, withResources([{ ...primary, resourceId: primary.resourceId.toUpperCase(), type: primary.type.toUpperCase() }])), true);
525
+ const bounded = Array.from({ length: 128 }, (_, index) => ({
526
+ ...primary,
527
+ resourceId: `${primary.resourceId}${index}`,
528
+ role: index === 0 ? "primary" : "ancillary",
529
+ ownership: index === 0 ? "managed" : "existing",
530
+ }));
531
+ assert.equal(Value.Check(IacBindingV1Schema, withResources(bounded)), true);
532
+ for (const physicalResources of [
533
+ [],
534
+ null,
535
+ {},
536
+ [primary, primary],
537
+ [...bounded, primary],
538
+ [{ ...primary, unexpected: true }],
539
+ [{ ...primary, ownership: "observed" }],
540
+ [{ ...primary, role: "secondary" }],
541
+ [{ ...primary, type: "" }],
542
+ [{ ...primary, type: `Microsoft.Storage/${"a".repeat(256)}` }],
543
+ [{ ...primary, resourceId: `${primary.resourceId}${"a".repeat(2048)}` }],
544
+ ...["*", "%2f", "?query", "#fragment", "[expression]", "${expression}", "\n", "\r\n"].map((suffix) => [
545
+ { ...primary, resourceId: `${primary.resourceId}${suffix}` },
546
+ ]),
547
+ [{ ...primary, type: `${primary.type}\n` }],
548
+ ...Object.keys(primary).map((key) => [
549
+ Object.fromEntries(Object.entries(primary).filter(([field]) => field !== key)),
550
+ ]),
551
+ ]) {
552
+ assert.equal(Value.Check(IacBindingV1Schema, withResources(physicalResources)), false);
553
+ }
554
+ });
555
+ it("bootstrap preflight cannot assert execution authority or hide unassessed operations", () => {
556
+ const plan = {
557
+ schemaVersion: "1.0.0",
558
+ config: { schemaVersion: "1.0.0", projectId: "demo" },
559
+ configHash: "a".repeat(64),
560
+ runtimeVersion: "0.11.0-next.0",
561
+ scope: "local-bootstrap-preflight-v1",
562
+ status: "pending",
563
+ checks: ["repository", "workspace-runtime", "apex-state"].map((id) => ({
564
+ id,
565
+ status: "pending",
566
+ reason: "Needs setup",
567
+ })),
568
+ unassessed: [
569
+ "machine-prerequisites",
570
+ "client-health",
571
+ "remote-coe",
572
+ "github-repository",
573
+ "governance-oidc",
574
+ "reviewed-baseline",
575
+ ],
576
+ filesModified: false,
577
+ executionAuthorized: false,
578
+ };
579
+ assert.equal(Value.Check(BootstrapPlanV1Schema, plan), true);
580
+ for (const changed of [
581
+ { ...plan, executionAuthorized: true },
582
+ { ...plan, filesModified: true },
583
+ { ...plan, unassessed: [] },
584
+ { ...plan, checks: [] },
585
+ { ...plan, configHash: "invalid" },
586
+ { ...plan, token: "secret" },
587
+ ])
588
+ assert.equal(Value.Check(BootstrapPlanV1Schema, changed), false);
589
+ });
590
+ it("governance setup inputs reject secrets, malformed scopes and incomplete reused identities", () => {
591
+ const config = {
592
+ schemaVersion: "1.0.0",
593
+ repository: "Example/COE",
594
+ tenantId: "a".repeat(8) + "-1111-1111-1111-111111111111",
595
+ subscriptionId: "22222222-2222-2222-2222-222222222222",
596
+ identity: { mode: "create", displayName: "coe-reader" },
597
+ };
598
+ assert.equal(Value.Check(GovernanceSetupConfigV1Schema, config), true);
599
+ assert.equal(Value.Check(GovernanceSetupConfigV1Schema, { ...config, managementGroupId: "a" }), true);
600
+ for (const invalid of [
601
+ { ...config, clientSecret: "forbidden" },
602
+ { ...config, managementGroupId: "../root" },
603
+ { ...config, repository: "Example/COE\n" },
604
+ { ...config, tenantId: config.tenantId + "\n" },
605
+ { ...config, managementGroupId: "platform\n" },
606
+ { ...config, identity: { mode: "reuse", clientId: config.tenantId } },
607
+ { ...config, repository: "Example/COE:environment:production" },
608
+ { ...config, identity: { mode: "create", displayName: "coe", role: "Owner" } },
609
+ ])
610
+ assert.equal(Value.Check(GovernanceSetupConfigV1Schema, invalid), false);
611
+ for (const field of ["filesModified", "executionAuthorized", "deploymentAuthorized"])
612
+ assert.equal(Value.Check(GovernanceSetupPlanV1Schema.properties[field], true), false);
613
+ });
614
+ it("batch archetype configuration requires bounded independent remote selections", () => {
615
+ const config = {
616
+ schemaVersion: "1.0.0",
617
+ repository: "https://github.com/example/coe",
618
+ revision: "a".repeat(40),
619
+ selections: [{ selectedPath: "archetypes/storage", destination: "storage" }],
620
+ };
621
+ assert.equal(Value.Check(ArchetypeBatchConfigV1Schema, config), true);
622
+ for (const invalid of [
623
+ { ...config, repository: "/local/path" },
624
+ { ...config, revision: "main" },
625
+ { ...config, selections: [] },
626
+ { ...config, selections: Array.from({ length: 17 }, () => config.selections[0]) },
627
+ { ...config, selections: [{ selectedPath: "../escape", destination: "storage" }] },
628
+ { ...config, selections: [{ selectedPath: "archetypes/storage", destination: "nested/workload" }] },
629
+ { ...config, authorityImported: true },
630
+ ])
631
+ assert.equal(Value.Check(ArchetypeBatchConfigV1Schema, invalid), false);
632
+ });
52
633
  it("validates strict onboarding configuration with optional defaults", () => {
53
634
  const config = {
54
635
  schemaVersion: CONTRACT_VERSION,
55
636
  projectId: "payments",
56
- client: "github-copilot-vscode",
637
+ client: "github-copilot-cli",
57
638
  createRepository: true,
58
639
  };
59
640
  assert.equal(Value.Check(OnboardingConfigV1Schema, config), true);
60
- assert.equal(Value.Check(OnboardingConfigV1Schema, { ...config, client: "unsupported" }), false);
641
+ for (const client of ["github-copilot-vscode", "both", "unsupported"])
642
+ assert.equal(Value.Check(OnboardingConfigV1Schema, { ...config, client }), false);
61
643
  assert.equal(Value.Check(OnboardingConfigV1Schema, { ...config, unexpected: true }), false);
62
644
  });
63
645
  it("binds live qualification evidence to an exact candidate", () => {
@@ -111,6 +693,32 @@ describe("Wave 1 contracts", () => {
111
693
  assert.match(schema.$id ?? "", /^https:\/\/schemas\.apexops\.dev\//);
112
694
  }
113
695
  });
696
+ it("validates strict bounded repeat-guard records", () => {
697
+ const record = {
698
+ fingerprint: hash,
699
+ callHash: otherHash,
700
+ operation: "stageArtifact",
701
+ stateBefore: null,
702
+ stateAfter: hash,
703
+ recordedAt: timestamp,
704
+ expiresAt: timestamp,
705
+ result: '{"staged":true}',
706
+ };
707
+ const file = { schemaVersion: CONTRACT_VERSION, records: [record, { ...record, stateBefore: otherHash }] };
708
+ assert.equal(Value.Check(RepeatGuardRecordsV1Schema, file), true);
709
+ assert.equal(contractMetadata[RepeatGuardRecordsV1Schema.$id]?.sensitivity, "confidential");
710
+ for (const invalid of [
711
+ { ...file, unexpected: true },
712
+ { ...file, schemaVersion: "2.0.0" },
713
+ { ...file, records: [{ ...record, unexpected: true }] },
714
+ { ...file, records: [{ ...record, callHash: "not-a-hash" }] },
715
+ { ...file, records: [{ ...record, operation: "1bad" }] },
716
+ { ...file, records: [{ ...record, result: "x".repeat(65_537) }] },
717
+ { ...file, records: Array.from({ length: 17 }, () => record) },
718
+ ]) {
719
+ assert.equal(Value.Check(RepeatGuardRecordsV1Schema, invalid), false);
720
+ }
721
+ });
114
722
  it("validates bounded improvement contracts", () => {
115
723
  const observation = {
116
724
  schemaVersion: CONTRACT_VERSION,
@@ -372,6 +980,7 @@ describe("target family contracts", () => {
372
980
  {
373
981
  id: "api",
374
982
  service: "Azure App Service",
983
+ resourceTypes: ["Microsoft.Web/sites"],
375
984
  purpose: "Host API",
376
985
  requirementIds: ["REQ-001"],
377
986
  dependsOn: [],
@@ -379,6 +988,25 @@ describe("target family contracts", () => {
379
988
  ],
380
989
  decisions: ["Use managed identity"],
381
990
  risks: [],
991
+ wellArchitectedAssessment: {
992
+ framework: "azure-well-architected-framework",
993
+ assessmentType: "qualitative",
994
+ pillars: [
995
+ "security",
996
+ "reliability",
997
+ "performance-efficiency",
998
+ "cost-optimization",
999
+ "operational-excellence",
1000
+ ].map((pillar) => ({
1001
+ pillar,
1002
+ status: "aligned",
1003
+ assessment: `${pillar} requirements are addressed`,
1004
+ requirementIds: ["REQ-001"],
1005
+ evidenceRefs: [hash],
1006
+ recommendations: [],
1007
+ tradeoffs: [],
1008
+ })),
1009
+ },
382
1010
  },
383
1011
  ],
384
1012
  [
@@ -415,6 +1043,13 @@ describe("target family contracts", () => {
415
1043
  subjectKind: "architecture-v1",
416
1044
  subjectHash: hash,
417
1045
  reviewedAt: timestamp,
1046
+ capture: {
1047
+ reviewer: "rubber-duck",
1048
+ nonce: "0123456789abcdef0123456789abcdef",
1049
+ captureHash: otherHash,
1050
+ promptSha256: hash,
1051
+ responseSha256: otherHash,
1052
+ },
418
1053
  findings: [
419
1054
  {
420
1055
  id: "finding-1",
@@ -426,6 +1061,18 @@ describe("target family contracts", () => {
426
1061
  resolution: "Added zone-redundant deployment",
427
1062
  },
428
1063
  ],
1064
+ criteria: [
1065
+ "security",
1066
+ "reliability",
1067
+ "performance-efficiency",
1068
+ "cost-optimization",
1069
+ "operational-excellence",
1070
+ ].map((criterionId) => ({
1071
+ criterionId,
1072
+ outcome: criterionId === "reliability" ? "finding" : "pass",
1073
+ rationale: `${criterionId} was reviewed`,
1074
+ findingIds: criterionId === "reliability" ? ["finding-1"] : [],
1075
+ })),
429
1076
  },
430
1077
  ],
431
1078
  [
@@ -435,6 +1082,7 @@ describe("target family contracts", () => {
435
1082
  projectId: "example-project",
436
1083
  runId: "run-1",
437
1084
  targetScope: "/subscriptions/example",
1085
+ source: "collected",
438
1086
  discoveredAt: timestamp,
439
1087
  expiresAt: expiry,
440
1088
  summary: { assignmentCount: 3, denyCount: 1, modifyCount: 1, auditCount: 1, exemptionCount: 0 },
@@ -677,6 +1325,42 @@ describe("target family contracts", () => {
677
1325
  lockedAt: timestamp,
678
1326
  },
679
1327
  ],
1328
+ [
1329
+ ReviewCaptureV1Schema,
1330
+ {
1331
+ schema: "apex-review-capture-v1",
1332
+ nonce: "0123456789abcdef0123456789abcdef",
1333
+ sessionId: null,
1334
+ toolName: "task",
1335
+ agentType: "rubber-duck",
1336
+ prompt: "APEX-REVIEW: nonce=0123456789abcdef0123456789abcdef",
1337
+ requestSha256: hash,
1338
+ response: '```apex-review\n{"findings":[]}\n```',
1339
+ responseSha256: otherHash,
1340
+ capturedAt: timestamp,
1341
+ signature: hash,
1342
+ },
1343
+ ],
1344
+ [
1345
+ ReviewRequestV1Schema,
1346
+ {
1347
+ schemaVersion: CONTRACT_VERSION,
1348
+ nonce: "0123456789abcdef0123456789abcdef",
1349
+ agentType: "rubber-duck",
1350
+ mode: "sync",
1351
+ gate: 1,
1352
+ subjectKind: "requirements",
1353
+ subjectHash: hash,
1354
+ attempt: 1,
1355
+ maxAttempts: 2,
1356
+ prompt: "APEX-REVIEW: nonce=0123456789abcdef0123456789abcdef",
1357
+ promptSha256: otherHash,
1358
+ files: [
1359
+ { label: "instructions", kind: "instructions", path: "/workspace/instructions.md", sha256: hash },
1360
+ { label: "subject", kind: "requirements", path: "/workspace/subject.json", sha256: otherHash },
1361
+ ],
1362
+ },
1363
+ ],
680
1364
  ];
681
1365
  it("validates a representative fixture for every target family", () => {
682
1366
  for (const [schema, fixture] of fixtures) {
@@ -693,6 +1377,42 @@ describe("target family contracts", () => {
693
1377
  questions: [{ id: "region", prompt: "Which region?", options: ["sweden", "germany"] }],
694
1378
  };
695
1379
  assert.equal(Value.Check(InputRequestV1Schema, request), true);
1380
+ const { intake: _intake, ...base } = request;
1381
+ const governance = {
1382
+ candidatePath: "governance/baseline.json",
1383
+ candidateHash: hash,
1384
+ observedAt: "2026-09-01T00:00:00Z",
1385
+ requestedAt: "2026-09-19T00:00:00Z",
1386
+ expiresAt: "2026-09-20T00:00:00Z",
1387
+ targetScope: "/subscriptions/11111111-1111-1111-1111-111111111111",
1388
+ refreshRequired: false,
1389
+ };
1390
+ assert.equal(Value.Check(InputRequestV1Schema, { ...base, governance }), true);
1391
+ assert.equal(Value.Check(InputRequestV1Schema, { ...request, governance }), false);
1392
+ assert.equal(Value.Check(InputRequestV1Schema, { ...base, governance, decision: { taskId: "task-1", id: "choice" } }), false);
1393
+ for (const candidatePath of [
1394
+ "/baseline.json",
1395
+ "C:/baseline.json",
1396
+ "../baseline.json",
1397
+ "dir/../baseline.json",
1398
+ "./baseline.json",
1399
+ "dir\\baseline.json",
1400
+ "bad\u0000.json",
1401
+ "a".repeat(4097),
1402
+ ]) {
1403
+ assert.equal(Value.Check(InputRequestV1Schema, { ...base, governance: { ...governance, candidatePath } }), false);
1404
+ }
1405
+ for (const extra of [
1406
+ { candidateHash: "bad" },
1407
+ { observedAt: "not-a-date" },
1408
+ { requestedAt: undefined },
1409
+ { requestedAt: null },
1410
+ { requestedAt: "not-a-date" },
1411
+ { refreshRequired: "false" },
1412
+ { snapshot: {} },
1413
+ ]) {
1414
+ assert.equal(Value.Check(InputRequestV1Schema, { ...base, governance: { ...governance, ...extra } }), false);
1415
+ }
696
1416
  assert.equal(Value.Check(InputRequestV1Schema, {
697
1417
  schemaVersion: CONTRACT_VERSION,
698
1418
  requestId: request.requestId,
@@ -719,7 +1439,13 @@ describe("target family contracts", () => {
719
1439
  }), true);
720
1440
  assert.equal(hasValidInputRequestQuestions([
721
1441
  { id: "one", prompt: "One?" },
722
- { id: "two", prompt: "Two?", options: ["a", "b"], multiSelect: true },
1442
+ {
1443
+ id: "two",
1444
+ prompt: "Two?",
1445
+ options: ["a", "b"],
1446
+ multiSelect: true,
1447
+ recommendation: { value: ["a"], source: "default", rationale: "Recommended baseline." },
1448
+ },
723
1449
  ]), true);
724
1450
  assert.equal(hasValidInputRequestQuestions([
725
1451
  { id: "same", prompt: "One?" },
@@ -728,6 +1454,17 @@ describe("target family contracts", () => {
728
1454
  assert.equal(hasValidInputRequestQuestions([{ id: "bad", prompt: "Bad?", multiSelect: true }]), false);
729
1455
  assert.equal(hasValidInputRequestQuestions([{ id: "bad", prompt: "Bad?", options: [] }]), false);
730
1456
  assert.equal(hasValidInputRequestQuestions([{ id: "bad", prompt: "Bad?", options: ["same", "same"] }]), false);
1457
+ assert.equal(hasValidInputRequestQuestions([
1458
+ {
1459
+ id: "bad",
1460
+ prompt: "Bad?",
1461
+ options: ["a", "b"],
1462
+ recommendation: { value: "c", source: "derived", rationale: "Outside options." },
1463
+ },
1464
+ ]), false);
1465
+ assert.equal(hasValidInputRequestQuestions([
1466
+ { id: "bad", prompt: "Bad?", options: ["a", "b"], recommendation: null },
1467
+ ]), false);
731
1468
  assert.equal(Value.Check(InputRequestV1Schema, {
732
1469
  ...request,
733
1470
  questions: [{ id: "bad", prompt: "Bad?", options: ["same", "same"] }],
@@ -748,6 +1485,16 @@ describe("target family contracts", () => {
748
1485
  },
749
1486
  }), false);
750
1487
  });
1488
+ it("accepts optional non-empty execution addresses without changing binding descriptors", () => {
1489
+ const manifest = fixtures[7][1];
1490
+ assert.equal(Value.Check(LogicalResourceManifestV1Schema, manifest), true);
1491
+ for (const executionAddress of ["plan", "azapi_resource.plan", "data.azapi_resource.plan", "module.plan", "", 42]) {
1492
+ assert.equal(Value.Check(LogicalResourceManifestV1Schema, {
1493
+ ...manifest,
1494
+ resources: manifest.resources.map((resource) => ({ ...resource, executionAddress })),
1495
+ }), typeof executionAddress === "string" && executionAddress.length > 0);
1496
+ }
1497
+ });
751
1498
  it("requires unique logical IDs and resolvable dependency references", () => {
752
1499
  const manifest = fixtures[7][1];
753
1500
  assert.equal(hasValidLogicalResourceReferences(manifest), true);
@@ -768,6 +1515,24 @@ describe("target family contracts", () => {
768
1515
  ],
769
1516
  }), false);
770
1517
  });
1518
+ it("requires track-specific read-only declarations for existing resource ownership", () => {
1519
+ const manifest = fixtures[7][1];
1520
+ for (const track of ["bicep", "terraform"]) {
1521
+ for (const implementationKind of ["resource", "module", "data", "existing"]) {
1522
+ for (const ownership of ["managed", "existing"]) {
1523
+ const referenceKind = track === "bicep" ? "existing" : "data";
1524
+ const expected = ownership === "existing"
1525
+ ? implementationKind === referenceKind
1526
+ : implementationKind === "resource" || implementationKind === "module";
1527
+ assert.equal(hasValidLogicalResourceReferences({
1528
+ ...manifest,
1529
+ track,
1530
+ resources: manifest.resources.map((resource) => ({ ...resource, implementationKind, ownership })),
1531
+ }), expected, `${track}: ${implementationKind} with ${ownership} ownership`);
1532
+ }
1533
+ }
1534
+ }
1535
+ });
771
1536
  it("binds encrypted plan attestations to the preview and approval recipient", () => {
772
1537
  const attestation = fixtures[9][1];
773
1538
  const preview = {