@plasius/asset-contracts 0.3.1 → 0.4.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.
@@ -0,0 +1,1041 @@
1
+ import {
2
+ CANONICAL_MODEL_COORDINATE_SYSTEM,
3
+ MODEL_ASSET_KINDS,
4
+ MODEL_CONFIRMATION_VIEW_KINDS,
5
+ MODEL_CONFIRMATION_VIEW_SIZE_PX,
6
+ MODEL_MATCH_ASSURANCE_BANDS,
7
+ MODEL_PROVENANCE_KINDS,
8
+ MODEL_RANKER_EVIDENCE_MODES,
9
+ MODEL_REQUEST_MAX_REVISION,
10
+ MODEL_RESOLUTION_CONTRACT_VERSION,
11
+ MODEL_RESOLUTION_STATES,
12
+ MODEL_RIGHTS_STATUSES,
13
+ STATIC_WORLD_V1_MODEL_POLICY,
14
+ } from "./model-resolution.js";
15
+ import {
16
+ MODEL_RESOLUTION_V2_CONTRACT_VERSION,
17
+ MODEL_RESOLUTION_V2_STATES,
18
+ PVOX_ASSET_MANIFEST_VERSION,
19
+ PVOX_BRICK_EDGE_VOXELS,
20
+ PVOX_CAPABILITIES,
21
+ PVOX_CONTENT_TYPE,
22
+ PVOX_DEFAULT_LIMITS,
23
+ PVOX_DEFAULT_SOURCE_INGESTION_LIMITS,
24
+ PVOX_EDIT_JOURNAL_VERSION,
25
+ PVOX_FIDELITY_PROFILE_IDS,
26
+ PVOX_FIDELITY_PROFILE_VERSION,
27
+ PVOX_FILE_EXTENSION,
28
+ PVOX_HASH_DOMAINS,
29
+ PVOX_HEADER_BYTE_LENGTH,
30
+ PVOX_DIRECTORY_ENTRY_BYTE_LENGTH,
31
+ PVOX_MAGIC,
32
+ PVOX_MAX_ABSOLUTE_COORDINATE_METRES,
33
+ PVOX_MAX_ENCODED_BRICK_PAYLOAD_BYTES,
34
+ PVOX_MAX_HIERARCHY_NODES,
35
+ PVOX_MAX_LOCAL_SAMPLES_PER_BRICK,
36
+ PVOX_MAX_RUNS_PER_BRICK,
37
+ PVOX_MAX_SECTIONS,
38
+ PVOX_MIN_STATIC_SECTION_COUNT,
39
+ PVOX_MAX_EDIT_PATCHES,
40
+ PVOX_MODEL_REQUEST_POLICY_ID,
41
+ PVOX_NATIVE_RENDERER_ID,
42
+ PVOX_NATIVE_REVIEW_SETTINGS_ID,
43
+ PVOX_NON_OVERRIDABLE_GATE_KINDS,
44
+ PVOX_PAGE_KINDS,
45
+ PVOX_PAGE_SIZE_BYTES,
46
+ PVOX_PHYSICAL_PROPERTIES,
47
+ PVOX_PHYSICAL_REGION_INVENTORY_VERSION,
48
+ PVOX_PHYSICAL_PROPERTY_POLICIES,
49
+ PVOX_PHYSICAL_PROPERTY_POLICY_ID,
50
+ PVOX_PHYSICAL_PROPERTY_POLICY_VERSION,
51
+ PVOX_RUNTIME_CAPABILITY_PROFILE_IDS,
52
+ } from "./pvox-model-resolution.js";
53
+
54
+ export type PvoxModelResolutionJsonSchema = Readonly<Record<string, unknown>> & {
55
+ readonly $id: string;
56
+ readonly $schema: "https://json-schema.org/draft/2020-12/schema";
57
+ readonly type: "object";
58
+ readonly additionalProperties: false;
59
+ readonly $defs: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
60
+ };
61
+
62
+ type Schema = Record<string, unknown>;
63
+
64
+ function deepFreeze<T>(value: T, seen = new WeakSet<object>()): T {
65
+ if (value === null || typeof value !== "object") return value;
66
+ const object = value as object;
67
+ if (seen.has(object)) return value;
68
+ seen.add(object);
69
+ for (const child of Object.values(value as Record<string, unknown>)) deepFreeze(child, seen);
70
+ return Object.freeze(value);
71
+ }
72
+
73
+ function objectSchema(properties: Record<string, Schema>, required: readonly string[] = [], extra: Schema = {}): Schema {
74
+ return {
75
+ type: "object",
76
+ additionalProperties: false,
77
+ properties,
78
+ required,
79
+ ...extra,
80
+ };
81
+ }
82
+
83
+ function arraySchema(items: Schema, minimum = 0, maximum?: number): Schema {
84
+ return {
85
+ type: "array",
86
+ items,
87
+ minItems: minimum,
88
+ ...(maximum === undefined ? {} : { maxItems: maximum }),
89
+ };
90
+ }
91
+
92
+ function tupleSchema(items: readonly Schema[]): Schema {
93
+ return {
94
+ type: "array",
95
+ prefixItems: items,
96
+ items: false,
97
+ minItems: items.length,
98
+ maxItems: items.length,
99
+ };
100
+ }
101
+
102
+ function hashAttestationSchema(domain: Schema): Schema {
103
+ return objectSchema({
104
+ algorithm: { const: "sha256" },
105
+ domain,
106
+ digest: sha256,
107
+ attestationToken: attestation,
108
+ }, ["algorithm", "domain", "digest", "attestationToken"]);
109
+ }
110
+
111
+ const ref = (name: string): Schema => ({ $ref: `#/$defs/${name}` });
112
+ const stringSchema = (maximum = 512): Schema => ({ type: "string", minLength: 1, maxLength: maximum });
113
+ const numberSchema = (minimum?: number, maximum?: number): Schema => ({
114
+ type: "number",
115
+ ...(minimum === undefined ? {} : { minimum }),
116
+ ...(maximum === undefined ? {} : { maximum }),
117
+ });
118
+ const integerSchema = (minimum: number, maximum?: number): Schema => ({
119
+ type: "integer",
120
+ minimum,
121
+ ...(maximum === undefined ? {} : { maximum }),
122
+ });
123
+
124
+ const sha256 = { type: "string", pattern: "^[a-f0-9]{64}$" };
125
+ const token = { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" };
126
+ const opaqueSourceAssetId = { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$" };
127
+ const pathSegment = { type: "string", pattern: "^(?!\\.{1,2}$)[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$" };
128
+ const reasonCode = { type: "string", pattern: "^[a-z0-9][a-z0-9._:-]{0,127}$" };
129
+ const attestation = { type: "string", pattern: "^[A-Za-z0-9_-]{32,256}$" };
130
+ const timestamp = {
131
+ type: "string",
132
+ pattern: "^(?:[0-9]{4})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\.[0-9]{3}Z$",
133
+ };
134
+ const immutableVersion = {
135
+ type: "string",
136
+ minLength: 1,
137
+ maxLength: 128,
138
+ pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$",
139
+ not: {
140
+ anyOf: [
141
+ { pattern: "^[Ll][Aa][Tt][Ee][Ss][Tt]$" },
142
+ { pattern: "^[Cc][Uu][Rr][Rr][Ee][Nn][Tt]$" },
143
+ { pattern: "^[Ss][Tt][Aa][Bb][Ll][Ee]$" },
144
+ { pattern: "^[Pp][Rr][Ee][Vv][Ii][Ee][Ww]$" },
145
+ { pattern: "^[Dd][Ee][Ff][Aa][Uu][Ll][Tt]$" },
146
+ { pattern: "^[Pp][Rr][Oo][Dd][Uu][Cc][Tt][Ii][Oo][Nn]$" },
147
+ { pattern: "^[Cc][Aa][Nn][Aa][Rr][Yy]$" },
148
+ { pattern: "^[Nn][Ee][Xx][Tt]$" },
149
+ { pattern: "^[Hh][Ee][Aa][Dd]$" },
150
+ { pattern: "^[Mm][Aa][Ii][Nn]$" },
151
+ { pattern: "(?:^|[._-])[xX](?:$|[._-])" },
152
+ ],
153
+ },
154
+ };
155
+ const reasonCodes = { ...arraySchema(reasonCode, 0, 32), uniqueItems: true };
156
+ const releasedV1ReasonCodes = { ...arraySchema(token, 0, 32), uniqueItems: true };
157
+ const mutableCatalogVersionPath = {
158
+ anyOf: [
159
+ { pattern: "/versions/[Ll][Aa][Tt][Ee][Ss][Tt]/" },
160
+ { pattern: "/versions/[Cc][Uu][Rr][Rr][Ee][Nn][Tt]/" },
161
+ { pattern: "/versions/[Ss][Tt][Aa][Bb][Ll][Ee]/" },
162
+ { pattern: "/versions/[Pp][Rr][Ee][Vv][Ii][Ee][Ww]/" },
163
+ { pattern: "/versions/[Dd][Ee][Ff][Aa][Uu][Ll][Tt]/" },
164
+ { pattern: "/versions/[Pp][Rr][Oo][Dd][Uu][Cc][Tt][Ii][Oo][Nn]/" },
165
+ { pattern: "/versions/[Cc][Aa][Nn][Aa][Rr][Yy]/" },
166
+ { pattern: "/versions/[Nn][Ee][Xx][Tt]/" },
167
+ { pattern: "/versions/[Hh][Ee][Aa][Dd]/" },
168
+ { pattern: "/versions/[Mm][Aa][Ii][Nn]/" },
169
+ { pattern: "/versions/(?:[vV])?[xX](?:[.-]|/)" },
170
+ { pattern: "/versions/[^/]*\\.[xX](?:[.-]|/)" },
171
+ ],
172
+ };
173
+ const shaTuple = tupleSchema([sha256, sha256, sha256, sha256]);
174
+ const vector3 = tupleSchema([
175
+ numberSchema(-PVOX_MAX_ABSOLUTE_COORDINATE_METRES, PVOX_MAX_ABSOLUTE_COORDINATE_METRES),
176
+ numberSchema(-PVOX_MAX_ABSOLUTE_COORDINATE_METRES, PVOX_MAX_ABSOLUTE_COORDINATE_METRES),
177
+ numberSchema(-PVOX_MAX_ABSOLUTE_COORDINATE_METRES, PVOX_MAX_ABSOLUTE_COORDINATE_METRES),
178
+ ]);
179
+ const positiveVector3 = tupleSchema([numberSchema(Number.EPSILON), numberSchema(Number.EPSILON), numberSchema(Number.EPSILON)]);
180
+ const quaternion = tupleSchema([numberSchema(-1, 1), numberSchema(-1, 1), numberSchema(-1, 1), numberSchema(-1, 1)]);
181
+
182
+ const definitions: Record<string, Schema> = {
183
+ coordinateSystem: objectSchema({
184
+ unit: { const: CANONICAL_MODEL_COORDINATE_SYSTEM.unit },
185
+ upAxis: { const: CANONICAL_MODEL_COORDINATE_SYSTEM.upAxis },
186
+ forwardAxis: { const: CANONICAL_MODEL_COORDINATE_SYSTEM.forwardAxis },
187
+ origin: { const: CANONICAL_MODEL_COORDINATE_SYSTEM.origin },
188
+ outwardFaceWinding: { const: CANONICAL_MODEL_COORDINATE_SYSTEM.outwardFaceWinding },
189
+ }, ["unit", "upAxis", "forwardAxis", "origin", "outwardFaceWinding"]),
190
+ pvoxFormatVersion: objectSchema({ major: { const: 1 }, minor: { const: 0 } }, ["major", "minor"]),
191
+ pvoxHashAttestation: hashAttestationSchema({ enum: Object.values(PVOX_HASH_DOMAINS) }),
192
+ pvoxAssemblyClosureHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.assemblyClosure }),
193
+ pvoxCapabilitySetHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.capabilitySet }),
194
+ pvoxConfirmationBindingHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.confirmationBinding }),
195
+ pvoxEditJournalHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.editJournal }),
196
+ pvoxEditOverlayRootHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.editOverlayRoot }),
197
+ pvoxEvaluationClosureHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.evaluationClosure }),
198
+ pvoxPhysicalEvidenceHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.physicalEvidence }),
199
+ pvoxPhysicalInventoryHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.physicalInventory }),
200
+ pvoxProcessingClosureHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.processingClosure }),
201
+ pvoxPublicationHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.publication }),
202
+ pvoxRenderEvidenceHashAttestation: hashAttestationSchema({ const: PVOX_HASH_DOMAINS.renderEvidence }),
203
+ bounds: objectSchema({ min: vector3, max: vector3 }, ["min", "max"]),
204
+ dimensions: objectSchema({
205
+ width: numberSchema(Number.EPSILON),
206
+ height: numberSchema(Number.EPSILON),
207
+ depth: numberSchema(Number.EPSILON),
208
+ }, ["width", "height", "depth"]),
209
+ hardConstraintsV2: objectSchema({
210
+ boundsMetres: ref("bounds"),
211
+ dimensionsMetres: ref("dimensions"),
212
+ collision: { enum: ["required", "optional", "forbidden"] },
213
+ partition: { enum: ["single", "allowed", "required"] },
214
+ }),
215
+ softPreferences: objectSchema({
216
+ category: stringSchema(80),
217
+ style: stringSchema(80),
218
+ materials: arraySchema(stringSchema(256), 0, 32),
219
+ colors: arraySchema(stringSchema(256), 0, 32),
220
+ era: stringSchema(80),
221
+ condition: stringSchema(80),
222
+ tags: arraySchema(stringSchema(256), 0, 32),
223
+ }),
224
+ sourceIngestionLimits: objectSchema({
225
+ maximumDownloadBytes: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumDownloadBytes),
226
+ maximumExpandedBytes: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumExpandedBytes),
227
+ maximumArchiveEntries: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumArchiveEntries),
228
+ maximumSourceFiles: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumSourceFiles),
229
+ maximumDecodedTextureBytes: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumDecodedTextureBytes),
230
+ maximumTextureDimensionPx: integerSchema(1, PVOX_DEFAULT_SOURCE_INGESTION_LIMITS.maximumTextureDimensionPx),
231
+ }, ["maximumDownloadBytes", "maximumExpandedBytes", "maximumArchiveEntries", "maximumSourceFiles", "maximumDecodedTextureBytes", "maximumTextureDimensionPx"]),
232
+ pvoxRuntimeLimits: objectSchema({
233
+ maximumArtifactBytes: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumArtifactBytes),
234
+ maximumPages: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPages),
235
+ maximumHierarchyDepth: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumHierarchyDepth),
236
+ maximumHierarchyNodes: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumHierarchyNodes),
237
+ maximumBricks: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumBricks),
238
+ maximumLogicalVoxels: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumLogicalVoxels),
239
+ maximumEncodedSurfaceSamples: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumEncodedSurfaceSamples),
240
+ maximumSurfaceProperties: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumSurfaceProperties),
241
+ maximumPhysicalPaletteRecords: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPhysicalProperties),
242
+ maximumPhysicalEvidenceEntries: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPhysicalEvidenceEntries),
243
+ maximumMaterialRegions: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumMaterialRegions),
244
+ maximumInteriorLayers: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumInteriorLayers),
245
+ maximumMassPropertyRecords: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumMassPropertyRecords),
246
+ maximumBondRecords: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumBondRecords),
247
+ maximumPartitions: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPartitions),
248
+ maximumLodCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumLodCount),
249
+ maximumCpuResidentBytes: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumCpuResidentBytes),
250
+ maximumGpuResidentBytes: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumGpuResidentBytes),
251
+ }, ["maximumArtifactBytes", "maximumPages", "maximumHierarchyDepth", "maximumHierarchyNodes", "maximumBricks", "maximumLogicalVoxels", "maximumEncodedSurfaceSamples", "maximumSurfaceProperties", "maximumPhysicalPaletteRecords", "maximumPhysicalEvidenceEntries", "maximumMaterialRegions", "maximumInteriorLayers", "maximumMassPropertyRecords", "maximumBondRecords", "maximumPartitions", "maximumLodCount", "maximumCpuResidentBytes", "maximumGpuResidentBytes"]),
252
+ pvoxRuntimeProfile: objectSchema({
253
+ profileId: token,
254
+ fidelityProfileId: { enum: PVOX_FIDELITY_PROFILE_IDS },
255
+ capabilityProfileId: { enum: PVOX_RUNTIME_CAPABILITY_PROFILE_IDS },
256
+ geometryMode: { enum: ["solid", "shell", "mixed", "auto"] },
257
+ requiredCapabilities: { ...arraySchema({ enum: PVOX_CAPABILITIES }, 1, PVOX_CAPABILITIES.length), uniqueItems: true },
258
+ limits: ref("pvoxRuntimeLimits"),
259
+ }, ["profileId", "fidelityProfileId", "capabilityProfileId", "geometryMode", "requiredCapabilities", "limits"]),
260
+ modelRequestSpecV2: objectSchema({
261
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
262
+ policyProfileId: { const: PVOX_MODEL_REQUEST_POLICY_ID },
263
+ requestSemanticProfileHash: sha256,
264
+ query: stringSchema(1_000),
265
+ revision: integerSchema(0, MODEL_REQUEST_MAX_REVISION),
266
+ locale: stringSchema(64),
267
+ rankerId: token,
268
+ hardConstraints: ref("hardConstraintsV2"),
269
+ softPreferences: ref("softPreferences"),
270
+ exclusions: arraySchema(stringSchema(256), 0, 32),
271
+ sourceIngestionLimits: ref("sourceIngestionLimits"),
272
+ pvoxRuntimeProfile: ref("pvoxRuntimeProfile"),
273
+ }, ["contractVersion", "policyProfileId", "requestSemanticProfileHash", "query", "revision", "hardConstraints", "softPreferences", "exclusions", "sourceIngestionLimits", "pvoxRuntimeProfile"]),
274
+ pvoxResource: objectSchema({
275
+ uri: {
276
+ type: "string",
277
+ maxLength: 512,
278
+ oneOf: [
279
+ { pattern: "^mcp://models/resolutions/[A-Za-z0-9._~-]+/candidates/[A-Za-z0-9._~-]+/artifacts/sha256/[a-f0-9]{64}\\.pvox$" },
280
+ {
281
+ pattern: "^mcp://models/catalog/[a-z0-9]+(?:-[a-z0-9]+)*/versions/[A-Za-z0-9][A-Za-z0-9._-]{0,127}/artifacts/sha256/[a-f0-9]{64}\\.pvox$",
282
+ not: mutableCatalogVersionPath,
283
+ },
284
+ ],
285
+ },
286
+ byteLength: { ...integerSchema(PVOX_PAGE_SIZE_BYTES, PVOX_DEFAULT_LIMITS.maximumArtifactBytes), multipleOf: PVOX_PAGE_SIZE_BYTES },
287
+ sha256,
288
+ contentType: { const: PVOX_CONTENT_TYPE },
289
+ authenticated: { const: true },
290
+ }, ["uri", "byteLength", "sha256", "contentType", "authenticated"]),
291
+ pvoxPageSpatialKey: objectSchema({
292
+ lodLevel: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumLodCount - 1),
293
+ partitionIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPartitions - 1),
294
+ hierarchyDepth: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumHierarchyDepth),
295
+ minimumMortonCode: { type: "string", pattern: "^[a-f0-9]{16}$" },
296
+ maximumMortonCode: { type: "string", pattern: "^[a-f0-9]{16}$" },
297
+ }, ["lodLevel", "partitionIndex", "hierarchyDepth", "minimumMortonCode", "maximumMortonCode"]),
298
+ pvoxPage: objectSchema({
299
+ pageIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPages - 1),
300
+ pageKind: { enum: PVOX_PAGE_KINDS },
301
+ byteOffset: { ...integerSchema(0, PVOX_DEFAULT_LIMITS.maximumArtifactBytes - 1), multipleOf: PVOX_PAGE_SIZE_BYTES },
302
+ byteLength: { const: PVOX_PAGE_SIZE_BYTES },
303
+ decodedByteLength: { const: PVOX_PAGE_SIZE_BYTES },
304
+ sha256,
305
+ spatialKey: ref("pvoxPageSpatialKey"),
306
+ }, ["pageIndex", "pageKind", "byteOffset", "byteLength", "decodedByteLength", "sha256"], {
307
+ allOf: [{
308
+ if: {
309
+ properties: { pageKind: { enum: ["render-field", "collision-field"] } },
310
+ required: ["pageKind"],
311
+ },
312
+ then: { properties: { spatialKey: ref("pvoxPageSpatialKey") }, required: ["spatialKey"] },
313
+ else: { not: { properties: { spatialKey: {} }, required: ["spatialKey"] } },
314
+ }],
315
+ }),
316
+ pvoxLod: objectSchema({
317
+ level: integerSchema(0, 3),
318
+ firstPageIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPages - 1),
319
+ pageCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPages),
320
+ brickCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumBricks),
321
+ cellSizeMetres: numberSchema(Number.EPSILON),
322
+ maximumSurfaceErrorMetres: numberSchema(0),
323
+ p99SurfaceErrorMetres: numberSchema(0),
324
+ silhouetteIou: numberSchema(0, 1),
325
+ maximumContourDisplacementPx: numberSchema(0),
326
+ renderedSsim: numberSchema(0, 1),
327
+ p95DeltaE2000: numberSchema(0, 100),
328
+ normalizedMaterialError: numberSchema(0, 1),
329
+ }, ["level", "firstPageIndex", "pageCount", "brickCount", "cellSizeMetres", "maximumSurfaceErrorMetres", "p99SurfaceErrorMetres", "silhouetteIou", "maximumContourDisplacementPx", "renderedSsim", "p95DeltaE2000", "normalizedMaterialError"]),
330
+ pvoxAssetManifest: objectSchema({
331
+ manifestVersion: { const: PVOX_ASSET_MANIFEST_VERSION },
332
+ representation: { const: "pvox" },
333
+ formatVersion: ref("pvoxFormatVersion"),
334
+ contentType: { const: PVOX_CONTENT_TYPE },
335
+ fileExtension: { const: PVOX_FILE_EXTENSION },
336
+ magic: { const: PVOX_MAGIC },
337
+ brickEdgeVoxels: { const: PVOX_BRICK_EDGE_VOXELS },
338
+ pageSizeBytes: { const: PVOX_PAGE_SIZE_BYTES },
339
+ geometryMode: { enum: ["solid", "shell", "mixed"] },
340
+ sourceContentHash: sha256,
341
+ canonicalDocumentHash: sha256,
342
+ rootHash: sha256,
343
+ directoryHash: sha256,
344
+ pageSetHash: sha256,
345
+ binaryClosureHash: sha256,
346
+ validationEvidenceHash: sha256,
347
+ compilationInputHash: sha256,
348
+ runtimeRequestProfileHash: sha256,
349
+ headerByteLength: { const: PVOX_HEADER_BYTE_LENGTH },
350
+ directoryEntryByteLength: { const: PVOX_DIRECTORY_ENTRY_BYTE_LENGTH },
351
+ sectionCount: integerSchema(PVOX_MIN_STATIC_SECTION_COUNT, PVOX_MAX_SECTIONS),
352
+ maximumRunsPerBrick: { const: PVOX_MAX_RUNS_PER_BRICK },
353
+ maximumLocalSamplesPerBrick: { const: PVOX_MAX_LOCAL_SAMPLES_PER_BRICK },
354
+ maximumEncodedBrickPayloadBytes: { const: PVOX_MAX_ENCODED_BRICK_PAYLOAD_BYTES },
355
+ coordinateSystem: ref("coordinateSystem"),
356
+ boundsMetres: ref("bounds"),
357
+ artifact: ref("pvoxResource"),
358
+ pages: arraySchema(ref("pvoxPage"), 1, PVOX_DEFAULT_LIMITS.maximumPages),
359
+ lods: arraySchema(ref("pvoxLod"), 1, PVOX_DEFAULT_LIMITS.maximumLodCount),
360
+ }, ["manifestVersion", "representation", "formatVersion", "contentType", "fileExtension", "magic", "brickEdgeVoxels", "pageSizeBytes", "geometryMode", "sourceContentHash", "canonicalDocumentHash", "rootHash", "directoryHash", "pageSetHash", "binaryClosureHash", "validationEvidenceHash", "compilationInputHash", "runtimeRequestProfileHash", "headerByteLength", "directoryEntryByteLength", "sectionCount", "maximumRunsPerBrick", "maximumLocalSamplesPerBrick", "maximumEncodedBrickPayloadBytes", "coordinateSystem", "boundsMetres", "artifact", "pages", "lods"]),
361
+ voxelTechnicalProfile: objectSchema({
362
+ boundsMetres: ref("bounds"),
363
+ dimensionsMetres: ref("dimensions"),
364
+ geometryMode: { enum: ["solid", "shell", "mixed"] },
365
+ artifactByteLength: { ...integerSchema(PVOX_PAGE_SIZE_BYTES, PVOX_DEFAULT_LIMITS.maximumArtifactBytes), multipleOf: PVOX_PAGE_SIZE_BYTES },
366
+ pageCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPages),
367
+ brickCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumBricks),
368
+ logicalVoxelCapacity: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumLogicalVoxels),
369
+ encodedSurfaceSampleCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumEncodedSurfaceSamples),
370
+ surfacePropertyCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumSurfaceProperties),
371
+ sectionCount: integerSchema(PVOX_MIN_STATIC_SECTION_COUNT, PVOX_MAX_SECTIONS),
372
+ levelSpanRecordCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPartitions * PVOX_DEFAULT_LIMITS.maximumLodCount * (PVOX_DEFAULT_LIMITS.maximumHierarchyDepth + 1)),
373
+ physicalPaletteRecordCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPhysicalProperties),
374
+ physicalEvidenceRecordCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPhysicalEvidenceEntries),
375
+ materialRegionCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumMaterialRegions),
376
+ interiorLayerRecordCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumInteriorLayers),
377
+ massPropertyRecordCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumMassPropertyRecords),
378
+ bondRecordCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumBondRecords),
379
+ hierarchyDepth: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumHierarchyDepth),
380
+ hierarchyNodeCount: integerSchema(1, PVOX_MAX_HIERARCHY_NODES),
381
+ lodCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumLodCount),
382
+ collisionHierarchyNodeCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumHierarchyNodes),
383
+ collisionBrickCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumBricks),
384
+ collisionLogicalVoxelCapacity: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumLogicalVoxels),
385
+ collisionEncodedSurfaceSampleCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumEncodedSurfaceSamples),
386
+ cpuResidentByteLength: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumCpuResidentBytes),
387
+ gpuResidentByteLength: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumGpuResidentBytes),
388
+ hasCollision: { type: "boolean" },
389
+ partitionCount: integerSchema(1, PVOX_DEFAULT_LIMITS.maximumPartitions),
390
+ maximumPartitionExtentMetres: numberSchema(Number.EPSILON, PVOX_MAX_ABSOLUTE_COORDINATE_METRES * 2),
391
+ maximumPartitionDiagonalMetres: numberSchema(Number.EPSILON, PVOX_MAX_ABSOLUTE_COORDINATE_METRES * Math.sqrt(12)),
392
+ }, ["boundsMetres", "dimensionsMetres", "geometryMode", "artifactByteLength", "pageCount", "brickCount", "logicalVoxelCapacity", "encodedSurfaceSampleCount", "surfacePropertyCount", "sectionCount", "levelSpanRecordCount", "physicalPaletteRecordCount", "physicalEvidenceRecordCount", "materialRegionCount", "interiorLayerRecordCount", "massPropertyRecordCount", "bondRecordCount", "hierarchyDepth", "hierarchyNodeCount", "lodCount", "collisionHierarchyNodeCount", "collisionBrickCount", "collisionLogicalVoxelCapacity", "collisionEncodedSurfaceSampleCount", "cpuResidentByteLength", "gpuResidentByteLength", "hasCollision", "partitionCount", "maximumPartitionExtentMetres", "maximumPartitionDiagonalMetres"]),
393
+ voxelCapabilityAssessment: objectSchema({
394
+ capability: { enum: PVOX_CAPABILITIES },
395
+ status: { enum: ["supported", "unsupported", "not-applicable"] },
396
+ evaluatorId: token,
397
+ evaluatorVersion: immutableVersion,
398
+ subjectContentHash: sha256,
399
+ evidenceHash: sha256,
400
+ reasonCodes,
401
+ evaluatedAt: timestamp,
402
+ }, ["capability", "status", "evaluatorId", "evaluatorVersion", "subjectContentHash", "evidenceHash", "reasonCodes", "evaluatedAt"], {
403
+ allOf: [
404
+ {
405
+ if: { properties: { status: { const: "supported" } }, required: ["status"] },
406
+ then: { properties: { reasonCodes: { ...reasonCodes, maxItems: 0 } } },
407
+ else: { properties: { reasonCodes: { ...reasonCodes, minItems: 1 } } },
408
+ },
409
+ ],
410
+ }),
411
+ physicalPropertyEvidence: objectSchema({
412
+ property: { enum: PVOX_PHYSICAL_PROPERTIES },
413
+ value: numberSchema(),
414
+ unit: stringSchema(32),
415
+ provenance: { enum: ["source", "authored", "derived", "inferred", "default"] },
416
+ confidence: numberSchema(0, 1),
417
+ subjectContentHash: sha256,
418
+ regionId: token,
419
+ materialId: token,
420
+ policyId: { const: PVOX_PHYSICAL_PROPERTY_POLICY_ID },
421
+ policyVersion: { const: PVOX_PHYSICAL_PROPERTY_POLICY_VERSION },
422
+ evidenceHash: sha256,
423
+ reviewedBy: token,
424
+ reviewedAt: timestamp,
425
+ reviewToken: attestation,
426
+ }, ["property", "value", "unit", "provenance", "confidence", "subjectContentHash", "regionId", "materialId", "policyId", "policyVersion", "evidenceHash"], {
427
+ dependentRequired: {
428
+ reviewedBy: ["reviewedAt", "reviewToken"],
429
+ reviewedAt: ["reviewedBy", "reviewToken"],
430
+ reviewToken: ["reviewedBy", "reviewedAt"],
431
+ },
432
+ allOf: [
433
+ {
434
+ if: { properties: { provenance: { const: "inferred" } }, required: ["provenance"] },
435
+ then: {
436
+ properties: { reviewedBy: token, reviewedAt: timestamp, reviewToken: attestation },
437
+ required: ["reviewedBy", "reviewedAt", "reviewToken"],
438
+ },
439
+ },
440
+ {
441
+ oneOf: Object.entries(PVOX_PHYSICAL_PROPERTY_POLICIES).map(([property, policy]) => ({
442
+ properties: {
443
+ property: { const: property },
444
+ unit: { const: policy.unit },
445
+ value: numberSchema(policy.minimum, policy.maximum),
446
+ },
447
+ required: ["property", "unit", "value"],
448
+ })),
449
+ },
450
+ ],
451
+ }),
452
+ pvoxFidelityEvidence: objectSchema({
453
+ profileId: { enum: PVOX_FIDELITY_PROFILE_IDS },
454
+ surfaceProfileId: { enum: ["precision-hero-v1", "props-furniture-v1", "rocks-organic-shells-v1", "buildings-v1"] },
455
+ profileVersion: { const: PVOX_FIDELITY_PROFILE_VERSION },
456
+ outcome: { enum: ["passed", "blocked"] },
457
+ canonicalDocumentHash: sha256,
458
+ pvoxBinaryClosureHash: sha256,
459
+ evaluatedDiagonalMetres: numberSchema(Number.EPSILON),
460
+ lod0CellSizeMetres: numberSchema(Number.EPSILON),
461
+ maximumAllowedSurfaceErrorMetres: numberSchema(0),
462
+ maximumSurfaceErrorMetres: numberSchema(0),
463
+ p99AllowedSurfaceErrorMetres: numberSchema(0),
464
+ p99SurfaceErrorMetres: numberSchema(0),
465
+ minimumSilhouetteIou: { const: 0.995 },
466
+ silhouetteIou: numberSchema(0, 1),
467
+ maximumAllowedContourDisplacementPx: { const: 0.5 },
468
+ maximumContourDisplacementPx: numberSchema(0),
469
+ minimumRenderedSsim: { const: 0.98 },
470
+ renderedSsim: numberSchema(0, 1),
471
+ maximumP95DeltaE2000: { const: 3 },
472
+ p95DeltaE2000: numberSchema(0, 100),
473
+ maximumNormalizedMaterialError: { const: 1 / 255 },
474
+ normalizedMaterialError: numberSchema(0, 1),
475
+ evidenceHash: sha256,
476
+ evaluatedAt: timestamp,
477
+ decisionToken: attestation,
478
+ }, ["profileId", "surfaceProfileId", "profileVersion", "outcome", "canonicalDocumentHash", "pvoxBinaryClosureHash", "evaluatedDiagonalMetres", "lod0CellSizeMetres", "maximumAllowedSurfaceErrorMetres", "maximumSurfaceErrorMetres", "p99AllowedSurfaceErrorMetres", "p99SurfaceErrorMetres", "minimumSilhouetteIou", "silhouetteIou", "maximumAllowedContourDisplacementPx", "maximumContourDisplacementPx", "minimumRenderedSsim", "renderedSsim", "maximumP95DeltaE2000", "p95DeltaE2000", "maximumNormalizedMaterialError", "normalizedMaterialError", "evidenceHash", "evaluatedAt", "decisionToken"]),
479
+ pvoxBrickPatch: objectSchema({
480
+ fieldKind: { enum: ["render-field", "collision-field"] },
481
+ lodLevel: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumLodCount - 1),
482
+ partitionIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPartitions - 1),
483
+ hierarchyDepth: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumHierarchyDepth),
484
+ mortonCode: { type: "string", pattern: "^[a-f0-9]{16}$" },
485
+ expectedPageIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPages - 1),
486
+ expectedPageHash: sha256,
487
+ operation: { enum: ["insert", "replace", "remove"] },
488
+ expectedBrickHash: sha256,
489
+ resultingBrickHash: sha256,
490
+ resultingPageHash: sha256,
491
+ }, ["fieldKind", "lodLevel", "partitionIndex", "hierarchyDepth", "mortonCode", "expectedPageIndex", "expectedPageHash", "operation", "expectedBrickHash", "resultingBrickHash", "resultingPageHash"]),
492
+ pvoxEditJournal: objectSchema({
493
+ journalVersion: { const: PVOX_EDIT_JOURNAL_VERSION },
494
+ baseContentHash: sha256,
495
+ basePageSetHash: sha256,
496
+ placementId: token,
497
+ gridVersion: token,
498
+ operationId: token,
499
+ expectedRevision: integerSchema(0),
500
+ resultingRevision: integerSchema(1),
501
+ previousJournalHash: sha256,
502
+ expectedRootHash: sha256,
503
+ resultingRootHash: sha256,
504
+ resultingRootHashAttestation: ref("pvoxEditOverlayRootHashAttestation"),
505
+ patches: arraySchema(ref("pvoxBrickPatch"), 1, PVOX_MAX_EDIT_PATCHES),
506
+ dirtyBoundsMetres: ref("bounds"),
507
+ massDeltaKg: numberSchema(),
508
+ journalHash: sha256,
509
+ journalHashAttestation: ref("pvoxEditJournalHashAttestation"),
510
+ recordedAt: timestamp,
511
+ }, ["journalVersion", "baseContentHash", "basePageSetHash", "placementId", "gridVersion", "operationId", "expectedRevision", "resultingRevision", "previousJournalHash", "expectedRootHash", "resultingRootHash", "resultingRootHashAttestation", "patches", "dirtyBoundsMetres", "massDeltaKg", "journalHash", "journalHashAttestation", "recordedAt"]),
512
+ pvoxGateEvidence: objectSchema({
513
+ kind: { enum: PVOX_NON_OVERRIDABLE_GATE_KINDS },
514
+ outcome: { enum: ["passed", "blocked"] },
515
+ validatorId: token,
516
+ validatorVersion: immutableVersion,
517
+ subjectContentHash: sha256,
518
+ evidenceHash: sha256,
519
+ reasonCodes,
520
+ evaluatedAt: timestamp,
521
+ attestationToken: attestation,
522
+ }, ["kind", "outcome", "validatorId", "validatorVersion", "subjectContentHash", "evidenceHash", "reasonCodes", "evaluatedAt", "attestationToken"]),
523
+ compilerEvidence: objectSchema({
524
+ compilerId: token,
525
+ compilerVersion: immutableVersion,
526
+ sourceFormat: token,
527
+ sourceContentHash: sha256,
528
+ canonicalDocumentHash: sha256,
529
+ compilationInputHash: sha256,
530
+ runtimeRequestProfileHash: sha256,
531
+ outputContentHash: sha256,
532
+ evidenceHash: sha256,
533
+ compiledAt: timestamp,
534
+ }, ["compilerId", "compilerVersion", "sourceFormat", "sourceContentHash", "canonicalDocumentHash", "compilationInputHash", "runtimeRequestProfileHash", "outputContentHash", "evidenceHash", "compiledAt"]),
535
+ physicalRegionInventoryEntry: objectSchema({
536
+ regionIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumMaterialRegions - 1),
537
+ physicalPaletteIndex: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumPhysicalProperties - 1),
538
+ regionId: token,
539
+ materialId: token,
540
+ }, ["regionIndex", "physicalPaletteIndex", "regionId", "materialId"]),
541
+ physicalRegionInventory: objectSchema({
542
+ inventoryVersion: { const: PVOX_PHYSICAL_REGION_INVENTORY_VERSION },
543
+ subjectContentHash: sha256,
544
+ inventoryHash: sha256,
545
+ inventoryHashAttestation: ref("pvoxPhysicalInventoryHashAttestation"),
546
+ validationEvidenceHash: sha256,
547
+ entries: arraySchema(ref("physicalRegionInventoryEntry"), 1, PVOX_DEFAULT_LIMITS.maximumMaterialRegions),
548
+ }, ["inventoryVersion", "subjectContentHash", "inventoryHash", "inventoryHashAttestation", "validationEvidenceHash", "entries"]),
549
+ reviewedStructuralEvidence: objectSchema({
550
+ kind: { enum: ["mass-properties", "bond-graph", "interior-layers"] },
551
+ subjectContentHash: sha256,
552
+ physicalInventoryHash: sha256,
553
+ recordCount: integerSchema(0, PVOX_DEFAULT_LIMITS.maximumBondRecords),
554
+ evidenceHash: sha256,
555
+ reviewerId: token,
556
+ reviewedAt: timestamp,
557
+ reviewToken: attestation,
558
+ }, ["kind", "subjectContentHash", "physicalInventoryHash", "recordCount", "evidenceHash", "reviewerId", "reviewedAt", "reviewToken"]),
559
+ transform: objectSchema({ translationMetres: vector3, rotationQuaternion: quaternion, scale: positiveVector3 }, ["translationMetres", "rotationQuaternion", "scale"]),
560
+ modelAssetRef: objectSchema({
561
+ contractVersion: { const: MODEL_RESOLUTION_CONTRACT_VERSION },
562
+ assetId: { type: "string", pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
563
+ version: immutableVersion,
564
+ kind: { enum: MODEL_ASSET_KINDS },
565
+ contentHash: sha256,
566
+ runtimeManifestUri: { type: "string", pattern: "^mcp://models/catalog/[a-z0-9]+(?:-[a-z0-9]+)*/versions/[A-Za-z0-9][A-Za-z0-9._-]*/manifest$" },
567
+ }, ["contractVersion", "assetId", "version", "kind", "contentHash", "runtimeManifestUri"]),
568
+ existingAssemblyChildRef: objectSchema({
569
+ disposition: { const: "existing" },
570
+ representation: { const: "pvox" },
571
+ asset: ref("modelAssetRef"),
572
+ processingManifestId: token,
573
+ binaryClosureHash: sha256,
574
+ processingClosureHash: sha256,
575
+ processingManifestUri: { type: "string", pattern: "^mcp://models/catalog/.+/processing-manifest$" },
576
+ }, ["disposition", "representation", "asset", "processingManifestId", "binaryClosureHash", "processingClosureHash", "processingManifestUri"]),
577
+ stagedAssemblyChildRef: objectSchema({
578
+ disposition: { const: "staged-derived" },
579
+ representation: { const: "pvox" },
580
+ derivedId: pathSegment,
581
+ kind: { const: "leaf" },
582
+ contentHash: sha256,
583
+ binaryClosureHash: sha256,
584
+ processingClosureHash: sha256,
585
+ processingManifestId: token,
586
+ processingManifestUri: { type: "string", pattern: "^mcp://models/resolutions/.+/processing-manifest$" },
587
+ }, ["disposition", "representation", "derivedId", "kind", "contentHash", "binaryClosureHash", "processingClosureHash", "processingManifestId", "processingManifestUri"]),
588
+ assemblyChild: objectSchema({
589
+ instanceId: token,
590
+ parentInstanceId: token,
591
+ assetRef: { oneOf: [ref("existingAssemblyChildRef"), ref("stagedAssemblyChildRef")] },
592
+ transform: ref("transform"),
593
+ }, ["instanceId", "assetRef", "transform"]),
594
+ modelProcessingManifest: objectSchema({
595
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
596
+ representation: { const: "pvox" },
597
+ manifestId: token,
598
+ resolutionId: pathSegment,
599
+ candidateId: pathSegment,
600
+ kind: { enum: MODEL_ASSET_KINDS },
601
+ requestProfileId: token,
602
+ requestSemanticProfileHash: sha256,
603
+ capabilityProfileId: { enum: PVOX_RUNTIME_CAPABILITY_PROFILE_IDS },
604
+ contentHash: sha256,
605
+ binaryClosureHash: sha256,
606
+ processingClosureHash: sha256,
607
+ processingClosureAttestation: ref("pvoxProcessingClosureHashAttestation"),
608
+ assemblyClosureHash: sha256,
609
+ assemblyClosureAttestation: ref("pvoxAssemblyClosureHashAttestation"),
610
+ compilationInputHash: sha256,
611
+ runtimeRequestProfileHash: sha256,
612
+ coordinateSystem: ref("coordinateSystem"),
613
+ pvox: ref("pvoxAssetManifest"),
614
+ technicalProfile: ref("voxelTechnicalProfile"),
615
+ requiredCapabilities: { ...arraySchema({ enum: PVOX_CAPABILITIES }, 1, PVOX_CAPABILITIES.length), uniqueItems: true },
616
+ capabilities: { ...arraySchema(ref("voxelCapabilityAssessment"), PVOX_CAPABILITIES.length, PVOX_CAPABILITIES.length), uniqueItems: true },
617
+ capabilityEvidenceSetHash: sha256,
618
+ capabilityEvidenceSetAttestation: ref("pvoxCapabilitySetHashAttestation"),
619
+ physicalRegionInventory: ref("physicalRegionInventory"),
620
+ physicalProperties: arraySchema(ref("physicalPropertyEvidence"), 0, PVOX_DEFAULT_LIMITS.maximumPhysicalEvidenceEntries),
621
+ physicalEvidenceHash: sha256,
622
+ physicalEvidenceAttestation: ref("pvoxPhysicalEvidenceHashAttestation"),
623
+ massPropertiesEvidence: ref("reviewedStructuralEvidence"),
624
+ bondGraphEvidence: ref("reviewedStructuralEvidence"),
625
+ interiorLayerEvidence: ref("reviewedStructuralEvidence"),
626
+ converter: ref("compilerEvidence"),
627
+ fidelity: ref("pvoxFidelityEvidence"),
628
+ children: arraySchema(ref("assemblyChild"), 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren),
629
+ processedAt: timestamp,
630
+ }, ["contractVersion", "representation", "manifestId", "resolutionId", "candidateId", "kind", "requestProfileId", "requestSemanticProfileHash", "capabilityProfileId", "contentHash", "binaryClosureHash", "processingClosureHash", "processingClosureAttestation", "assemblyClosureHash", "assemblyClosureAttestation", "compilationInputHash", "runtimeRequestProfileHash", "coordinateSystem", "pvox", "technicalProfile", "requiredCapabilities", "capabilities", "capabilityEvidenceSetHash", "capabilityEvidenceSetAttestation", "physicalRegionInventory", "physicalProperties", "physicalEvidenceHash", "physicalEvidenceAttestation", "massPropertiesEvidence", "bondGraphEvidence", "interiorLayerEvidence", "converter", "fidelity", "children", "processedAt"]),
631
+ hardConstraintsV1: objectSchema({
632
+ boundsMetres: ref("bounds"),
633
+ dimensionsMetres: ref("dimensions"),
634
+ maxTriangles: integerSchema(1, STATIC_WORLD_V1_MODEL_POLICY.maxTriangles),
635
+ maxBytes: integerSchema(1, STATIC_WORLD_V1_MODEL_POLICY.maxBytes),
636
+ maxTextureBytes: integerSchema(1, STATIC_WORLD_V1_MODEL_POLICY.maxTextureBytes),
637
+ maxTextureDimensionPx: integerSchema(1, STATIC_WORLD_V1_MODEL_POLICY.maxTextureDimensionPx),
638
+ maxPartitionCellMetres: numberSchema(Number.EPSILON, STATIC_WORLD_V1_MODEL_POLICY.maxPartitionCellMetres),
639
+ lod: { enum: ["required", "optional", "forbidden"] },
640
+ collision: { enum: ["required", "optional", "forbidden"] },
641
+ partition: { enum: ["single", "allowed", "required"] },
642
+ }, ["maxTriangles", "maxBytes", "maxTextureBytes", "maxTextureDimensionPx", "maxPartitionCellMetres", "lod", "collision", "partition"]),
643
+ modelRequestSpecV1: objectSchema({
644
+ contractVersion: { const: MODEL_RESOLUTION_CONTRACT_VERSION },
645
+ policyProfileId: { const: STATIC_WORLD_V1_MODEL_POLICY.id },
646
+ query: stringSchema(1_000),
647
+ revision: integerSchema(0, MODEL_REQUEST_MAX_REVISION),
648
+ locale: stringSchema(64),
649
+ rankerId: token,
650
+ hardConstraints: ref("hardConstraintsV1"),
651
+ softPreferences: ref("softPreferences"),
652
+ exclusions: arraySchema(stringSchema(256), 0, 32),
653
+ }, ["contractVersion", "policyProfileId", "query", "revision", "hardConstraints", "softPreferences", "exclusions"]),
654
+ rankerRef: objectSchema({
655
+ id: token,
656
+ version: immutableVersion,
657
+ calibrationId: token,
658
+ calibrationVersion: immutableVersion,
659
+ evidenceMode: { enum: MODEL_RANKER_EVIDENCE_MODES },
660
+ assuranceCeiling: { enum: MODEL_MATCH_ASSURANCE_BANDS },
661
+ }, ["id", "version", "calibrationId", "calibrationVersion", "evidenceMode", "assuranceCeiling"]),
662
+ modelMatchAssessment: objectSchema({
663
+ contractVersion: { const: MODEL_RESOLUTION_CONTRACT_VERSION },
664
+ score: numberSchema(0, 1),
665
+ assurance: { enum: MODEL_MATCH_ASSURANCE_BANDS },
666
+ hardConstraintPass: { type: "boolean" },
667
+ exactMatch: { type: "boolean" },
668
+ reasonCodes: releasedV1ReasonCodes,
669
+ ranker: ref("rankerRef"),
670
+ fidelityWarnings: arraySchema(stringSchema(256), 0, 32),
671
+ request: ref("modelRequestSpecV1"),
672
+ candidateId: pathSegment,
673
+ candidateContentHash: sha256,
674
+ requestSemanticProfileHash: sha256,
675
+ requestSemanticProfileCanonical: stringSchema(65_536),
676
+ evidenceHash: sha256,
677
+ }, ["contractVersion", "score", "assurance", "hardConstraintPass", "exactMatch", "reasonCodes", "ranker", "fidelityWarnings", "request", "candidateId", "candidateContentHash", "requestSemanticProfileHash", "requestSemanticProfileCanonical", "evidenceHash"]),
678
+ provenance: objectSchema({
679
+ kind: { enum: MODEL_PROVENANCE_KINDS },
680
+ sourceId: token,
681
+ sourceAssetId: opaqueSourceAssetId,
682
+ sourcePageUri: { type: "string", pattern: "^https://", maxLength: 2_048 },
683
+ contentHash: sha256,
684
+ capturedAt: timestamp,
685
+ }, ["kind", "sourceId", "sourceAssetId", "contentHash", "capturedAt"]),
686
+ attribution: objectSchema({
687
+ title: stringSchema(256),
688
+ creator: stringSchema(256),
689
+ notice: stringSchema(512),
690
+ sourcePageUri: { type: "string", pattern: "^https://", maxLength: 2_048 },
691
+ }, ["title", "creator", "notice"]),
692
+ rights: objectSchema({
693
+ decisionId: token,
694
+ decisionToken: attestation,
695
+ policyId: token,
696
+ policyVersion: immutableVersion,
697
+ sourceId: token,
698
+ sourceAssetId: opaqueSourceAssetId,
699
+ sourceContentHash: sha256,
700
+ status: { enum: MODEL_RIGHTS_STATUSES },
701
+ licenseId: token,
702
+ evidencePageUri: { type: "string", pattern: "^https://", maxLength: 2_048 },
703
+ attribution: ref("attribution"),
704
+ reviewedAt: timestamp,
705
+ }, ["decisionId", "decisionToken", "policyId", "policyVersion", "sourceId", "sourceAssetId", "sourceContentHash", "status", "licenseId", "evidencePageUri", "reviewedAt"]),
706
+ existingCandidateAssetRef: objectSchema({ disposition: { const: "existing" }, kind: { enum: MODEL_ASSET_KINDS }, contentHash: sha256, asset: ref("modelAssetRef") }, ["disposition", "kind", "contentHash", "asset"]),
707
+ proposedCandidateAssetRef: objectSchema({ disposition: { const: "proposed" }, proposalId: token, kind: { enum: MODEL_ASSET_KINDS }, contentHash: sha256 }, ["disposition", "proposalId", "kind", "contentHash"]),
708
+ confirmationView: objectSchema({
709
+ kind: { enum: MODEL_CONFIRMATION_VIEW_KINDS },
710
+ imageUri: { type: "string", pattern: "^mcp://models/resolutions/.+\\.png$", maxLength: 512 },
711
+ sha256,
712
+ contentType: { const: "image/png" },
713
+ width: { const: MODEL_CONFIRMATION_VIEW_SIZE_PX },
714
+ height: { const: MODEL_CONFIRMATION_VIEW_SIZE_PX },
715
+ }, ["kind", "imageUri", "sha256", "contentType", "width", "height"]),
716
+ renderEvidence: objectSchema({
717
+ renderId: token,
718
+ representation: { const: "pvox" },
719
+ lodLevel: { const: 0 },
720
+ traversalBackend: { const: "native-pvox" },
721
+ rendererId: { const: PVOX_NATIVE_RENDERER_ID },
722
+ rendererVersion: immutableVersion,
723
+ rendererQualificationHash: sha256,
724
+ settingsId: { const: PVOX_NATIVE_REVIEW_SETTINGS_ID },
725
+ settingsVersion: immutableVersion,
726
+ cameraQualificationHash: sha256,
727
+ processingManifestId: token,
728
+ processingClosureHash: sha256,
729
+ pvoxContentHash: sha256,
730
+ pvoxRootHash: sha256,
731
+ pvoxDirectoryHash: sha256,
732
+ pvoxPageSetHash: sha256,
733
+ viewSha256s: shaTuple,
734
+ renderedAt: timestamp,
735
+ evidenceHash: sha256,
736
+ evidenceHashAttestation: ref("pvoxRenderEvidenceHashAttestation"),
737
+ }, ["renderId", "representation", "lodLevel", "traversalBackend", "rendererId", "rendererVersion", "rendererQualificationHash", "settingsId", "settingsVersion", "cameraQualificationHash", "processingManifestId", "processingClosureHash", "pvoxContentHash", "pvoxRootHash", "pvoxDirectoryHash", "pvoxPageSetHash", "viewSha256s", "renderedAt", "evidenceHash", "evidenceHashAttestation"]),
738
+ confirmationBinding: objectSchema({
739
+ bindingHash: sha256,
740
+ bindingHashAttestation: ref("pvoxConfirmationBindingHashAttestation"),
741
+ resolutionId: pathSegment,
742
+ requesterId: token,
743
+ request: ref("modelRequestSpecV2"),
744
+ requestSemanticProfileHash: sha256,
745
+ requestRevision: integerSchema(0, MODEL_REQUEST_MAX_REVISION),
746
+ candidateId: pathSegment,
747
+ candidateContentHash: sha256,
748
+ candidateAssetRef: { oneOf: [ref("existingCandidateAssetRef"), ref("proposedCandidateAssetRef")] },
749
+ match: ref("modelMatchAssessment"),
750
+ provenance: ref("provenance"),
751
+ rights: ref("rights"),
752
+ sourceContentHash: sha256,
753
+ binaryClosureHash: sha256,
754
+ pvoxRootHash: sha256,
755
+ pvoxDirectoryHash: sha256,
756
+ pvoxPageSetHash: sha256,
757
+ compilationInputHash: sha256,
758
+ runtimeRequestProfileHash: sha256,
759
+ processingClosureHash: sha256,
760
+ assemblyClosureHash: sha256,
761
+ evaluationClosureHash: sha256,
762
+ capabilityEvidenceSetHash: sha256,
763
+ hardGates: { ...arraySchema(ref("pvoxGateEvidence"), PVOX_NON_OVERRIDABLE_GATE_KINDS.length, PVOX_NON_OVERRIDABLE_GATE_KINDS.length), uniqueItems: true },
764
+ viewSha256s: shaTuple,
765
+ rightsDecisionId: token,
766
+ fidelityEvidenceHash: sha256,
767
+ physicalEvidenceHash: sha256,
768
+ rendererId: { const: PVOX_NATIVE_RENDERER_ID },
769
+ rendererVersion: immutableVersion,
770
+ rendererEvidenceHash: sha256,
771
+ renderEvidence: ref("renderEvidence"),
772
+ }, ["bindingHash", "bindingHashAttestation", "resolutionId", "requesterId", "request", "requestSemanticProfileHash", "requestRevision", "candidateId", "candidateContentHash", "candidateAssetRef", "match", "provenance", "rights", "sourceContentHash", "binaryClosureHash", "pvoxRootHash", "pvoxDirectoryHash", "pvoxPageSetHash", "compilationInputHash", "runtimeRequestProfileHash", "processingClosureHash", "assemblyClosureHash", "evaluationClosureHash", "capabilityEvidenceSetHash", "hardGates", "viewSha256s", "rightsDecisionId", "fidelityEvidenceHash", "physicalEvidenceHash", "rendererId", "rendererVersion", "rendererEvidenceHash", "renderEvidence"]),
773
+ modelCandidate: objectSchema({
774
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
775
+ resolutionId: pathSegment,
776
+ requesterId: token,
777
+ candidateId: pathSegment,
778
+ request: ref("modelRequestSpecV2"),
779
+ admissionStatus: { enum: ["confirmable", "diagnostic"] },
780
+ assetRef: { oneOf: [ref("existingCandidateAssetRef"), ref("proposedCandidateAssetRef")] },
781
+ match: ref("modelMatchAssessment"),
782
+ provenance: ref("provenance"),
783
+ rights: ref("rights"),
784
+ processingManifest: ref("modelProcessingManifest"),
785
+ views: arraySchema(ref("confirmationView"), 4, 4),
786
+ renderEvidence: ref("renderEvidence"),
787
+ evaluationClosureHash: sha256,
788
+ evaluationClosureAttestation: ref("pvoxEvaluationClosureHashAttestation"),
789
+ hardGates: { ...arraySchema(ref("pvoxGateEvidence"), PVOX_NON_OVERRIDABLE_GATE_KINDS.length, PVOX_NON_OVERRIDABLE_GATE_KINDS.length), uniqueItems: true },
790
+ confirmationBinding: ref("confirmationBinding"),
791
+ confirmationToken: attestation,
792
+ blockingReasonCodes: arraySchema(reasonCode, 1, 256),
793
+ confirmationRequired: { type: "boolean" },
794
+ }, ["contractVersion", "resolutionId", "requesterId", "candidateId", "request", "admissionStatus", "assetRef", "match", "provenance", "rights", "processingManifest", "views", "renderEvidence", "evaluationClosureHash", "evaluationClosureAttestation", "hardGates", "confirmationRequired"], {
795
+ oneOf: [
796
+ {
797
+ properties: {
798
+ admissionStatus: { const: "confirmable" },
799
+ confirmationRequired: { const: true },
800
+ confirmationBinding: ref("confirmationBinding"),
801
+ confirmationToken: attestation,
802
+ blockingReasonCodes: arraySchema(reasonCode, 1, 256),
803
+ },
804
+ required: ["admissionStatus", "confirmationRequired", "confirmationBinding", "confirmationToken"],
805
+ not: { required: ["blockingReasonCodes"], properties: { blockingReasonCodes: {} } },
806
+ },
807
+ {
808
+ properties: {
809
+ admissionStatus: { const: "diagnostic" },
810
+ confirmationRequired: { const: false },
811
+ blockingReasonCodes: arraySchema(reasonCode, 1, 256),
812
+ confirmationBinding: ref("confirmationBinding"),
813
+ confirmationToken: attestation,
814
+ },
815
+ required: ["admissionStatus", "confirmationRequired", "blockingReasonCodes"],
816
+ not: {
817
+ anyOf: [
818
+ { required: ["confirmationBinding"], properties: { confirmationBinding: {} } },
819
+ { required: ["confirmationToken"], properties: { confirmationToken: {} } },
820
+ ],
821
+ },
822
+ },
823
+ ],
824
+ }),
825
+ modelCandidateConfirmation: objectSchema({
826
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
827
+ confirmationId: token,
828
+ resolutionId: pathSegment,
829
+ requesterId: token,
830
+ candidateId: pathSegment,
831
+ confirmationToken: attestation,
832
+ confirmationBindingHash: sha256,
833
+ viewSha256s: shaTuple,
834
+ confirmedBy: stringSchema(256),
835
+ confirmedAt: timestamp,
836
+ semanticRiskAccepted: { type: "boolean" },
837
+ }, ["contractVersion", "confirmationId", "resolutionId", "requesterId", "candidateId", "confirmationToken", "confirmationBindingHash", "viewSha256s", "confirmedBy", "confirmedAt", "semanticRiskAccepted"]),
838
+ modelPromotionReceipt: objectSchema({
839
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
840
+ promotionId: token,
841
+ resolutionId: pathSegment,
842
+ requesterId: token,
843
+ candidateId: pathSegment,
844
+ proposalId: token,
845
+ candidateAssetRef: ref("proposedCandidateAssetRef"),
846
+ confirmationId: token,
847
+ confirmationBindingHash: sha256,
848
+ processingManifestId: token,
849
+ processingContentHash: sha256,
850
+ processingClosureHash: sha256,
851
+ assemblyClosureHash: sha256,
852
+ assemblyChildClosureHashes: arraySchema(sha256, 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren),
853
+ finalAssetRef: ref("modelAssetRef"),
854
+ creditsRecordHash: sha256,
855
+ catalogRowHash: sha256,
856
+ indexSnapshotHash: sha256,
857
+ catalogPointerEtag: token,
858
+ indexPointerEtag: token,
859
+ publicationState: { const: "pointer-last-complete" },
860
+ creditsWrittenAt: timestamp,
861
+ catalogRowWrittenAt: timestamp,
862
+ indexSnapshotWrittenAt: timestamp,
863
+ pointerPublishedAt: timestamp,
864
+ publicationHash: sha256,
865
+ publicationHashAttestation: ref("pvoxPublicationHashAttestation"),
866
+ promotedAt: timestamp,
867
+ publicationToken: attestation,
868
+ }, ["contractVersion", "promotionId", "resolutionId", "requesterId", "candidateId", "proposalId", "candidateAssetRef", "confirmationId", "confirmationBindingHash", "processingManifestId", "processingContentHash", "processingClosureHash", "assemblyClosureHash", "assemblyChildClosureHashes", "finalAssetRef", "creditsRecordHash", "catalogRowHash", "indexSnapshotHash", "catalogPointerEtag", "indexPointerEtag", "publicationState", "creditsWrittenAt", "catalogRowWrittenAt", "indexSnapshotWrittenAt", "pointerPublishedAt", "publicationHash", "publicationHashAttestation", "promotedAt", "publicationToken"]),
869
+ modelRefinementQuestion: objectSchema({ questionId: token, prompt: stringSchema(500), reasonCodes }, ["questionId", "prompt", "reasonCodes"]),
870
+ modelResolution: objectSchema({
871
+ contractVersion: { const: MODEL_RESOLUTION_V2_CONTRACT_VERSION },
872
+ resolutionId: pathSegment,
873
+ requesterId: token,
874
+ request: ref("modelRequestSpecV2"),
875
+ attempts: integerSchema(1, 12),
876
+ state: { enum: MODEL_RESOLUTION_V2_STATES },
877
+ compatibilityState: { enum: MODEL_RESOLUTION_STATES },
878
+ candidates: arraySchema(ref("modelCandidate"), 0, 20),
879
+ bestCandidate: ref("modelCandidate"),
880
+ confirmation: ref("modelCandidateConfirmation"),
881
+ promotionReceipt: ref("modelPromotionReceipt"),
882
+ refinementQuestions: arraySchema(ref("modelRefinementQuestion"), 0, 3),
883
+ finalAssetRef: ref("modelAssetRef"),
884
+ stateReasonCode: reasonCode,
885
+ createdAt: timestamp,
886
+ updatedAt: timestamp,
887
+ }, ["contractVersion", "resolutionId", "requesterId", "request", "attempts", "state", "compatibilityState", "candidates", "refinementQuestions", "createdAt", "updatedAt"], {
888
+ allOf: [
889
+ {
890
+ if: { properties: { state: { const: "awaiting-confirmation" } }, required: ["state"] },
891
+ then: {
892
+ properties: {
893
+ bestCandidate: {
894
+ type: "object",
895
+ properties: { admissionStatus: { const: "confirmable" } },
896
+ required: ["admissionStatus"],
897
+ },
898
+ },
899
+ required: ["bestCandidate"],
900
+ },
901
+ },
902
+ {
903
+ if: {
904
+ properties: {
905
+ state: { const: "awaiting-confirmation" },
906
+ bestCandidate: {
907
+ type: "object",
908
+ properties: {
909
+ match: {
910
+ type: "object",
911
+ properties: { assurance: { const: "low" } },
912
+ required: ["assurance"],
913
+ },
914
+ },
915
+ required: ["match"],
916
+ },
917
+ },
918
+ required: ["state", "bestCandidate"],
919
+ },
920
+ then: {
921
+ properties: { refinementQuestions: arraySchema(ref("modelRefinementQuestion"), 1, 3) },
922
+ required: ["refinementQuestions"],
923
+ },
924
+ },
925
+ {
926
+ if: { properties: { state: { enum: ["promoting", "completed"] } }, required: ["state"] },
927
+ then: {
928
+ properties: {
929
+ bestCandidate: {
930
+ type: "object",
931
+ properties: { admissionStatus: { const: "confirmable" } },
932
+ required: ["admissionStatus"],
933
+ },
934
+ confirmation: ref("modelCandidateConfirmation"),
935
+ },
936
+ required: ["bestCandidate", "confirmation"],
937
+ },
938
+ else: {
939
+ not: {
940
+ properties: { confirmation: {} },
941
+ required: ["confirmation"],
942
+ },
943
+ },
944
+ },
945
+ {
946
+ if: { properties: { state: { const: "completed" } }, required: ["state"] },
947
+ then: {
948
+ properties: { finalAssetRef: ref("modelAssetRef") },
949
+ required: ["finalAssetRef"],
950
+ },
951
+ else: {
952
+ not: {
953
+ properties: { finalAssetRef: {} },
954
+ required: ["finalAssetRef"],
955
+ },
956
+ },
957
+ },
958
+ {
959
+ if: {
960
+ properties: {
961
+ state: { const: "completed" },
962
+ bestCandidate: {
963
+ type: "object",
964
+ properties: {
965
+ assetRef: {
966
+ type: "object",
967
+ properties: { disposition: { const: "proposed" } },
968
+ required: ["disposition"],
969
+ },
970
+ },
971
+ required: ["assetRef"],
972
+ },
973
+ },
974
+ required: ["state", "bestCandidate"],
975
+ },
976
+ then: {
977
+ properties: { promotionReceipt: ref("modelPromotionReceipt") },
978
+ required: ["promotionReceipt"],
979
+ },
980
+ else: {
981
+ not: {
982
+ properties: { promotionReceipt: {} },
983
+ required: ["promotionReceipt"],
984
+ },
985
+ },
986
+ },
987
+ {
988
+ if: {
989
+ properties: { state: { enum: ["unresolved", "failed", "cancelled"] } },
990
+ required: ["state"],
991
+ },
992
+ then: {
993
+ properties: { stateReasonCode: reasonCode },
994
+ required: ["stateReasonCode"],
995
+ },
996
+ else: {
997
+ not: {
998
+ properties: { stateReasonCode: {} },
999
+ required: ["stateReasonCode"],
1000
+ },
1001
+ },
1002
+ },
1003
+ ],
1004
+ }),
1005
+ };
1006
+
1007
+ const frozenDefinitions = deepFreeze(definitions);
1008
+
1009
+ function standaloneSchema(definitionName: string, title: string): PvoxModelResolutionJsonSchema {
1010
+ const definition = frozenDefinitions[definitionName];
1011
+ if (definition === undefined || definition.type !== "object" || definition.additionalProperties !== false) {
1012
+ throw new Error("PVOX standalone schema requires a closed object definition.");
1013
+ }
1014
+ return deepFreeze({
1015
+ $id: `https://schemas.plasius.com/asset-contracts/model-resolution/${MODEL_RESOLUTION_V2_CONTRACT_VERSION}/${definitionName}.schema.json`,
1016
+ $schema: "https://json-schema.org/draft/2020-12/schema" as const,
1017
+ title,
1018
+ ...definition,
1019
+ type: "object" as const,
1020
+ additionalProperties: false as const,
1021
+ $defs: frozenDefinitions,
1022
+ });
1023
+ }
1024
+
1025
+ /** Complete closed JSON Schema 2020-12 descriptors for MCP/admin consumers. */
1026
+ export const MODEL_RESOLUTION_V2_JSON_SCHEMAS = deepFreeze({
1027
+ modelRequestSpec: standaloneSchema("modelRequestSpecV2", "ModelRequestSpecV2"),
1028
+ pvoxAssetManifest: standaloneSchema("pvoxAssetManifest", "PvoxAssetManifestV1"),
1029
+ voxelTechnicalProfile: standaloneSchema("voxelTechnicalProfile", "VoxelTechnicalProfile"),
1030
+ voxelCapabilityAssessment: standaloneSchema("voxelCapabilityAssessment", "VoxelCapabilityAssessment"),
1031
+ physicalPropertyEvidence: standaloneSchema("physicalPropertyEvidence", "PhysicalPropertyEvidence"),
1032
+ pvoxEditJournal: standaloneSchema("pvoxEditJournal", "PvoxEditJournal"),
1033
+ pvoxFidelityEvidence: standaloneSchema("pvoxFidelityEvidence", "PvoxFidelityEvidence"),
1034
+ pvoxGateEvidence: standaloneSchema("pvoxGateEvidence", "PvoxGateEvidence"),
1035
+ modelProcessingManifest: standaloneSchema("modelProcessingManifest", "ModelProcessingManifestV2"),
1036
+ modelCandidate: standaloneSchema("modelCandidate", "ModelCandidateV2"),
1037
+ modelCandidateConfirmation: standaloneSchema("modelCandidateConfirmation", "ModelCandidateConfirmationV2"),
1038
+ modelPromotionReceipt: standaloneSchema("modelPromotionReceipt", "ModelPromotionReceiptV2"),
1039
+ modelRefinementQuestion: standaloneSchema("modelRefinementQuestion", "ModelRefinementQuestionV2"),
1040
+ modelResolution: standaloneSchema("modelResolution", "ModelResolutionV2"),
1041
+ });