@calltelemetry/ct-lab-mcp 0.8.150 → 0.8.152

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 (64) hide show
  1. package/dist/src/generated-version.d.ts +1 -1
  2. package/dist/src/generated-version.js +1 -1
  3. package/dist/src/inspection/lab-inspection.d.ts +16293 -0
  4. package/dist/src/inspection/lab-inspection.d.ts.map +1 -0
  5. package/dist/src/inspection/lab-inspection.js +964 -0
  6. package/dist/src/inspection/lab-inspection.js.map +1 -0
  7. package/dist/src/inspection/read-provenance.d.ts +44 -0
  8. package/dist/src/inspection/read-provenance.d.ts.map +1 -0
  9. package/dist/src/inspection/read-provenance.js +28 -0
  10. package/dist/src/inspection/read-provenance.js.map +1 -0
  11. package/dist/src/inspection/runtime-artifact.d.ts +16 -0
  12. package/dist/src/inspection/runtime-artifact.d.ts.map +1 -0
  13. package/dist/src/inspection/runtime-artifact.js +99 -0
  14. package/dist/src/inspection/runtime-artifact.js.map +1 -0
  15. package/dist/src/lab-exec/claim-resolve.d.ts +97 -0
  16. package/dist/src/lab-exec/claim-resolve.d.ts.map +1 -1
  17. package/dist/src/lab-exec/claim-resolve.js +5 -0
  18. package/dist/src/lab-exec/claim-resolve.js.map +1 -1
  19. package/dist/src/lab-exec/executor.d.ts +3 -0
  20. package/dist/src/lab-exec/executor.d.ts.map +1 -1
  21. package/dist/src/lab-exec/executor.js +4 -1
  22. package/dist/src/lab-exec/executor.js.map +1 -1
  23. package/dist/src/lab-exec/remote.d.ts +3 -0
  24. package/dist/src/lab-exec/remote.d.ts.map +1 -1
  25. package/dist/src/lab-exec/remote.js +5 -0
  26. package/dist/src/lab-exec/remote.js.map +1 -1
  27. package/dist/src/lab-exec/server.d.ts.map +1 -1
  28. package/dist/src/lab-exec/server.js +3 -2
  29. package/dist/src/lab-exec/server.js.map +1 -1
  30. package/dist/src/tools/appliance-candidate-retire.d.ts +6 -6
  31. package/dist/src/tools/appliance-candidate-update.d.ts +6 -6
  32. package/dist/src/tools/appliance-claim-tools.d.ts +62 -3
  33. package/dist/src/tools/appliance-claim-tools.d.ts.map +1 -1
  34. package/dist/src/tools/appliance-claim-tools.js +810 -16
  35. package/dist/src/tools/appliance-claim-tools.js.map +1 -1
  36. package/dist/src/tools/canonical-guard.d.ts +1 -1
  37. package/dist/src/tools/canonical-guard.d.ts.map +1 -1
  38. package/dist/src/tools/canonical-guard.js +8 -0
  39. package/dist/src/tools/canonical-guard.js.map +1 -1
  40. package/dist/src/tools/claim-lifecycle.d.ts +4 -4
  41. package/dist/src/tools/claimed-import-ova.d.ts +9 -9
  42. package/dist/src/tools/claimed-import-qcow.d.ts +2 -2
  43. package/dist/src/tools/cube-canonical.d.ts +2 -2
  44. package/dist/src/tools/host-migrate-vm.d.ts +4 -4
  45. package/dist/src/tools/import-qcow.d.ts +6 -6
  46. package/dist/src/tools/index.d.ts.map +1 -1
  47. package/dist/src/tools/index.js +7 -2
  48. package/dist/src/tools/index.js.map +1 -1
  49. package/dist/src/tools/lab-dev.d.ts +38 -38
  50. package/dist/src/tools/list-hosts.d.ts.map +1 -1
  51. package/dist/src/tools/list-hosts.js +16 -4
  52. package/dist/src/tools/list-hosts.js.map +1 -1
  53. package/dist/src/tools/list-inventory.d.ts.map +1 -1
  54. package/dist/src/tools/list-inventory.js +13 -3
  55. package/dist/src/tools/list-inventory.js.map +1 -1
  56. package/dist/src/tools/provision-tools.d.ts +20 -20
  57. package/dist/src/tools/quick-provision.d.ts +2 -2
  58. package/dist/src/tools/sandbox-tools.d.ts +4 -4
  59. package/dist/src/tools/slot-tools.d.ts +8 -8
  60. package/dist/src/tools/storage-tools.d.ts +8 -8
  61. package/dist/src/tools/uat-access.d.ts +2 -2
  62. package/dist/src/tools/vm-action.d.ts +8 -8
  63. package/dist/src/tools/vm-repair.d.ts +6 -6
  64. package/package.json +1 -1
@@ -0,0 +1,964 @@
1
+ import { z } from "zod";
2
+ export const LAB_INSPECTION_SCHEMA = "ct-lab-inspection/v1";
3
+ export const CUBE_WORKFLOW_SCHEMA = "ct.appliance.cube-workflow/v1";
4
+ export const LIFECYCLE_DIAGNOSTIC_SCHEMA = "ct.appliance.lifecycle-diagnostic/v1";
5
+ export const CUBE_NETWORK_REVALIDATION_SCHEMA = "ct.appliance.cube-network-revalidation/v1";
6
+ export const WORKFLOW_PHASES = [
7
+ "clone_bind",
8
+ "nic_isolation",
9
+ "boot",
10
+ "ios_access",
11
+ "dhcp",
12
+ "network_ssh",
13
+ "running_config",
14
+ "startup_config",
15
+ "ready",
16
+ ];
17
+ export const WORKFLOW_CHECKPOINTS = ["intent_recorded", "result_recorded", "awaiting_readback"];
18
+ export const DIAGNOSTIC_CLASSIFICATIONS = ["transient", "terminal", "uncertain", "conflict", "integrity"];
19
+ export const EFFECT_CERTAINTIES = ["none", "confirmed", "unknown"];
20
+ export const RETRY_CLASSES = ["never", "bounded", "after_read_back", "manual_only"];
21
+ export const NEXT_ACTIONS = [
22
+ "none",
23
+ "read_back",
24
+ "wait",
25
+ "repair_access",
26
+ "repair_binding",
27
+ "resume_same_claim",
28
+ "continue_qualification",
29
+ "run_paired_call",
30
+ "retire",
31
+ "manual_review",
32
+ ];
33
+ const SafeCodeSchema = z.string().min(1).max(96).regex(/^[A-Z][A-Z0-9_]*$/);
34
+ const SafeReasonCodeSchema = z.string().min(1).max(96).regex(/^[a-z][a-z0-9_]*$/);
35
+ const SafeSourceSchema = z.string().min(1).max(64).regex(/^[a-z][a-z0-9_.-]*$/);
36
+ const UuidSchema = z.string().uuid();
37
+ const DigestRefSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/);
38
+ const IntentDigestSchema = DigestRefSchema;
39
+ const OperationIdSchema = z.string().min(1).max(128).regex(/^[A-Za-z0-9._:-]+$/);
40
+ const Rfc3339UtcSchema = z.string().datetime({ offset: false });
41
+ function isIpv4Address(value) {
42
+ const octets = value.split(".");
43
+ return octets.length === 4 && octets.every((octet) => /^(?:0|[1-9][0-9]{0,2})$/u.test(octet) && Number(octet) <= 255);
44
+ }
45
+ const Ipv4AddressSchema = z.string().max(15).refine(isIpv4Address, "must be an IPv4 address");
46
+ export const EvidenceSchema = (valueSchema) => z.discriminatedUnion("state", [
47
+ z.object({ state: z.literal("verified"), value: valueSchema, source: SafeSourceSchema }).strict(),
48
+ z.object({ state: z.literal("unknown"), reasonCode: SafeReasonCodeSchema }).strict(),
49
+ ]);
50
+ export function verified(value, source) {
51
+ return { state: "verified", value, source };
52
+ }
53
+ export function unknown(reasonCode) {
54
+ return { state: "unknown", reasonCode };
55
+ }
56
+ const CanonicalHostTupleSchema = z.object({
57
+ hostAssetId: z.string().min(1).max(80).regex(/^[a-z0-9][a-z0-9-]*$/),
58
+ node: z.string().min(1).max(80).regex(/^[a-z0-9][a-z0-9-]*$/),
59
+ vmid: z.number().int().min(100).max(999_999_999),
60
+ }).strict();
61
+ const ObservedFactSchema = (valueSchema) => z.object({
62
+ value: valueSchema,
63
+ observedAt: Rfc3339UtcSchema,
64
+ validUntil: Rfc3339UtcSchema.optional(),
65
+ }).strict();
66
+ const AccessCapabilitySchema = z.object({
67
+ resolved: EvidenceSchema(z.boolean()),
68
+ authenticated: EvidenceSchema(z.boolean()),
69
+ privileged: EvidenceSchema(z.boolean()),
70
+ }).strict();
71
+ const AccessFailureClassSchema = z.enum([
72
+ "none",
73
+ "credential_mismatch",
74
+ "transport_failure",
75
+ "boot_not_ready",
76
+ "authorization_failure",
77
+ ]);
78
+ const RoleSchema = z.enum(["admin", "full_admin"]);
79
+ const CredentialSchema = z.object({
80
+ schema: z.string().min(1).max(96).regex(/^[a-z0-9][a-z0-9./-]*$/),
81
+ version: z.union([z.string().min(1).max(32), z.number().int().positive()]),
82
+ referenceRevision: z.string().min(1).max(160).regex(/^[A-Za-z0-9._:-]+$/).nullable(),
83
+ referenceRevisionReasonCode: z.literal("provider_revision_unavailable").optional(),
84
+ }).strict().superRefine((value, context) => {
85
+ if (value.referenceRevision === null && value.referenceRevisionReasonCode !== "provider_revision_unavailable") {
86
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["referenceRevisionReasonCode"], message: "provider_revision_unavailable is required when revision is unknown" });
87
+ }
88
+ if (value.referenceRevision !== null && value.referenceRevisionReasonCode !== undefined) {
89
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["referenceRevisionReasonCode"], message: "revision reason is not allowed when provider revision is known" });
90
+ }
91
+ });
92
+ const PrincipalSchema = z.object({ validated: z.boolean(), role: RoleSchema }).strict();
93
+ const SessionSchema = z.object({ authenticated: z.boolean() }).strict();
94
+ const AuthorizationSchema = z.object({ privileged: z.boolean() }).strict();
95
+ const KeySchema = z.object({
96
+ provenance: z.string().min(1).max(80).regex(/^[a-z][a-z0-9_.-]*$/),
97
+ revision: z.string().min(1).max(160).regex(/^[A-Za-z0-9._:-]+$/).nullable(),
98
+ revisionReasonCode: z.literal("provider_revision_unavailable").optional(),
99
+ fingerprint: z.string().regex(/^sha256:[a-f0-9]{64}$/),
100
+ }).strict().superRefine((value, context) => {
101
+ if (value.revision === null && value.revisionReasonCode !== "provider_revision_unavailable") {
102
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["revisionReasonCode"], message: "provider_revision_unavailable is required when key revision is unknown" });
103
+ }
104
+ if (value.revision !== null && value.revisionReasonCode !== undefined) {
105
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["revisionReasonCode"], message: "revision reason is not allowed when provider revision is known" });
106
+ }
107
+ });
108
+ const AccessRequirementSchema = z.object({
109
+ credentialSchema: z.string().min(1).max(96).regex(/^[a-z0-9][a-z0-9./-]*$/).optional(),
110
+ role: RoleSchema.optional(),
111
+ capabilities: z.array(z.enum(["resolved", "authenticated", "privileged"])).max(3),
112
+ }).strict();
113
+ const AccessSummarySchema = z.object({
114
+ credential: EvidenceSchema(CredentialSchema),
115
+ principal: EvidenceSchema(PrincipalSchema),
116
+ session: EvidenceSchema(SessionSchema),
117
+ authorization: EvidenceSchema(AuthorizationSchema),
118
+ key: EvidenceSchema(KeySchema),
119
+ capabilities: AccessCapabilitySchema,
120
+ failureClass: EvidenceSchema(AccessFailureClassSchema),
121
+ }).strict();
122
+ const AccessDomainObservationSchema = z.object({
123
+ credential: EvidenceSchema(ObservedFactSchema(CredentialSchema)),
124
+ principal: EvidenceSchema(ObservedFactSchema(PrincipalSchema)),
125
+ session: EvidenceSchema(ObservedFactSchema(SessionSchema)),
126
+ authorization: EvidenceSchema(ObservedFactSchema(AuthorizationSchema)),
127
+ key: EvidenceSchema(ObservedFactSchema(KeySchema)),
128
+ capabilities: z.object({
129
+ resolved: EvidenceSchema(ObservedFactSchema(z.boolean())),
130
+ authenticated: EvidenceSchema(ObservedFactSchema(z.boolean())),
131
+ privileged: EvidenceSchema(ObservedFactSchema(z.boolean())),
132
+ }).strict(),
133
+ failureClass: EvidenceSchema(ObservedFactSchema(AccessFailureClassSchema)),
134
+ }).strict();
135
+ const AccessObservationSchema = z.object({
136
+ cube: AccessDomainObservationSchema,
137
+ web: AccessDomainObservationSchema,
138
+ }).strict();
139
+ const ReadinessStateSchema = z.enum(["ready", "pending", "not_ready", "failed", "not_required"]);
140
+ const ReadinessFactSchema = ObservedFactSchema(z.object({ state: ReadinessStateSchema }).strict());
141
+ const ReadinessDimensionSchema = z.object({
142
+ desired: EvidenceSchema(z.enum(["ready", "not_required"])),
143
+ observed: EvidenceSchema(ReadinessFactSchema),
144
+ }).strict();
145
+ const ReadinessSchema = z.object({
146
+ claim: ReadinessDimensionSchema,
147
+ provider: ReadinessDimensionSchema,
148
+ guestIdentity: ReadinessDimensionSchema,
149
+ network: ReadinessDimensionSchema,
150
+ ssh: ReadinessDimensionSchema,
151
+ configuration: ReadinessDimensionSchema,
152
+ application: ReadinessDimensionSchema,
153
+ }).strict();
154
+ const CanonicalHostProjectionSchema = z.object({
155
+ desired: EvidenceSchema(CanonicalHostTupleSchema),
156
+ observed: EvidenceSchema(ObservedFactSchema(CanonicalHostTupleSchema)),
157
+ }).strict();
158
+ const GuestIdentityProjectionSchema = z.object({
159
+ desired: EvidenceSchema(z.string().min(1).max(160)),
160
+ observed: EvidenceSchema(ObservedFactSchema(z.string().min(1).max(160))),
161
+ }).strict();
162
+ const AddressFactSchema = z.object({
163
+ value: z.string().min(1).max(128),
164
+ source: z.string().min(1).max(80).regex(/^[a-z][a-z0-9_.-]*$/),
165
+ observedAt: Rfc3339UtcSchema,
166
+ validUntil: Rfc3339UtcSchema.optional(),
167
+ }).strict();
168
+ const AddressProjectionSchema = z.object({
169
+ desired: EvidenceSchema(z.object({ value: z.string().min(1).max(128), source: SafeSourceSchema }).strict()),
170
+ observed: EvidenceSchema(AddressFactSchema),
171
+ }).strict();
172
+ const WorkflowPhaseIntentSchema = z.object({
173
+ operationId: OperationIdSchema,
174
+ intentDigest: IntentDigestSchema,
175
+ recordedAt: Rfc3339UtcSchema,
176
+ }).strict();
177
+ const WorkflowPhaseIntentSourceSchema = WorkflowPhaseIntentSchema.passthrough();
178
+ const WorkflowPhaseResultSchema = z.object({
179
+ effectCertainty: z.enum(EFFECT_CERTAINTIES),
180
+ observedAt: Rfc3339UtcSchema,
181
+ evidenceRefs: z.array(DigestRefSchema).max(32),
182
+ outcomeCode: SafeCodeSchema,
183
+ }).strict();
184
+ const WorkflowPhaseResultSourceSchema = WorkflowPhaseResultSchema.passthrough();
185
+ const WorkflowPhaseRecordSchema = z.object({
186
+ intent: WorkflowPhaseIntentSchema,
187
+ result: WorkflowPhaseResultSchema.optional(),
188
+ }).strict();
189
+ const WorkflowPhaseRecordSourceSchema = z.object({
190
+ intent: WorkflowPhaseIntentSourceSchema,
191
+ result: WorkflowPhaseResultSourceSchema.optional(),
192
+ }).passthrough();
193
+ const WorkflowPhasesSchema = z.record(z.enum(WORKFLOW_PHASES), WorkflowPhaseRecordSchema);
194
+ const WorkflowSummarySchema = z.object({
195
+ operationId: OperationIdSchema,
196
+ intentDigest: IntentDigestSchema,
197
+ phase: z.enum(WORKFLOW_PHASES),
198
+ checkpoint: z.enum(WORKFLOW_CHECKPOINTS),
199
+ workflowDeadlineAt: Rfc3339UtcSchema,
200
+ phaseDeadlineAt: Rfc3339UtcSchema,
201
+ cleanupAllowanceMs: z.number().int().nonnegative(),
202
+ retryClass: z.enum(RETRY_CLASSES),
203
+ effectCertainty: z.enum(EFFECT_CERTAINTIES),
204
+ nextAction: z.enum(NEXT_ACTIONS),
205
+ resumable: z.boolean(),
206
+ retryAt: Rfc3339UtcSchema.optional(),
207
+ }).strict();
208
+ const WorkflowProjectionSchema = z.object({
209
+ schema: z.literal(CUBE_WORKFLOW_SCHEMA),
210
+ ...WorkflowSummarySchema.shape,
211
+ phases: WorkflowPhasesSchema,
212
+ accessObserved: EvidenceSchema(AccessSummarySchema).optional(),
213
+ callbackTarget: EvidenceSchema(z.object({
214
+ schema: z.literal("ct.appliance.cube-callback-target/v1"),
215
+ transport: z.enum(["http", "https"]),
216
+ host: z.string().min(1).max(253).regex(/^[A-Za-z0-9.-]+$/),
217
+ pathDigest: DigestRefSchema,
218
+ targetDigest: DigestRefSchema,
219
+ runningConfigDigest: DigestRefSchema,
220
+ startupConfigDigest: DigestRefSchema,
221
+ observedAt: Rfc3339UtcSchema,
222
+ evidenceRefs: z.array(DigestRefSchema).max(32),
223
+ }).strict()).optional(),
224
+ }).strict();
225
+ const LifecycleDiagnosticSchema = z.object({
226
+ schema: z.literal(LIFECYCLE_DIAGNOSTIC_SCHEMA),
227
+ code: SafeCodeSchema,
228
+ classification: z.enum(DIAGNOSTIC_CLASSIFICATIONS),
229
+ phase: z.enum(WORKFLOW_PHASES),
230
+ resumable: z.boolean(),
231
+ retryAt: Rfc3339UtcSchema.optional(),
232
+ message: z.string().min(1).max(240).regex(/^[A-Za-z0-9 .,:;_()'-]+$/),
233
+ observedAt: Rfc3339UtcSchema,
234
+ resource: z.object({
235
+ name: z.string().min(1).max(253).regex(/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/),
236
+ uid: UuidSchema,
237
+ generation: z.number().int().nonnegative(),
238
+ resourceVersion: z.string().min(1).max(128).regex(/^[A-Za-z0-9._:-]+$/),
239
+ }).strict(),
240
+ evidenceRefs: z.array(DigestRefSchema).max(32),
241
+ effectCertainty: z.enum(EFFECT_CERTAINTIES),
242
+ retryClass: z.enum(RETRY_CLASSES),
243
+ nextAction: z.enum(NEXT_ACTIONS),
244
+ }).strict();
245
+ const SshPreflightSchema = z.discriminatedUnion("state", [
246
+ z.object({
247
+ state: z.literal("verified"),
248
+ value: z.object({
249
+ fingerprint: z.string().regex(/^sha256:[a-f0-9]{64}$/),
250
+ sameGuestUuid: z.literal(true),
251
+ authenticated: z.literal(true),
252
+ }).strict(),
253
+ source: z.literal("same-guest-ssh"),
254
+ observedAt: Rfc3339UtcSchema,
255
+ validUntil: Rfc3339UtcSchema,
256
+ }).strict(),
257
+ z.object({
258
+ state: z.literal("unknown"),
259
+ reasonCode: SafeReasonCodeSchema,
260
+ source: z.literal("same-guest-ssh"),
261
+ observedAt: Rfc3339UtcSchema.optional(),
262
+ validUntil: Rfc3339UtcSchema.optional(),
263
+ }).strict(),
264
+ ]);
265
+ const RoutesPreflightSchema = z.discriminatedUnion("state", [
266
+ z.object({
267
+ state: z.literal("verified"),
268
+ value: z.object({
269
+ peerTargetsPinged: z.boolean(),
270
+ xccHostPing: z.boolean().optional(),
271
+ routeSetDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
272
+ }).strict(),
273
+ source: z.literal("ios-ping-readback"),
274
+ observedAt: Rfc3339UtcSchema,
275
+ validUntil: Rfc3339UtcSchema,
276
+ }).strict(),
277
+ z.object({
278
+ state: z.literal("unknown"),
279
+ reasonCode: SafeReasonCodeSchema,
280
+ source: z.literal("ios-ping-readback"),
281
+ observedAt: Rfc3339UtcSchema.optional(),
282
+ validUntil: Rfc3339UtcSchema.optional(),
283
+ }).strict(),
284
+ ]);
285
+ const NetworkRevalidationIdentitySchema = z.object({
286
+ schema: z.literal(CUBE_NETWORK_REVALIDATION_SCHEMA),
287
+ status: z.enum(["pending", "verified", "unknown", "rejected"]),
288
+ requestId: UuidSchema,
289
+ claimUid: UuidSchema,
290
+ generation: z.number().int().positive(),
291
+ operationId: OperationIdSchema,
292
+ intentDigest: IntentDigestSchema,
293
+ }).passthrough();
294
+ const PendingNetworkRevalidationSchema = NetworkRevalidationIdentitySchema.extend({
295
+ status: z.literal("pending"),
296
+ requestedAt: Rfc3339UtcSchema,
297
+ requestExpiresAt: Rfc3339UtcSchema,
298
+ outcomeCode: SafeCodeSchema.optional(),
299
+ }).strict();
300
+ const UnknownNetworkRevalidationSchema = NetworkRevalidationIdentitySchema.extend({
301
+ status: z.literal("unknown"),
302
+ requestedAt: Rfc3339UtcSchema.optional(),
303
+ requestExpiresAt: Rfc3339UtcSchema.optional(),
304
+ outcomeCode: SafeCodeSchema.optional(),
305
+ reasonCode: SafeReasonCodeSchema.optional(),
306
+ evidenceRefs: z.array(DigestRefSchema).max(32).optional(),
307
+ }).strict();
308
+ const RejectedNetworkRevalidationSchema = NetworkRevalidationIdentitySchema.extend({
309
+ status: z.literal("rejected"),
310
+ requestedAt: Rfc3339UtcSchema.optional(),
311
+ requestExpiresAt: Rfc3339UtcSchema.optional(),
312
+ reasonCode: SafeReasonCodeSchema,
313
+ }).strict();
314
+ const VerifiedNetworkRevalidationSchema = NetworkRevalidationIdentitySchema.extend({
315
+ status: z.literal("verified"),
316
+ freshnessPolicy: z.literal("cube-network-preflight/v1"),
317
+ host: CanonicalHostTupleSchema,
318
+ guestUuid: UuidSchema,
319
+ mac: z.string().regex(/^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/),
320
+ address: Ipv4AddressSchema,
321
+ source: z.string().min(1).max(80).regex(/^[a-z][a-z0-9_.-]*$/),
322
+ requestedAt: Rfc3339UtcSchema,
323
+ observedAt: Rfc3339UtcSchema,
324
+ requestExpiresAt: Rfc3339UtcSchema,
325
+ claimExpiresAt: Rfc3339UtcSchema,
326
+ validUntil: Rfc3339UtcSchema,
327
+ validatedAt: Rfc3339UtcSchema,
328
+ remainingValidityMs: z.number().int().min(1).max(60_000),
329
+ iosLeaseExpiresAt: Rfc3339UtcSchema.optional(),
330
+ ssh: SshPreflightSchema,
331
+ routes: RoutesPreflightSchema,
332
+ evidenceRefs: z.array(DigestRefSchema).max(32),
333
+ }).strict();
334
+ const NetworkRevalidationSchema = z.discriminatedUnion("status", [
335
+ PendingNetworkRevalidationSchema,
336
+ UnknownNetworkRevalidationSchema,
337
+ VerifiedNetworkRevalidationSchema,
338
+ RejectedNetworkRevalidationSchema,
339
+ ]);
340
+ const NetworkRevalidationSourceIdentitySchema = z.object({
341
+ schema: z.literal(CUBE_NETWORK_REVALIDATION_SCHEMA),
342
+ requestId: UuidSchema,
343
+ claimUid: UuidSchema,
344
+ generation: z.number().int().positive(),
345
+ operationId: OperationIdSchema,
346
+ intentDigest: IntentDigestSchema,
347
+ });
348
+ const VerifiedNetworkRevalidationSourceSchema = VerifiedNetworkRevalidationSchema
349
+ .omit({ status: true, validatedAt: true, remainingValidityMs: true })
350
+ .extend({ address: z.unknown(), state: z.literal("verified") })
351
+ .passthrough();
352
+ const NetworkRevalidationSourceSchema = z.discriminatedUnion("state", [
353
+ NetworkRevalidationSourceIdentitySchema.extend({
354
+ state: z.literal("pending"),
355
+ requestedAt: Rfc3339UtcSchema,
356
+ requestExpiresAt: Rfc3339UtcSchema,
357
+ outcomeCode: SafeCodeSchema.optional(),
358
+ }).passthrough(),
359
+ NetworkRevalidationSourceIdentitySchema.extend({
360
+ state: z.literal("unknown"),
361
+ requestedAt: Rfc3339UtcSchema.optional(),
362
+ requestExpiresAt: Rfc3339UtcSchema.optional(),
363
+ outcomeCode: SafeCodeSchema.optional(),
364
+ reasonCode: SafeReasonCodeSchema.optional(),
365
+ evidenceRefs: z.array(DigestRefSchema).max(32).optional(),
366
+ }).passthrough(),
367
+ VerifiedNetworkRevalidationSourceSchema,
368
+ ]);
369
+ const BackendIdentitySchema = z.object({
370
+ kind: z.enum(["kubernetes_claims", "canonical_lab_inventory"]),
371
+ mode: z.enum(["in-cluster", "kubeconfig", "canonical_cli"]),
372
+ contextFingerprint: z.string().regex(/^sha256:[a-f0-9]{64}$/),
373
+ serverFingerprint: z.string().regex(/^sha256:[a-f0-9]{64}$/),
374
+ plane: z.enum(["local-stdio", "local-sse"]),
375
+ runtimeVersion: z.string().min(1).max(64),
376
+ mock: z.boolean(),
377
+ }).strict();
378
+ const ClaimCustodySchema = z.object({
379
+ present: z.boolean(),
380
+ phase: z.enum(["bound", "provider-bound", "retiring", "missing"]),
381
+ guest: CanonicalHostTupleSchema.optional(),
382
+ }).strict();
383
+ const StructuredReasonSchema = z.object({
384
+ code: SafeCodeSchema,
385
+ classification: z.enum(DIAGNOSTIC_CLASSIFICATIONS).optional(),
386
+ evidenceRefs: z.array(DigestRefSchema).max(32).optional(),
387
+ }).strict();
388
+ const RuntimeArtifactSchema = z.object({
389
+ packageName: z.literal("@calltelemetry/ct-lab-mcp"),
390
+ version: z.string().min(1).max(64),
391
+ integrity: z.string().regex(/^sha256:[a-f0-9]{64}$/),
392
+ revision: EvidenceSchema(z.string().regex(/^[a-f0-9]{40}$/)),
393
+ }).strict();
394
+ export const LabInspectionV1Schema = z.object({
395
+ schema: z.literal(LAB_INSPECTION_SCHEMA),
396
+ operation: z.object({
397
+ name: z.enum(["get_appliance_claim", "revalidate_appliance_claim_network"]),
398
+ intent: z.enum(["inspect_claim", "revalidate_network"]),
399
+ }).strict(),
400
+ backend: z.object({
401
+ identity: EvidenceSchema(BackendIdentitySchema),
402
+ observedAt: EvidenceSchema(Rfc3339UtcSchema),
403
+ retrievedAt: EvidenceSchema(Rfc3339UtcSchema),
404
+ }).strict(),
405
+ claim: z.object({
406
+ name: EvidenceSchema(z.string().min(1).max(253)),
407
+ assetId: EvidenceSchema(z.string().min(1).max(160)),
408
+ uid: EvidenceSchema(UuidSchema),
409
+ generation: EvidenceSchema(z.number().int().nonnegative()),
410
+ observedGeneration: EvidenceSchema(z.number().int().nonnegative()),
411
+ resourceVersion: EvidenceSchema(z.string().min(1).max(128).regex(/^[A-Za-z0-9._:-]+$/)),
412
+ expiresAt: EvidenceSchema(Rfc3339UtcSchema.nullable()),
413
+ custody: EvidenceSchema(ClaimCustodySchema),
414
+ }).strict(),
415
+ host: z.object({ canonical: CanonicalHostProjectionSchema }).strict(),
416
+ guest: z.object({ uuid: GuestIdentityProjectionSchema, mac: GuestIdentityProjectionSchema }).strict(),
417
+ address: AddressProjectionSchema,
418
+ access: z.object({ desired: EvidenceSchema(AccessRequirementSchema), observed: AccessObservationSchema }).strict(),
419
+ readiness: ReadinessSchema,
420
+ networkRevalidation: NetworkRevalidationSchema.optional(),
421
+ runtimeArtifact: EvidenceSchema(RuntimeArtifactSchema),
422
+ workflow: EvidenceSchema(WorkflowProjectionSchema),
423
+ diagnostic: EvidenceSchema(LifecycleDiagnosticSchema),
424
+ reason: EvidenceSchema(StructuredReasonSchema),
425
+ effectCertainty: EvidenceSchema(z.enum(EFFECT_CERTAINTIES)),
426
+ retryClass: EvidenceSchema(z.enum(RETRY_CLASSES)),
427
+ nextAction: EvidenceSchema(z.enum(NEXT_ACTIONS)),
428
+ }).strict().superRefine((value, context) => {
429
+ const conflict = (path) => context.addIssue({
430
+ code: z.ZodIssueCode.custom,
431
+ path,
432
+ message: "INSPECTION_CONFLICT",
433
+ });
434
+ const same = (left, right) => JSON.stringify(left) === JSON.stringify(right);
435
+ const hostDesired = value.host.canonical.desired;
436
+ const hostObserved = value.host.canonical.observed;
437
+ if (hostDesired.state === "verified" && hostObserved.state === "verified"
438
+ && !same(hostDesired.value, hostObserved.value.value)) {
439
+ conflict(["host", "canonical"]);
440
+ }
441
+ for (const key of ["uuid", "mac"]) {
442
+ const desired = value.guest[key].desired;
443
+ const observed = value.guest[key].observed;
444
+ if (desired.state === "verified" && observed.state === "verified"
445
+ && desired.value !== observed.value.value) {
446
+ conflict(["guest", key]);
447
+ }
448
+ }
449
+ const addressDesired = value.address.desired;
450
+ const addressObserved = value.address.observed;
451
+ if (addressDesired.state === "verified" && addressObserved.state === "verified"
452
+ && addressDesired.value.value !== addressObserved.value.value) {
453
+ conflict(["address"]);
454
+ }
455
+ if (value.workflow.state === "verified") {
456
+ const workflow = value.workflow.value;
457
+ for (const [phase, record] of Object.entries(workflow.phases)) {
458
+ if (record.intent.operationId !== workflow.operationId || record.intent.intentDigest !== workflow.intentDigest) {
459
+ conflict(["workflow", "phases", phase, "intent"]);
460
+ }
461
+ }
462
+ }
463
+ if (value.diagnostic.state === "verified" && value.claim.uid.state === "verified"
464
+ && value.diagnostic.value.resource.uid !== value.claim.uid.value) {
465
+ conflict(["diagnostic", "resource", "uid"]);
466
+ }
467
+ if (value.diagnostic.state === "verified" && value.claim.generation.state === "verified"
468
+ && value.diagnostic.value.resource.generation !== value.claim.generation.value) {
469
+ conflict(["diagnostic", "resource", "generation"]);
470
+ }
471
+ if (value.networkRevalidation?.status === "verified") {
472
+ const readback = value.networkRevalidation;
473
+ if (value.claim.uid.state === "verified" && readback.claimUid !== value.claim.uid.value)
474
+ conflict(["networkRevalidation", "claimUid"]);
475
+ if (value.claim.generation.state === "verified" && readback.generation !== value.claim.generation.value)
476
+ conflict(["networkRevalidation", "generation"]);
477
+ if (hostObserved.state === "verified" && !same(readback.host, hostObserved.value.value))
478
+ conflict(["networkRevalidation", "host"]);
479
+ if (value.guest.uuid.observed.state === "verified" && readback.guestUuid !== value.guest.uuid.observed.value.value)
480
+ conflict(["networkRevalidation", "guestUuid"]);
481
+ if (value.guest.mac.observed.state === "verified" && readback.mac.toLowerCase() !== value.guest.mac.observed.value.value.toLowerCase())
482
+ conflict(["networkRevalidation", "mac"]);
483
+ if (addressObserved.state === "verified" && readback.address !== addressObserved.value.value)
484
+ conflict(["networkRevalidation", "address"]);
485
+ }
486
+ });
487
+ export class InspectionConflictError extends Error {
488
+ code = "INSPECTION_CONFLICT";
489
+ constructor(message = "INSPECTION_CONFLICT") {
490
+ super(message);
491
+ this.name = "InspectionConflictError";
492
+ }
493
+ }
494
+ export class InspectionContractError extends Error {
495
+ code = "INSPECTION_CONTRACT_INVALID";
496
+ constructor(message = "inspection contract is invalid") {
497
+ super(message);
498
+ this.name = "InspectionContractError";
499
+ }
500
+ }
501
+ export function buildLabInspectionEnvelope(candidate) {
502
+ const result = LabInspectionV1Schema.safeParse(candidate);
503
+ if (result.success)
504
+ return result.data;
505
+ if (result.error.issues.some((issue) => issue.message === "INSPECTION_CONFLICT")) {
506
+ throw new InspectionConflictError();
507
+ }
508
+ throw new InspectionContractError();
509
+ }
510
+ export function projectOperatorWorkflow(raw, statusGenerationCurrent = true) {
511
+ const parsed = CubeWorkflowSourceSchema.safeParse(raw);
512
+ if (!parsed.success)
513
+ return unknown("workflow_status_invalid");
514
+ const { schema, summary, phases } = parsed.data;
515
+ const projectedPhases = {};
516
+ for (const phase of WORKFLOW_PHASES) {
517
+ const sourceRecord = phases[phase];
518
+ if (!sourceRecord)
519
+ continue;
520
+ if (sourceRecord.intent.operationId !== summary.operationId || sourceRecord.intent.intentDigest !== summary.intentDigest) {
521
+ throw new InspectionConflictError("INSPECTION_CONFLICT");
522
+ }
523
+ projectedPhases[phase] = {
524
+ intent: {
525
+ operationId: sourceRecord.intent.operationId,
526
+ intentDigest: sourceRecord.intent.intentDigest,
527
+ recordedAt: sourceRecord.intent.recordedAt,
528
+ },
529
+ ...(sourceRecord.result ? { result: {
530
+ effectCertainty: sourceRecord.result.effectCertainty,
531
+ observedAt: sourceRecord.result.observedAt,
532
+ evidenceRefs: sourceRecord.result.evidenceRefs,
533
+ outcomeCode: sourceRecord.result.outcomeCode,
534
+ } } : {}),
535
+ };
536
+ }
537
+ const sourceRecord = raw && typeof raw === "object" && !Array.isArray(raw)
538
+ ? raw
539
+ : undefined;
540
+ const summaryAccess = AccessSummarySchema.safeParse(summary.accessObserved);
541
+ const workflowAccessRaw = sourceRecord?.accessObserved;
542
+ const workflowAccess = AccessSummarySchema.safeParse(workflowAccessRaw);
543
+ if (summaryAccess.success && workflowAccess.success
544
+ && JSON.stringify(summaryAccess.data) !== JSON.stringify(workflowAccess.data)) {
545
+ throw new InspectionConflictError("INSPECTION_CONFLICT");
546
+ }
547
+ const accessObserved = summaryAccess.success || summary.accessObserved !== undefined
548
+ ? summaryAccess
549
+ : workflowAccess;
550
+ const callbackSource = sourceRecord?.callbackTarget && typeof sourceRecord.callbackTarget === "object" && !Array.isArray(sourceRecord.callbackTarget)
551
+ ? sourceRecord.callbackTarget
552
+ : undefined;
553
+ const callbackTarget = callbackSource
554
+ ? z.object({
555
+ schema: z.literal("ct.appliance.cube-callback-target/v1"),
556
+ state: z.literal("verified"),
557
+ transport: z.enum(["http", "https"]),
558
+ host: z.string().min(1).max(253).regex(/^[A-Za-z0-9.-]+$/),
559
+ pathDigest: DigestRefSchema,
560
+ targetDigest: DigestRefSchema,
561
+ runningConfigDigest: DigestRefSchema,
562
+ startupConfigDigest: DigestRefSchema,
563
+ observedAt: Rfc3339UtcSchema,
564
+ evidenceRefs: z.array(DigestRefSchema).max(32),
565
+ }).passthrough().safeParse(callbackSource)
566
+ : undefined;
567
+ const value = WorkflowProjectionSchema.parse({
568
+ schema,
569
+ operationId: summary.operationId,
570
+ intentDigest: summary.intentDigest,
571
+ phase: summary.phase,
572
+ checkpoint: summary.checkpoint,
573
+ workflowDeadlineAt: summary.workflowDeadlineAt,
574
+ phaseDeadlineAt: summary.phaseDeadlineAt,
575
+ cleanupAllowanceMs: summary.cleanupAllowanceMs,
576
+ retryClass: summary.retryClass,
577
+ effectCertainty: summary.effectCertainty,
578
+ nextAction: summary.nextAction,
579
+ resumable: summary.resumable,
580
+ ...(summary.retryAt ? { retryAt: summary.retryAt } : {}),
581
+ phases: projectedPhases,
582
+ ...(statusGenerationCurrent
583
+ ? accessObserved.success ? { accessObserved: verified(accessObserved.data, "operator_access_observed") } : {}
584
+ : { accessObserved: unknown("claim_status_generation_stale") }),
585
+ ...(statusGenerationCurrent
586
+ ? callbackTarget?.success ? { callbackTarget: verified({
587
+ schema: callbackTarget.data.schema,
588
+ transport: callbackTarget.data.transport,
589
+ host: callbackTarget.data.host,
590
+ pathDigest: callbackTarget.data.pathDigest,
591
+ targetDigest: callbackTarget.data.targetDigest,
592
+ runningConfigDigest: callbackTarget.data.runningConfigDigest,
593
+ startupConfigDigest: callbackTarget.data.startupConfigDigest,
594
+ observedAt: callbackTarget.data.observedAt,
595
+ evidenceRefs: callbackTarget.data.evidenceRefs,
596
+ }, "operator_callback_target_status") } : {}
597
+ : { callbackTarget: unknown("claim_status_generation_stale") }),
598
+ });
599
+ return verified(value, "operator_workflow_status");
600
+ }
601
+ function timeAccessEvidence(evidence, observedAt) {
602
+ if (evidence.state === "unknown")
603
+ return evidence;
604
+ const timestamp = Rfc3339UtcSchema.safeParse(observedAt);
605
+ if (!timestamp.success)
606
+ return unknown("access_observation_time_missing");
607
+ return verified({ value: evidence.value, observedAt: timestamp.data }, evidence.source);
608
+ }
609
+ function unknownAccessDomain(reasonCode) {
610
+ return {
611
+ credential: unknown(reasonCode),
612
+ principal: unknown("not_applicable"),
613
+ session: unknown("not_attempted"),
614
+ authorization: unknown("not_attempted"),
615
+ key: unknown(reasonCode),
616
+ capabilities: {
617
+ resolved: unknown(reasonCode),
618
+ authenticated: unknown("not_attempted"),
619
+ privileged: unknown("not_attempted"),
620
+ },
621
+ failureClass: unknown(reasonCode),
622
+ };
623
+ }
624
+ function projectAccessDomainObserved(raw, observedAt) {
625
+ const parsed = AccessSummarySchema.safeParse(raw);
626
+ if (!parsed.success)
627
+ return unknownAccessDomain("access_summary_invalid");
628
+ const value = parsed.data;
629
+ return {
630
+ credential: timeAccessEvidence(value.credential, observedAt),
631
+ principal: timeAccessEvidence(value.principal, observedAt),
632
+ session: timeAccessEvidence(value.session, observedAt),
633
+ authorization: timeAccessEvidence(value.authorization, observedAt),
634
+ key: timeAccessEvidence(value.key, observedAt),
635
+ capabilities: {
636
+ resolved: timeAccessEvidence(value.capabilities.resolved, observedAt),
637
+ authenticated: timeAccessEvidence(value.capabilities.authenticated, observedAt),
638
+ privileged: timeAccessEvidence(value.capabilities.privileged, observedAt),
639
+ },
640
+ failureClass: timeAccessEvidence(value.failureClass, observedAt),
641
+ };
642
+ }
643
+ export function projectAccessObserved(rawCube, observedAt, rawWeb) {
644
+ return {
645
+ cube: projectAccessDomainObserved(rawCube, observedAt),
646
+ web: rawWeb === undefined
647
+ ? unknownAccessDomain("web_access_not_projected")
648
+ : projectAccessDomainObserved(rawWeb, observedAt),
649
+ };
650
+ }
651
+ const CubeWorkflowSourceSchema = z.object({
652
+ schema: z.literal(CUBE_WORKFLOW_SCHEMA),
653
+ summary: WorkflowSummarySchema.passthrough(),
654
+ phases: z.record(z.string(), WorkflowPhaseRecordSourceSchema).default({}),
655
+ }).passthrough();
656
+ export const LIFECYCLE_DIAGNOSTIC_MESSAGES = {
657
+ CUBE_WORKFLOW_IDENTITY_MISMATCH: "Claim identity changed during this lifecycle operation.",
658
+ CUBE_WORKFLOW_LEASE_INACTIVE: "The claim lease is inactive; retire this operation.",
659
+ CUBE_WORKFLOW_DEADLINE_EXCEEDED: "The lifecycle deadline expired before this phase completed.",
660
+ CUBE_PHASE_OUTCOME_UNKNOWN: "Provider outcome is unknown; read back before retrying.",
661
+ CUBE_READINESS_PENDING: "The guest is still becoming ready; wait and resume the same claim.",
662
+ CUBE_ACCESS_REJECTED: "Guest access was rejected; repair access before continuing.",
663
+ CUBE_PROVIDER_IDENTITY_MISMATCH: "Provider identity did not match the claim; manual review is required.",
664
+ CUBE_BOOTSTRAP_ADMISSION_STALE: "Bootstrap evidence no longer matches the current template or profile.",
665
+ CUBE_PHASE_FAILED: "The provisioning phase failed and requires manual review.",
666
+ };
667
+ const DiagnosticSourceSchema = z.object({
668
+ schema: z.literal(LIFECYCLE_DIAGNOSTIC_SCHEMA),
669
+ code: SafeCodeSchema,
670
+ classification: z.enum(DIAGNOSTIC_CLASSIFICATIONS),
671
+ phase: z.enum(WORKFLOW_PHASES),
672
+ resumable: z.boolean(),
673
+ retryAt: Rfc3339UtcSchema.optional(),
674
+ message: z.string().min(1).max(240).regex(/^[A-Za-z0-9 .,:;_()'-]+$/),
675
+ observedAt: Rfc3339UtcSchema,
676
+ resource: z.object({
677
+ name: z.string().min(1).max(253),
678
+ uid: UuidSchema,
679
+ generation: z.number().int().nonnegative(),
680
+ resourceVersion: z.string().min(1).max(128),
681
+ }).passthrough(),
682
+ evidenceRefs: z.array(DigestRefSchema).max(32),
683
+ effectCertainty: z.enum(EFFECT_CERTAINTIES),
684
+ retryClass: z.enum(RETRY_CLASSES),
685
+ nextAction: z.enum(NEXT_ACTIONS),
686
+ }).passthrough().superRefine((value, context) => {
687
+ const expectedMessage = LIFECYCLE_DIAGNOSTIC_MESSAGES[value.code];
688
+ if (!expectedMessage || value.message !== expectedMessage) {
689
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["message"], message: "diagnostic message is not in the fixed redacted allowlist" });
690
+ }
691
+ });
692
+ export function projectLifecycleDiagnostic(raw, expected) {
693
+ const parsed = DiagnosticSourceSchema.safeParse(raw);
694
+ if (!parsed.success)
695
+ return unknown("diagnostic_status_invalid");
696
+ const value = LifecycleDiagnosticSchema.parse({
697
+ schema: parsed.data.schema,
698
+ code: parsed.data.code,
699
+ classification: parsed.data.classification,
700
+ phase: parsed.data.phase,
701
+ resumable: parsed.data.resumable,
702
+ ...(parsed.data.retryAt ? { retryAt: parsed.data.retryAt } : {}),
703
+ message: parsed.data.message,
704
+ observedAt: parsed.data.observedAt,
705
+ resource: {
706
+ name: parsed.data.resource.name,
707
+ uid: parsed.data.resource.uid,
708
+ generation: parsed.data.resource.generation,
709
+ resourceVersion: parsed.data.resource.resourceVersion,
710
+ },
711
+ evidenceRefs: parsed.data.evidenceRefs,
712
+ effectCertainty: parsed.data.effectCertainty,
713
+ retryClass: parsed.data.retryClass,
714
+ nextAction: parsed.data.nextAction,
715
+ });
716
+ if (expected && (value.resource.uid !== expected.uid || value.resource.generation !== expected.generation)) {
717
+ throw new InspectionConflictError("INSPECTION_CONFLICT");
718
+ }
719
+ return verified(value, "operator_lifecycle_diagnostic");
720
+ }
721
+ export const NETWORK_PREFLIGHT_MAX_AGE_MS = 60_000;
722
+ export const NETWORK_PREFLIGHT_MAX_FUTURE_SKEW_MS = 30_000;
723
+ export const NETWORK_REVALIDATION_REQUEST_TTL_MS = 120_000;
724
+ export const NETWORK_REVALIDATION_REQUEST_MAX_FUTURE_SKEW_MS = 30_000;
725
+ function requestWindowReason(requestedAt, requestExpiresAt, claimExpiresAt, trustedNowMs) {
726
+ const requestedAtMs = Date.parse(requestedAt);
727
+ const requestExpiresAtMs = Date.parse(requestExpiresAt);
728
+ const claimExpiresAtMs = Date.parse(claimExpiresAt);
729
+ if (![requestedAtMs, requestExpiresAtMs, claimExpiresAtMs, trustedNowMs].every(Number.isFinite)) {
730
+ return "network_request_invalid";
731
+ }
732
+ if (requestExpiresAtMs <= trustedNowMs)
733
+ return "network_request_expired";
734
+ if (requestedAtMs > trustedNowMs + NETWORK_REVALIDATION_REQUEST_MAX_FUTURE_SKEW_MS
735
+ || requestExpiresAtMs <= requestedAtMs
736
+ || requestExpiresAtMs > requestedAtMs + NETWORK_REVALIDATION_REQUEST_TTL_MS
737
+ || requestExpiresAtMs > claimExpiresAtMs) {
738
+ return "network_request_invalid";
739
+ }
740
+ return undefined;
741
+ }
742
+ export function projectNetworkRevalidation(raw, expected, trustedNow = new Date().toISOString()) {
743
+ const parsed = NetworkRevalidationSourceSchema.safeParse(raw);
744
+ if (!parsed.success)
745
+ throw new InspectionContractError("network revalidation status is invalid");
746
+ const value = parsed.data;
747
+ if (value.requestId !== expected.requestId
748
+ || value.claimUid !== expected.claimUid
749
+ || value.generation !== expected.generation
750
+ || value.operationId !== expected.operationId
751
+ || value.intentDigest !== expected.intentDigest
752
+ || (expected.claimExpiresAt !== undefined && typeof value.claimExpiresAt === "string" && value.claimExpiresAt !== expected.claimExpiresAt)
753
+ || (expected.host !== undefined && value.host !== undefined && JSON.stringify(value.host) !== JSON.stringify(expected.host))
754
+ || (expected.guestUuid !== undefined && typeof value.guestUuid === "string" && value.guestUuid !== expected.guestUuid)
755
+ || (expected.mac !== undefined && typeof value.mac === "string" && value.mac.toLowerCase() !== expected.mac.toLowerCase())) {
756
+ throw new InspectionConflictError("INSPECTION_CONFLICT");
757
+ }
758
+ if (value.state === "pending") {
759
+ const now = Date.parse(trustedNow);
760
+ if (!Rfc3339UtcSchema.safeParse(trustedNow).success || !Number.isFinite(now)) {
761
+ throw new InspectionContractError("trusted MCP clock is invalid");
762
+ }
763
+ const requestReason = requestWindowReason(value.requestedAt, value.requestExpiresAt, expected.claimExpiresAt ?? value.requestExpiresAt, now);
764
+ if (requestReason) {
765
+ return NetworkRevalidationSchema.parse({
766
+ schema: value.schema,
767
+ status: "unknown",
768
+ requestId: value.requestId,
769
+ claimUid: value.claimUid,
770
+ generation: value.generation,
771
+ operationId: value.operationId,
772
+ intentDigest: value.intentDigest,
773
+ requestedAt: value.requestedAt,
774
+ requestExpiresAt: value.requestExpiresAt,
775
+ reasonCode: requestReason,
776
+ ...(value.outcomeCode ? { outcomeCode: value.outcomeCode } : {}),
777
+ });
778
+ }
779
+ return NetworkRevalidationSchema.parse({
780
+ schema: value.schema,
781
+ status: value.state,
782
+ requestId: value.requestId,
783
+ claimUid: value.claimUid,
784
+ generation: value.generation,
785
+ operationId: value.operationId,
786
+ intentDigest: value.intentDigest,
787
+ requestedAt: value.requestedAt,
788
+ requestExpiresAt: value.requestExpiresAt,
789
+ ...(value.outcomeCode ? { outcomeCode: value.outcomeCode } : {}),
790
+ });
791
+ }
792
+ if (value.state === "unknown") {
793
+ const requestReason = typeof value.requestedAt === "string" && typeof value.requestExpiresAt === "string"
794
+ ? requestWindowReason(value.requestedAt, value.requestExpiresAt, expected.claimExpiresAt ?? value.requestExpiresAt, Date.parse(trustedNow))
795
+ : undefined;
796
+ return NetworkRevalidationSchema.parse({
797
+ schema: value.schema,
798
+ status: value.state,
799
+ requestId: value.requestId,
800
+ claimUid: value.claimUid,
801
+ generation: value.generation,
802
+ operationId: value.operationId,
803
+ intentDigest: value.intentDigest,
804
+ ...(typeof value.requestedAt === "string" ? { requestedAt: value.requestedAt } : {}),
805
+ ...(typeof value.requestExpiresAt === "string" ? { requestExpiresAt: value.requestExpiresAt } : {}),
806
+ ...(value.outcomeCode ? { outcomeCode: value.outcomeCode } : {}),
807
+ ...(requestReason ? { reasonCode: requestReason } : value.reasonCode ? { reasonCode: value.reasonCode } : {}),
808
+ ...(value.evidenceRefs ? { evidenceRefs: value.evidenceRefs } : {}),
809
+ });
810
+ }
811
+ const full = VerifiedNetworkRevalidationSourceSchema.safeParse(raw);
812
+ if (!full.success)
813
+ throw new InspectionContractError("verified network revalidation status is invalid");
814
+ const verifiedValue = full.data;
815
+ const now = Date.parse(trustedNow);
816
+ const observed = Date.parse(verifiedValue.observedAt);
817
+ const requestExpiry = Date.parse(verifiedValue.requestExpiresAt);
818
+ const claimExpiry = Date.parse(verifiedValue.claimExpiresAt);
819
+ const validUntil = Date.parse(verifiedValue.validUntil);
820
+ if (!Rfc3339UtcSchema.safeParse(trustedNow).success || !Number.isFinite(now)) {
821
+ throw new InspectionContractError("trusted MCP clock is invalid");
822
+ }
823
+ const requestReason = requestWindowReason(verifiedValue.requestedAt, verifiedValue.requestExpiresAt, verifiedValue.claimExpiresAt, now);
824
+ if (requestReason) {
825
+ return NetworkRevalidationSchema.parse({
826
+ schema: verifiedValue.schema,
827
+ status: "unknown",
828
+ requestId: verifiedValue.requestId,
829
+ claimUid: verifiedValue.claimUid,
830
+ generation: verifiedValue.generation,
831
+ operationId: verifiedValue.operationId,
832
+ intentDigest: verifiedValue.intentDigest,
833
+ requestedAt: verifiedValue.requestedAt,
834
+ requestExpiresAt: verifiedValue.requestExpiresAt,
835
+ reasonCode: requestReason,
836
+ evidenceRefs: verifiedValue.evidenceRefs,
837
+ });
838
+ }
839
+ if (typeof verifiedValue.address !== "string" || !isIpv4Address(verifiedValue.address)) {
840
+ return NetworkRevalidationSchema.parse({
841
+ schema: verifiedValue.schema,
842
+ status: "unknown",
843
+ requestId: verifiedValue.requestId,
844
+ claimUid: verifiedValue.claimUid,
845
+ generation: verifiedValue.generation,
846
+ operationId: verifiedValue.operationId,
847
+ intentDigest: verifiedValue.intentDigest,
848
+ requestedAt: verifiedValue.requestedAt,
849
+ requestExpiresAt: verifiedValue.requestExpiresAt,
850
+ reasonCode: "network_address_invalid",
851
+ evidenceRefs: verifiedValue.evidenceRefs,
852
+ });
853
+ }
854
+ const sourceFactsAt = [verifiedValue.ssh, verifiedValue.routes].flatMap((fact) => fact.state === "verified" ? [Date.parse(fact.observedAt)] : []);
855
+ const sourceTimesValid = [observed, ...sourceFactsAt].every((sourceAt) => Number.isFinite(sourceAt) && sourceAt <= now + NETWORK_PREFLIGHT_MAX_FUTURE_SKEW_MS
856
+ && sourceAt >= Date.parse(verifiedValue.requestedAt)
857
+ && sourceAt <= requestExpiry && sourceAt <= claimExpiry);
858
+ const timestampsOrdered = requestExpiry >= observed && claimExpiry >= observed
859
+ && sourceFactsAt.every((sourceAt) => sourceAt === observed);
860
+ const policyUntil = Math.min(observed + NETWORK_PREFLIGHT_MAX_AGE_MS, requestExpiry, claimExpiry);
861
+ if (!sourceTimesValid || !timestampsOrdered || !Number.isFinite(policyUntil)
862
+ || validUntil !== policyUntil || policyUntil <= observed) {
863
+ return NetworkRevalidationSchema.parse({
864
+ schema: verifiedValue.schema,
865
+ status: "unknown",
866
+ requestId: verifiedValue.requestId,
867
+ claimUid: verifiedValue.claimUid,
868
+ generation: verifiedValue.generation,
869
+ operationId: verifiedValue.operationId,
870
+ intentDigest: verifiedValue.intentDigest,
871
+ requestedAt: verifiedValue.requestedAt,
872
+ requestExpiresAt: verifiedValue.requestExpiresAt,
873
+ reasonCode: "network_freshness_invalid",
874
+ evidenceRefs: verifiedValue.evidenceRefs,
875
+ });
876
+ }
877
+ for (const readback of [verifiedValue.ssh, verifiedValue.routes]) {
878
+ if (readback.state === "verified" && readback.validUntil !== verifiedValue.validUntil) {
879
+ return NetworkRevalidationSchema.parse({
880
+ schema: verifiedValue.schema,
881
+ status: "unknown",
882
+ requestId: verifiedValue.requestId,
883
+ claimUid: verifiedValue.claimUid,
884
+ generation: verifiedValue.generation,
885
+ operationId: verifiedValue.operationId,
886
+ intentDigest: verifiedValue.intentDigest,
887
+ requestedAt: verifiedValue.requestedAt,
888
+ requestExpiresAt: verifiedValue.requestExpiresAt,
889
+ reasonCode: "network_freshness_invalid",
890
+ evidenceRefs: verifiedValue.evidenceRefs,
891
+ });
892
+ }
893
+ }
894
+ if (validUntil <= now) {
895
+ return NetworkRevalidationSchema.parse({
896
+ schema: verifiedValue.schema,
897
+ status: "unknown",
898
+ requestId: verifiedValue.requestId,
899
+ claimUid: verifiedValue.claimUid,
900
+ generation: verifiedValue.generation,
901
+ operationId: verifiedValue.operationId,
902
+ intentDigest: verifiedValue.intentDigest,
903
+ requestedAt: verifiedValue.requestedAt,
904
+ requestExpiresAt: verifiedValue.requestExpiresAt,
905
+ reasonCode: "network_validity_expired",
906
+ evidenceRefs: verifiedValue.evidenceRefs,
907
+ });
908
+ }
909
+ const producerFields = Object.fromEntries(Object.entries(verifiedValue).filter(([key]) => key !== "state"));
910
+ const safeValue = VerifiedNetworkRevalidationSchema.parse({
911
+ ...producerFields,
912
+ status: "verified",
913
+ validatedAt: new Date(now).toISOString(),
914
+ remainingValidityMs: Math.max(1, Math.min(NETWORK_PREFLIGHT_MAX_AGE_MS, validUntil - now)),
915
+ });
916
+ return safeValue;
917
+ }
918
+ export function projectCurrentNetworkReadiness(revalidation, retrievedAt) {
919
+ if (!revalidation)
920
+ return unknown("read_only_revalidation_required");
921
+ if (revalidation.status !== "verified") {
922
+ return unknown(revalidation.status === "unknown"
923
+ ? revalidation.reasonCode ?? revalidation.outcomeCode?.toLowerCase() ?? "network_revalidation_unavailable"
924
+ : revalidation.status === "pending" ? "network_revalidation_pending" : revalidation.reasonCode);
925
+ }
926
+ if (retrievedAt && Date.parse(retrievedAt) > Date.parse(revalidation.validUntil)) {
927
+ return unknown("network_validity_expired");
928
+ }
929
+ if (revalidation.ssh.state !== "verified")
930
+ return unknown(revalidation.ssh.reasonCode);
931
+ if (revalidation.routes.state !== "verified")
932
+ return unknown(revalidation.routes.reasonCode);
933
+ const state = revalidation.routes.value.peerTargetsPinged ? "ready" : "not_ready";
934
+ return verified({
935
+ value: { state },
936
+ observedAt: revalidation.observedAt,
937
+ validUntil: revalidation.validUntil,
938
+ }, "operator_cube_revalidation");
939
+ }
940
+ export function projectHistoricalNetworkReadiness(historical, retrievedAt) {
941
+ const source = SafeSourceSchema.safeParse(historical.source);
942
+ const address = z.string().min(1).max(128).safeParse(historical.address);
943
+ const observedAt = Rfc3339UtcSchema.safeParse(historical.observedAt);
944
+ const requestExpiresAt = Rfc3339UtcSchema.safeParse(historical.requestExpiresAt);
945
+ const claimExpiresAt = Rfc3339UtcSchema.safeParse(historical.claimExpiresAt);
946
+ const validUntil = Rfc3339UtcSchema.safeParse(historical.validUntil);
947
+ const retrieved = Rfc3339UtcSchema.safeParse(retrievedAt);
948
+ if (!source.success || !address.success || !observedAt.success || !retrieved.success) {
949
+ return unknown("network_observation_invalid");
950
+ }
951
+ if (historical.freshnessPolicy !== "cube-network-preflight/v1"
952
+ || !requestExpiresAt.success || !claimExpiresAt.success || !validUntil.success) {
953
+ return unknown("read_only_revalidation_required");
954
+ }
955
+ const policyUntil = Math.min(Date.parse(observedAt.data) + 60_000, Date.parse(requestExpiresAt.data), Date.parse(claimExpiresAt.data));
956
+ if (Date.parse(validUntil.data) !== policyUntil || policyUntil <= Date.parse(observedAt.data)) {
957
+ return unknown("network_validity_contract_invalid");
958
+ }
959
+ if (Date.parse(retrieved.data) > Date.parse(validUntil.data)) {
960
+ return unknown("network_validity_expired");
961
+ }
962
+ return verified({ value: { state: "ready" }, observedAt: observedAt.data, validUntil: validUntil.data }, source.data);
963
+ }
964
+ //# sourceMappingURL=lab-inspection.js.map