@plasius/asset-contracts 0.6.0 → 0.8.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.
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  SHADER_VALIDATION_EVIDENCE_VERSION,
6
6
  SUPPORTED_ADDITIVE_WEBGPU_MATRIX_POLICIES,
7
7
  SUPPORTED_STABLE_WEBGPU_MATRIX_POLICIES,
8
- canonicalizeGpuContract as canonicalizeGpuContract3,
9
- computeSha256 as computeSha2562,
8
+ canonicalizeGpuContract as canonicalizeGpuContract4,
9
+ computeSha256 as computeSha2563,
10
10
  parseGpuInterfaceManifest,
11
11
  parseJsonBytes,
12
12
  parseModelGpuCompatibilityDescriptor,
@@ -196,11 +196,11 @@ function assertNoDirectUrl(value, fieldName) {
196
196
  }
197
197
  }
198
198
  function requiredToken(value, fieldName) {
199
- const token2 = requiredString(value, fieldName, 128);
200
- if (!TOKEN_PATTERN.test(token2)) {
199
+ const token3 = requiredString(value, fieldName, 128);
200
+ if (!TOKEN_PATTERN.test(token3)) {
201
201
  throw new Error(`${fieldName} must be a token up to 128 characters.`);
202
202
  }
203
- return token2;
203
+ return token3;
204
204
  }
205
205
  function requiredModelPathSegment(value, fieldName) {
206
206
  const segment = requiredString(value, fieldName, 128);
@@ -2797,7 +2797,7 @@ function requireEnum(value, allowed, fieldName) {
2797
2797
  }
2798
2798
  function requireReasonCodes(value, fieldName) {
2799
2799
  const entries = asDenseArray(value, fieldName, 0, 32);
2800
- const result = entries.map((entry, index) => requireReasonCode(entry, `${fieldName}[${index}]`));
2800
+ const result = entries.map((entry2, index) => requireReasonCode(entry2, `${fieldName}[${index}]`));
2801
2801
  if (new Set(result).size !== result.length) throw new Error(`${fieldName} must not contain duplicates.`);
2802
2802
  return result;
2803
2803
  }
@@ -3119,7 +3119,7 @@ function createPvoxRuntimeRequestProfileV1(value) {
3119
3119
  const record2 = asRecord(value, fieldName);
3120
3120
  exactKeys(record2, ["profileId", "fidelityProfileId", "capabilityProfileId", "geometryMode", "requiredCapabilities", "limits"], fieldName);
3121
3121
  const requestedCapabilityEntries = asDenseArray(record2.requiredCapabilities, `${fieldName}.requiredCapabilities`, 1, PVOX_CAPABILITIES.length);
3122
- const requiredCapabilities = requestedCapabilityEntries.map((entry, index) => requireEnum(entry, PVOX_CAPABILITIES, `${fieldName}.requiredCapabilities[${index}]`));
3122
+ const requiredCapabilities = requestedCapabilityEntries.map((entry2, index) => requireEnum(entry2, PVOX_CAPABILITIES, `${fieldName}.requiredCapabilities[${index}]`));
3123
3123
  if (new Set(requiredCapabilities).size !== requiredCapabilities.length) {
3124
3124
  throw new Error(`${fieldName}.requiredCapabilities must not contain duplicates.`);
3125
3125
  }
@@ -3282,7 +3282,7 @@ function createPvoxAssetManifestV1(input) {
3282
3282
  }
3283
3283
  if (expectedOffset !== artifact.byteLength) throw new Error("PvoxAssetManifestV1 pages must exactly cover the artifact bytes.");
3284
3284
  const lodEntries = asDenseArray(record2.lods, "PvoxAssetManifestV1.lods", 1, 4);
3285
- const lods = lodEntries.map((entry, index) => createLod(entry, index, pages.length));
3285
+ const lods = lodEntries.map((entry2, index) => createLod(entry2, index, pages.length));
3286
3286
  for (const [index, current] of lods.entries()) {
3287
3287
  if (current.level !== index) throw new Error("PvoxAssetManifestV1 LOD levels must be contiguous from LOD0.");
3288
3288
  const previous = lods[index - 1];
@@ -3518,7 +3518,7 @@ function createPhysicalPropertyEvidence(input) {
3518
3518
  const reviewedBy = record2.reviewedBy === void 0 ? void 0 : requireToken(record2.reviewedBy, "PhysicalPropertyEvidence.reviewedBy");
3519
3519
  const reviewedAt = record2.reviewedAt === void 0 ? void 0 : requireTimestamp(record2.reviewedAt, "PhysicalPropertyEvidence.reviewedAt");
3520
3520
  const reviewToken = record2.reviewToken === void 0 ? void 0 : requireAttestation(record2.reviewToken, "PhysicalPropertyEvidence.reviewToken");
3521
- if (new Set([reviewedBy, reviewedAt, reviewToken].map((entry) => entry === void 0)).size !== 1) throw new Error("PhysicalPropertyEvidence signed review identity, timestamp, and token must be supplied together.");
3521
+ if (new Set([reviewedBy, reviewedAt, reviewToken].map((entry2) => entry2 === void 0)).size !== 1) throw new Error("PhysicalPropertyEvidence signed review identity, timestamp, and token must be supplied together.");
3522
3522
  if (provenance === "inferred" && reviewedBy === void 0) throw new Error("Inferred PhysicalPropertyEvidence requires human review.");
3523
3523
  return deepFreeze2({
3524
3524
  property,
@@ -3541,9 +3541,9 @@ function createPvoxPhysicalRegionInventoryV1(input) {
3541
3541
  exactKeys(record2, ["inventoryVersion", "subjectContentHash", "inventoryHash", "inventoryHashAttestation", "validationEvidenceHash", "entries"], fieldName);
3542
3542
  if (record2.inventoryVersion !== PVOX_PHYSICAL_REGION_INVENTORY_VERSION) throw new Error(`${fieldName}.inventoryVersion is unsupported.`);
3543
3543
  const entriesInput = asDenseArray(record2.entries, `${fieldName}.entries`, 1, PVOX_DEFAULT_LIMITS.maximumMaterialRegions);
3544
- const entries = entriesInput.map((entry, index) => {
3544
+ const entries = entriesInput.map((entry2, index) => {
3545
3545
  const entryName = `${fieldName}.entries[${index}]`;
3546
- const item = asRecord(entry, entryName);
3546
+ const item = asRecord(entry2, entryName);
3547
3547
  exactKeys(item, ["regionIndex", "physicalPaletteIndex", "regionId", "materialId"], entryName);
3548
3548
  return {
3549
3549
  regionIndex: requireInteger(item.regionIndex, `${entryName}.regionIndex`, 0, PVOX_DEFAULT_LIMITS.maximumMaterialRegions - 1),
@@ -3552,7 +3552,7 @@ function createPvoxPhysicalRegionInventoryV1(input) {
3552
3552
  materialId: requireToken(item.materialId, `${entryName}.materialId`)
3553
3553
  };
3554
3554
  });
3555
- if (entries.some((entry, index) => entry.regionIndex !== index)) throw new Error(`${fieldName} regionIndex values must be contiguous and canonically ordered.`);
3555
+ if (entries.some((entry2, index) => entry2.regionIndex !== index)) throw new Error(`${fieldName} regionIndex values must be contiguous and canonically ordered.`);
3556
3556
  const pairs = entries.map(({ regionId, materialId }) => `${regionId}\0${materialId}`);
3557
3557
  if (new Set(pairs).size !== pairs.length) throw new Error(`${fieldName} region/material pairs must be unique.`);
3558
3558
  const inventoryHash = requireSha256(record2.inventoryHash, `${fieldName}.inventoryHash`);
@@ -3689,9 +3689,9 @@ function createPvoxEditJournalCurrentState(input, baseManifest) {
3689
3689
  const record2 = asRecord(input, fieldName);
3690
3690
  exactKeys(record2, ["baseContentHash", "basePageSetHash", "placementId", "gridVersion", "revision", "rootHash", "latestJournalHash", "pageHashes"], fieldName);
3691
3691
  const pageEntries = asDenseArray(record2.pageHashes, `${fieldName}.pageHashes`, baseManifest.pages.length, baseManifest.pages.length);
3692
- const pageHashes = pageEntries.map((entry, index) => {
3692
+ const pageHashes = pageEntries.map((entry2, index) => {
3693
3693
  const entryName = `${fieldName}.pageHashes[${index}]`;
3694
- const page = asRecord(entry, entryName);
3694
+ const page = asRecord(entry2, entryName);
3695
3695
  exactKeys(page, ["pageIndex", "sha256"], entryName);
3696
3696
  const pageIndex = requireInteger(page.pageIndex, `${entryName}.pageIndex`, 0, baseManifest.pages.length - 1);
3697
3697
  if (pageIndex !== index) throw new Error(`${fieldName}.pageHashes must be complete and ordered by pageIndex.`);
@@ -3742,9 +3742,9 @@ function createPvoxEditJournal(input, baseManifestInput, currentStateInput) {
3742
3742
  }
3743
3743
  }
3744
3744
  const patchEntries = asDenseArray(record2.patches, "PvoxEditJournal.patches", 1, PVOX_MAX_EDIT_PATCHES);
3745
- const patches = patchEntries.map((entry, index) => {
3745
+ const patches = patchEntries.map((entry2, index) => {
3746
3746
  const fieldName = `PvoxEditJournal.patches[${index}]`;
3747
- const patch = asRecord(entry, fieldName);
3747
+ const patch = asRecord(entry2, fieldName);
3748
3748
  exactKeys(patch, ["fieldKind", "lodLevel", "partitionIndex", "hierarchyDepth", "mortonCode", "expectedPageIndex", "expectedPageHash", "operation", "expectedBrickHash", "resultingBrickHash", "resultingPageHash"], fieldName);
3749
3749
  const mortonCode = requireString(patch.mortonCode, `${fieldName}.mortonCode`, 16);
3750
3750
  if (!MORTON_CODE.test(mortonCode)) throw new Error(`${fieldName}.mortonCode must be a canonical Morton code.`);
@@ -3821,7 +3821,7 @@ function createPvoxEditJournalChain(input, baseManifestInput) {
3821
3821
  const journals = [];
3822
3822
  const operationIds = /* @__PURE__ */ new Set();
3823
3823
  const currentPageHashes = new Map(baseManifest.pages.map(({ pageIndex, sha256: sha2562 }) => [pageIndex, sha2562]));
3824
- for (const entry of entries) {
3824
+ for (const entry2 of entries) {
3825
3825
  const previous = journals.at(-1);
3826
3826
  const currentState = previous === void 0 ? void 0 : {
3827
3827
  baseContentHash: previous.baseContentHash,
@@ -3833,7 +3833,7 @@ function createPvoxEditJournalChain(input, baseManifestInput) {
3833
3833
  latestJournalHash: previous.journalHash,
3834
3834
  pageHashes: baseManifest.pages.map(({ pageIndex }) => ({ pageIndex, sha256: currentPageHashes.get(pageIndex) }))
3835
3835
  };
3836
- const journal = createPvoxEditJournal(entry, baseManifest, currentState);
3836
+ const journal = createPvoxEditJournal(entry2, baseManifest, currentState);
3837
3837
  if (previous === void 0 && (journal.expectedRevision !== 0 || journal.previousJournalHash !== PVOX_EDIT_JOURNAL_GENESIS_HASH)) {
3838
3838
  throw new Error("PvoxEditJournalChain must begin at the canonical genesis revision.");
3839
3839
  }
@@ -3891,10 +3891,10 @@ function createTransform2(value, fieldName) {
3891
3891
  exactKeys(record2, ["translationMetres", "rotationQuaternion", "scale"], fieldName);
3892
3892
  const translationMetres = requireVector(record2.translationMetres, `${fieldName}.translationMetres`);
3893
3893
  const rotationEntries = asDenseArray(record2.rotationQuaternion, `${fieldName}.rotationQuaternion`, 4, 4);
3894
- const rotationQuaternion = rotationEntries.map((entry, index) => requireNumber(entry, `${fieldName}.rotationQuaternion[${index}]`, -1, 1));
3894
+ const rotationQuaternion = rotationEntries.map((entry2, index) => requireNumber(entry2, `${fieldName}.rotationQuaternion[${index}]`, -1, 1));
3895
3895
  if (Math.abs(Math.hypot(...rotationQuaternion) - 1) > 1e-4) throw new Error(`${fieldName}.rotationQuaternion must be normalized.`);
3896
3896
  const scale = requireVector(record2.scale, `${fieldName}.scale`);
3897
- if (scale.some((entry) => entry <= 0)) throw new Error(`${fieldName}.scale values must be positive.`);
3897
+ if (scale.some((entry2) => entry2 <= 0)) throw new Error(`${fieldName}.scale values must be positive.`);
3898
3898
  return { translationMetres, rotationQuaternion, scale };
3899
3899
  }
3900
3900
  function createAssemblyChild2(value, index, resolutionId, candidateId) {
@@ -4062,10 +4062,10 @@ function createModelProcessingManifestV2(input) {
4062
4062
  }
4063
4063
  const capabilityEntries = asDenseArray(record2.capabilities, "ModelProcessingManifestV2.capabilities", PVOX_CAPABILITIES.length, PVOX_CAPABILITIES.length);
4064
4064
  const capabilities = capabilityEntries.map(createVoxelCapabilityAssessment);
4065
- const byCapability = new Map(capabilities.map((entry) => [entry.capability, entry]));
4065
+ const byCapability = new Map(capabilities.map((entry2) => [entry2.capability, entry2]));
4066
4066
  if (byCapability.size !== PVOX_CAPABILITIES.length || PVOX_CAPABILITIES.some((name) => !byCapability.has(name))) throw new Error("ModelProcessingManifestV2 must include every PVOX capability exactly once.");
4067
4067
  const orderedCapabilities = PVOX_CAPABILITIES.map((name) => byCapability.get(name));
4068
- if (orderedCapabilities.some((entry) => entry.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 capability evidence must bind the binaryClosureHash.");
4068
+ if (orderedCapabilities.some((entry2) => entry2.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 capability evidence must bind the binaryClosureHash.");
4069
4069
  const capabilityEvidenceSetHash = requireSha256(record2.capabilityEvidenceSetHash, "ModelProcessingManifestV2.capabilityEvidenceSetHash");
4070
4070
  const capabilityEvidenceSetAttestation = createHashAttestation(
4071
4071
  record2.capabilityEvidenceSetAttestation,
@@ -4074,7 +4074,7 @@ function createModelProcessingManifestV2(input) {
4074
4074
  "ModelProcessingManifestV2.capabilityEvidenceSetAttestation"
4075
4075
  );
4076
4076
  const requiredCapabilityEntries = asDenseArray(record2.requiredCapabilities, "ModelProcessingManifestV2.requiredCapabilities", 1, PVOX_CAPABILITIES.length);
4077
- const requiredCapabilities = requiredCapabilityEntries.map((entry, index) => requireEnum(entry, PVOX_CAPABILITIES, `ModelProcessingManifestV2.requiredCapabilities[${index}]`));
4077
+ const requiredCapabilities = requiredCapabilityEntries.map((entry2, index) => requireEnum(entry2, PVOX_CAPABILITIES, `ModelProcessingManifestV2.requiredCapabilities[${index}]`));
4078
4078
  if (new Set(requiredCapabilities).size !== requiredCapabilities.length) throw new Error("ModelProcessingManifestV2.requiredCapabilities must be unique.");
4079
4079
  if (!requiredCapabilities.includes("rendering")) throw new Error("ModelProcessingManifestV2 rendering capability is always required.");
4080
4080
  if (technicalProfile.hasCollision !== (byCapability.get("collision")?.status === "supported")) throw new Error("ModelProcessingManifestV2 collision capability must match technicalProfile.hasCollision.");
@@ -4087,9 +4087,9 @@ function createModelProcessingManifestV2(input) {
4087
4087
  }
4088
4088
  const physicalEntries = asDenseArray(record2.physicalProperties, "ModelProcessingManifestV2.physicalProperties", 0, PVOX_DEFAULT_LIMITS.maximumPhysicalEvidenceEntries);
4089
4089
  const physicalProperties = physicalEntries.map(createPhysicalPropertyEvidence);
4090
- const byRegionProperty = new Map(physicalProperties.map((entry) => [`${entry.regionId}\0${entry.materialId}\0${entry.property}`, entry]));
4090
+ const byRegionProperty = new Map(physicalProperties.map((entry2) => [`${entry2.regionId}\0${entry2.materialId}\0${entry2.property}`, entry2]));
4091
4091
  if (byRegionProperty.size !== physicalProperties.length) throw new Error("ModelProcessingManifestV2 physical properties must be unique per region, material, and property.");
4092
- if (physicalProperties.some((entry) => entry.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 physical evidence must bind the PVOX binary closure subject.");
4092
+ if (physicalProperties.some((entry2) => entry2.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 physical evidence must bind the PVOX binary closure subject.");
4093
4093
  const authoritativePairs = physicalRegionInventory.entries.map(({ regionId, materialId }) => `${regionId}\0${materialId}`);
4094
4094
  const authoritativePairSet = new Set(authoritativePairs);
4095
4095
  if (physicalProperties.some(({ regionId, materialId }) => !authoritativePairSet.has(`${regionId}\0${materialId}`))) {
@@ -4171,7 +4171,7 @@ function createModelProcessingManifestV2(input) {
4171
4171
  throw new Error("ModelProcessingManifestV2 fidelity evidence must exactly match every governed PVOX LOD0 metric.");
4172
4172
  }
4173
4173
  const childEntries = asDenseArray(record2.children, "ModelProcessingManifestV2.children", 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren);
4174
- const children = childEntries.map((entry, index) => createAssemblyChild2(entry, index, resolutionId, candidateId));
4174
+ const children = childEntries.map((entry2, index) => createAssemblyChild2(entry2, index, resolutionId, candidateId));
4175
4175
  const kind = requireEnum(record2.kind, ["leaf", "assembly"], "ModelProcessingManifestV2.kind");
4176
4176
  if (kind === "leaf" && children.length !== 0) throw new Error("A leaf ModelProcessingManifestV2 cannot contain children.");
4177
4177
  if (kind === "leaf" && technicalProfile.partitionCount !== 1) throw new Error("A leaf ModelProcessingManifestV2 must have one partition.");
@@ -4254,9 +4254,9 @@ function createCandidateAssetRef2(value) {
4254
4254
  }
4255
4255
  function createViews(value, resolutionId, candidateId) {
4256
4256
  const entries = asDenseArray(value, "ModelCandidateV2.views", 4, 4);
4257
- const parsed = entries.map((entry, index) => {
4257
+ const parsed = entries.map((entry2, index) => {
4258
4258
  const fieldName = `ModelCandidateV2.views[${index}]`;
4259
- const record2 = asRecord(entry, fieldName);
4259
+ const record2 = asRecord(entry2, fieldName);
4260
4260
  exactKeys(record2, ["kind", "imageUri", "sha256", "contentType", "width", "height"], fieldName);
4261
4261
  const kind = requireEnum(record2.kind, MODEL_CONFIRMATION_VIEW_KINDS, `${fieldName}.kind`);
4262
4262
  const expectedUri = `mcp://models/resolutions/${resolutionId}/candidates/${candidateId}/${kind}.png`;
@@ -4264,7 +4264,7 @@ function createViews(value, resolutionId, candidateId) {
4264
4264
  if (record2.contentType !== "image/png" || record2.width !== MODEL_CONFIRMATION_VIEW_SIZE_PX || record2.height !== MODEL_CONFIRMATION_VIEW_SIZE_PX) throw new Error(`${fieldName} must be an authenticated 1024x1024 PNG.`);
4265
4265
  return { kind, imageUri: expectedUri, sha256: requireSha256(record2.sha256, `${fieldName}.sha256`), contentType: "image/png", width: MODEL_CONFIRMATION_VIEW_SIZE_PX, height: MODEL_CONFIRMATION_VIEW_SIZE_PX };
4266
4266
  });
4267
- if (parsed.some((entry, index) => entry.kind !== MODEL_CONFIRMATION_VIEW_KINDS[index])) throw new Error("ModelCandidateV2.views must be ordered front, left, top, isometric.");
4267
+ if (parsed.some((entry2, index) => entry2.kind !== MODEL_CONFIRMATION_VIEW_KINDS[index])) throw new Error("ModelCandidateV2.views must be ordered front, left, top, isometric.");
4268
4268
  return parsed;
4269
4269
  }
4270
4270
  function createRenderEvidence2(value) {
@@ -4463,7 +4463,7 @@ function createModelCandidateV2(input) {
4463
4463
  );
4464
4464
  const gateEntries = asDenseArray(record2.hardGates, "ModelCandidateV2.hardGates", PVOX_NON_OVERRIDABLE_GATE_KINDS.length, PVOX_NON_OVERRIDABLE_GATE_KINDS.length);
4465
4465
  const gates = gateEntries.map(createPvoxGateEvidence);
4466
- const byGate = new Map(gates.map((entry) => [entry.kind, entry]));
4466
+ const byGate = new Map(gates.map((entry2) => [entry2.kind, entry2]));
4467
4467
  if (byGate.size !== PVOX_NON_OVERRIDABLE_GATE_KINDS.length || PVOX_NON_OVERRIDABLE_GATE_KINDS.some((kind) => !byGate.has(kind))) throw new Error("ModelCandidateV2 must contain every non-overridable hard gate exactly once.");
4468
4468
  const orderedGates = PVOX_NON_OVERRIDABLE_GATE_KINDS.map((kind) => byGate.get(kind));
4469
4469
  const concreteGateHashes = {
@@ -4486,7 +4486,7 @@ function createModelCandidateV2(input) {
4486
4486
  ...!match.hardConstraintPass ? ["semantic-hard-constraints-failed"] : [],
4487
4487
  ...!["allowed", "attribution-required"].includes(rights.status) ? [`rights:${rights.status}`] : [],
4488
4488
  ...processingManifest.requiredCapabilities.flatMap((capability) => {
4489
- const evidence = processingManifest.capabilities.find((entry) => entry.capability === capability);
4489
+ const evidence = processingManifest.capabilities.find((entry2) => entry2.capability === capability);
4490
4490
  return evidence.status === "supported" ? [] : [`capability:${capability}:${evidence.status}`];
4491
4491
  }),
4492
4492
  ...orderedGates.flatMap((gate) => gate.outcome === "passed" ? [] : gate.reasonCodes.map((reason) => `${gate.kind}:${reason}`))
@@ -4514,7 +4514,7 @@ function createModelCandidateV2(input) {
4514
4514
  if (record2.confirmationRequired !== false) throw new Error("Diagnostic ModelCandidateV2 confirmationRequired must be false.");
4515
4515
  if (record2.blockingReasonCodes !== void 0) {
4516
4516
  const suppliedEntries = asDenseArray(record2.blockingReasonCodes, "ModelCandidateV2.blockingReasonCodes", 1, 256);
4517
- const suppliedBlockingReasons = suppliedEntries.map((entry, index) => requireReasonCode(entry, `ModelCandidateV2.blockingReasonCodes[${index}]`));
4517
+ const suppliedBlockingReasons = suppliedEntries.map((entry2, index) => requireReasonCode(entry2, `ModelCandidateV2.blockingReasonCodes[${index}]`));
4518
4518
  if (JSON.stringify(suppliedBlockingReasons) !== JSON.stringify(blockingReasonCodes)) throw new Error("Diagnostic ModelCandidateV2 blockingReasonCodes must be derived from its evidence.");
4519
4519
  }
4520
4520
  return deepFreeze2({ ...common, admissionStatus: "diagnostic", blockingReasonCodes, confirmationRequired: false });
@@ -4568,7 +4568,7 @@ function createModelCandidateV2(input) {
4568
4568
  });
4569
4569
  }
4570
4570
  function isModelCandidateV2Confirmable(candidate) {
4571
- return candidate.admissionStatus === "confirmable" && candidate.confirmationRequired && candidate.match.hardConstraintPass && candidate.match.assurance !== "none" && (candidate.rights.status === "allowed" || candidate.rights.status === "attribution-required") && candidate.processingManifest.fidelity.outcome === "passed" && candidate.hardGates.length === PVOX_NON_OVERRIDABLE_GATE_KINDS.length && candidate.hardGates.every(({ outcome }) => outcome === "passed") && candidate.processingManifest.requiredCapabilities.every((name) => candidate.processingManifest.capabilities.find((entry) => entry.capability === name)?.status === "supported");
4571
+ return candidate.admissionStatus === "confirmable" && candidate.confirmationRequired && candidate.match.hardConstraintPass && candidate.match.assurance !== "none" && (candidate.rights.status === "allowed" || candidate.rights.status === "attribution-required") && candidate.processingManifest.fidelity.outcome === "passed" && candidate.hardGates.length === PVOX_NON_OVERRIDABLE_GATE_KINDS.length && candidate.hardGates.every(({ outcome }) => outcome === "passed") && candidate.processingManifest.requiredCapabilities.every((name) => candidate.processingManifest.capabilities.find((entry2) => entry2.capability === name)?.status === "supported");
4572
4572
  }
4573
4573
  function createModelCandidateConfirmationV2(input, expectedCandidate, expectedResolutionId) {
4574
4574
  const record2 = asRecord(input, "ModelCandidateConfirmationV2");
@@ -4665,7 +4665,7 @@ function createModelPromotionReceiptV2(input, resolutionId, candidate, confirmat
4665
4665
  const candidateAssetRef = createCandidateAssetRef2(record2.candidateAssetRef);
4666
4666
  if (JSON.stringify(candidateAssetRef) !== JSON.stringify(candidate.assetRef)) throw new Error("ModelPromotionReceiptV2 must bind the exact proposed candidate identity.");
4667
4667
  const childClosureEntries = asDenseArray(record2.assemblyChildClosureHashes, "ModelPromotionReceiptV2.assemblyChildClosureHashes", 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren);
4668
- const assemblyChildClosureHashes = childClosureEntries.map((entry, index) => requireSha256(entry, `ModelPromotionReceiptV2.assemblyChildClosureHashes[${index}]`));
4668
+ const assemblyChildClosureHashes = childClosureEntries.map((entry2, index) => requireSha256(entry2, `ModelPromotionReceiptV2.assemblyChildClosureHashes[${index}]`));
4669
4669
  const expectedChildClosureHashes = candidate.processingManifest.children.map(({ assetRef }) => assetRef.binaryClosureHash);
4670
4670
  if (JSON.stringify(assemblyChildClosureHashes) !== JSON.stringify(expectedChildClosureHashes)) throw new Error("ModelPromotionReceiptV2 child closure sequence must match the canonical assembly order.");
4671
4671
  assertDataOnlyTree(record2.finalAssetRef, "ModelPromotionReceiptV2.finalAssetRef");
@@ -4926,12 +4926,12 @@ function copyPvoxByteInput(value, fieldName, maximumByteLength) {
4926
4926
  if (!(value instanceof Uint8Array)) throw new Error(`${fieldName} must be a Uint8Array.`);
4927
4927
  let byteLength;
4928
4928
  try {
4929
- const typedArrayPrototype2 = Object.getPrototypeOf(Uint8Array.prototype);
4930
- const byteLengthGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteLength")?.get;
4931
- const bufferGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "buffer")?.get;
4932
- if (byteLengthGetter2 === void 0 || bufferGetter2 === void 0) throw new Error("Typed-array intrinsics are unavailable.");
4933
- byteLength = byteLengthGetter2.call(value);
4934
- const buffer = bufferGetter2.call(value);
4929
+ const typedArrayPrototype3 = Object.getPrototypeOf(Uint8Array.prototype);
4930
+ const byteLengthGetter3 = Object.getOwnPropertyDescriptor(typedArrayPrototype3, "byteLength")?.get;
4931
+ const bufferGetter3 = Object.getOwnPropertyDescriptor(typedArrayPrototype3, "buffer")?.get;
4932
+ if (byteLengthGetter3 === void 0 || bufferGetter3 === void 0) throw new Error("Typed-array intrinsics are unavailable.");
4933
+ byteLength = byteLengthGetter3.call(value);
4934
+ const buffer = bufferGetter3.call(value);
4935
4935
  if (typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer) {
4936
4936
  throw new Error(`${fieldName} must not use shared mutable storage.`);
4937
4937
  }
@@ -6701,9 +6701,9 @@ function snapshot(value, budget, depth = 0) {
6701
6701
  return value;
6702
6702
  }
6703
6703
  if (Array.isArray(value)) return Object.freeze(list(value).map((item) => snapshot(item, budget, depth + 1)));
6704
- const fields2 = record(value);
6705
- for (const key of Object.keys(fields2)) fields2[key] = snapshot(fields2[key], budget, depth + 1);
6706
- return Object.freeze(fields2);
6704
+ const fields4 = record(value);
6705
+ for (const key of Object.keys(fields4)) fields4[key] = snapshot(fields4[key], budget, depth + 1);
6706
+ return Object.freeze(fields4);
6707
6707
  }
6708
6708
  function path(value) {
6709
6709
  if (typeof value !== "string" || value.length > 1024 || !value.length) fail();
@@ -6775,14 +6775,14 @@ async function qualify(input) {
6775
6775
  contentType(file.contentType);
6776
6776
  }
6777
6777
  const entries = list(inventory.entries).map(record);
6778
- uniquePaths(entries.map((entry) => path(entry.path)));
6778
+ uniquePaths(entries.map((entry2) => path(entry2.path)));
6779
6779
  const ids = /* @__PURE__ */ new Set();
6780
- for (const entry of entries) {
6781
- if (Object.keys(entry).some((key) => !["id", "path", "role", "contentType"].includes(key)) || typeof entry.id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(entry.id) || ids.has(entry.id) || !["mesh", "material", "texture", "animation", "auxiliary"].includes(entry.role)) fail();
6782
- ids.add(entry.id);
6783
- const descriptor = descriptors.get(entry.path);
6780
+ for (const entry2 of entries) {
6781
+ if (Object.keys(entry2).some((key) => !["id", "path", "role", "contentType"].includes(key)) || typeof entry2.id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(entry2.id) || ids.has(entry2.id) || !["mesh", "material", "texture", "animation", "auxiliary"].includes(entry2.role)) fail();
6782
+ ids.add(entry2.id);
6783
+ const descriptor = descriptors.get(entry2.path);
6784
6784
  if (!descriptor) fail("inventory-mismatch");
6785
- if (entry.contentType !== void 0 && contentType(entry.contentType) !== descriptor.contentType) fail("content-mismatch");
6785
+ if (entry2.contentType !== void 0 && contentType(entry2.contentType) !== descriptor.contentType) fail("content-mismatch");
6786
6786
  }
6787
6787
  if (entries.length !== descriptors.size) fail("inventory-mismatch");
6788
6788
  const payloads = list(root.files).map((value) => {
@@ -6812,6 +6812,179 @@ async function qualify(input) {
6812
6812
  return Object.freeze({ ...manifest, files: Object.freeze([...manifest.files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)) });
6813
6813
  }
6814
6814
 
6815
+ // src/model-texture-resources.ts
6816
+ import { isGpuModelResourceGraph } from "@plasius/gpu-model-core";
6817
+ var MODEL_TEXTURE_RESOURCE_LIMITS = Object.freeze({ resources: 16384, derived: 4096, nodes: 65536, values: 262144, characters: 2097152, depth: 16, timeoutMs: 6e4 });
6818
+ var ModelTextureResourceError = class extends TypeError {
6819
+ constructor(code) {
6820
+ super(`Invalid model texture resources: ${code}`);
6821
+ this.code = code;
6822
+ this.name = "ModelTextureResourceError";
6823
+ }
6824
+ code;
6825
+ };
6826
+ function fail2(code = "invalid-input") {
6827
+ throw new ModelTextureResourceError(code);
6828
+ }
6829
+ function fields(value, allowed) {
6830
+ if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail2();
6831
+ const keys = Reflect.ownKeys(value);
6832
+ if (keys.length > 1024) fail2("limit-exceeded");
6833
+ const result = /* @__PURE__ */ Object.create(null);
6834
+ for (const key of keys) {
6835
+ if (typeof key !== "string" || key.length > 128 || ["__proto__", "prototype", "constructor"].includes(key) || allowed && !allowed.includes(key)) fail2();
6836
+ const property = Object.getOwnPropertyDescriptor(value, key);
6837
+ if (!("value" in property) || !property.enumerable) fail2();
6838
+ result[key] = property.value;
6839
+ }
6840
+ return result;
6841
+ }
6842
+ function array(value, maximum) {
6843
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) fail2();
6844
+ if (value.length > maximum) fail2("limit-exceeded");
6845
+ if (Reflect.ownKeys(value).length !== value.length + 1) fail2();
6846
+ const result = [];
6847
+ for (let i = 0; i < value.length; i++) {
6848
+ const property = Object.getOwnPropertyDescriptor(value, String(i));
6849
+ if (!property || !("value" in property) || !property.enumerable) fail2();
6850
+ result.push(property.value);
6851
+ }
6852
+ return result;
6853
+ }
6854
+ function snapshot2(value, budget, depth = 0) {
6855
+ if (--budget.values < 0 || depth > MODEL_TEXTURE_RESOURCE_LIMITS.depth) fail2("limit-exceeded");
6856
+ if (value === null || value === void 0 || typeof value === "boolean") return value;
6857
+ if (typeof value === "number" && Number.isFinite(value)) return value;
6858
+ if (typeof value === "string") {
6859
+ budget.characters -= value.length;
6860
+ if (value.length > 2048 || budget.characters < 0) fail2("limit-exceeded");
6861
+ return value;
6862
+ }
6863
+ if (Array.isArray(value)) return Object.freeze(array(value, MODEL_TEXTURE_RESOURCE_LIMITS.resources).map((v) => snapshot2(v, budget, depth + 1)));
6864
+ const result = fields(value);
6865
+ for (const key of Object.keys(result)) {
6866
+ budget.characters -= key.length;
6867
+ if (budget.characters < 0) fail2("limit-exceeded");
6868
+ result[key] = snapshot2(result[key], budget, depth + 1);
6869
+ }
6870
+ return Object.freeze(result);
6871
+ }
6872
+ function token2(value) {
6873
+ if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value)) fail2();
6874
+ return value;
6875
+ }
6876
+ var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
6877
+ var imageMime = (value) => ["image/png", "image/jpeg", "image/webp", "image/ktx2"].includes(value);
6878
+ var bufferMime = (value) => ["application/octet-stream", "application/vnd.plasius.gpu-buffer"].includes(value);
6879
+ function storageRole(role, file) {
6880
+ const valid = role === "texture" ? file.role === "texture" && imageMime(file.contentType) : role === "material" || role === "animation" ? file.role === "metadata" && file.contentType === "application/json" : role === "mesh" ? file.role === "binary" && bufferMime(file.contentType) || file.role === "model" && (file.contentType.startsWith("model/") || ["application/json", "application/octet-stream", "text/plain"].includes(file.contentType)) : role === "auxiliary" && (file.role === "binary" && bufferMime(file.contentType) || file.role === "metadata" && file.contentType === "application/json");
6881
+ if (!valid) fail2("role-mismatch");
6882
+ }
6883
+ async function qualifyModelTextureResources(input, options = {}) {
6884
+ let timer;
6885
+ let signal;
6886
+ let onAbort;
6887
+ try {
6888
+ const started = performance.now();
6889
+ const controls = fields(options, ["signal", "timeoutMs"]);
6890
+ const timeoutMs = controls.timeoutMs === void 0 ? 1e4 : controls.timeoutMs;
6891
+ if (typeof timeoutMs !== "number" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MODEL_TEXTURE_RESOURCE_LIMITS.timeoutMs) fail2();
6892
+ signal = controls.signal;
6893
+ const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted").get;
6894
+ const check = () => {
6895
+ if (signal !== void 0 && aborted.call(signal)) fail2("aborted");
6896
+ if (performance.now() - started >= timeoutMs) fail2("deadline-exceeded");
6897
+ };
6898
+ check();
6899
+ const root = fields(input, ["manifest", "packageManifest", "files", "graph", "resources", "derived"]);
6900
+ const graph = root.graph;
6901
+ if (!isGpuModelResourceGraph(graph)) fail2("unverified-graph");
6902
+ if (graph.nodes.length > MODEL_TEXTURE_RESOURCE_LIMITS.nodes) fail2("limit-exceeded");
6903
+ const budget = { values: MODEL_TEXTURE_RESOURCE_LIMITS.values, characters: MODEL_TEXTURE_RESOURCE_LIMITS.characters };
6904
+ const inventory = snapshot2(root.packageManifest, budget);
6905
+ const bindings = array(snapshot2(root.resources, budget), MODEL_TEXTURE_RESOURCE_LIMITS.resources).map((value) => {
6906
+ const binding = fields(value, ["resourceId", "filePath"]);
6907
+ return Object.freeze({ resourceId: token2(binding.resourceId), filePath: tokenPath(binding.filePath) });
6908
+ });
6909
+ const derived = array(snapshot2(root.derived, budget), MODEL_TEXTURE_RESOURCE_LIMITS.derived).map((value) => {
6910
+ const record2 = fields(value, ["role", "filePath", "sourceResourceIds"]);
6911
+ if (record2.role !== "gpu-upload" && record2.role !== "texture-atlas") fail2("role-mismatch");
6912
+ const ids = array(record2.sourceResourceIds, MODEL_TEXTURE_RESOURCE_LIMITS.resources).map(token2);
6913
+ if (!ids.length || new Set(ids).size !== ids.length) fail2("resource-mismatch");
6914
+ return Object.freeze({ role: record2.role, filePath: tokenPath(record2.filePath), sourceResourceIds: Object.freeze(ids.sort(compare)) });
6915
+ });
6916
+ check();
6917
+ const interrupted = new Promise((_resolve, reject) => {
6918
+ timer = setTimeout(() => reject(new ModelTextureResourceError("deadline-exceeded")), Math.max(1, timeoutMs - (performance.now() - started)));
6919
+ onAbort = () => reject(new ModelTextureResourceError("aborted"));
6920
+ if (signal) AbortSignal.prototype.addEventListener.call(signal, "abort", onAbort, { once: true });
6921
+ });
6922
+ const manifest = await Promise.race([
6923
+ qualifyModelResourceManifest({ manifest: root.manifest, files: root.files, packageManifest: inventory, signal, timeoutMs }),
6924
+ interrupted
6925
+ ]);
6926
+ check();
6927
+ const files = new Map(manifest.files.map((file) => [file.path, file]));
6928
+ const roles = new Map(inventory.entries.map((entry2) => [entry2.path, entry2.role]));
6929
+ for (const entry2 of inventory.entries) storageRole(entry2.role, files.get(entry2.path));
6930
+ const resources = new Map(graph.nodes.filter((node) => node.kind === "resource").map((node) => [node.id, node.value]));
6931
+ if (bindings.length !== resources.size || new Set(bindings.map((b) => b.resourceId)).size !== bindings.length) fail2("resource-mismatch");
6932
+ const resourceFiles = /* @__PURE__ */ new Set();
6933
+ const qualified2 = bindings.map((binding) => {
6934
+ const value = resources.get(binding.resourceId);
6935
+ const file = files.get(binding.filePath);
6936
+ if (!value || !file) fail2("resource-mismatch");
6937
+ const { resource, location, exportEmbeddingPolicy } = value;
6938
+ if (location.kind === "external") {
6939
+ if (binding.filePath !== location.relativePath || file.sha256 !== resource.contentHash || file.byteLength !== resource.byteLength || file.contentType !== resource.mimeType) fail2("resource-mismatch");
6940
+ if (resource.kind === "image" ? roles.get(file.path) !== "texture" : file.role !== "binary") fail2("role-mismatch");
6941
+ } else if (binding.filePath !== manifest.entrypoint || file.role !== "model") fail2("resource-mismatch");
6942
+ resourceFiles.add(binding.filePath);
6943
+ return Object.freeze({ ...binding, kind: resource.kind, contentHash: resource.contentHash, byteLength: resource.byteLength, mimeType: resource.mimeType, location, exportEmbeddingPolicy });
6944
+ });
6945
+ const outputFiles = /* @__PURE__ */ new Set();
6946
+ for (const output of derived) {
6947
+ const file = files.get(output.filePath);
6948
+ if (!file || outputFiles.has(output.filePath) || resourceFiles.has(output.filePath)) fail2("resource-mismatch");
6949
+ outputFiles.add(output.filePath);
6950
+ for (const id of output.sourceResourceIds) {
6951
+ const source2 = resources.get(id);
6952
+ if (!source2 || output.role === "texture-atlas" && source2.resource.kind !== "image") fail2("resource-mismatch");
6953
+ }
6954
+ if (output.role === "gpu-upload" ? file.role !== "binary" || !bufferMime(file.contentType) || roles.get(file.path) !== "auxiliary" : file.role !== "texture" || !imageMime(file.contentType) || roles.get(file.path) !== "texture") fail2("role-mismatch");
6955
+ }
6956
+ const materials = graph.nodes.filter((node) => node.kind === "material").map((node) => node.value);
6957
+ const textures = graph.nodes.filter((node) => node.kind === "texture").map((node) => node.value);
6958
+ const source = graph.nodes.find((node) => node.kind === "provenance");
6959
+ if (source.kind !== "provenance") fail2();
6960
+ snapshot2({ materials, textures, source: source.value }, budget);
6961
+ check();
6962
+ return Object.freeze({
6963
+ contractVersion: 1,
6964
+ manifest,
6965
+ source: source.value,
6966
+ resources: Object.freeze(qualified2.sort((a, b) => compare(a.resourceId, b.resourceId))),
6967
+ materials: Object.freeze(materials),
6968
+ textures: Object.freeze(textures),
6969
+ derived: Object.freeze(derived.sort((a, b) => compare(a.filePath, b.filePath)))
6970
+ });
6971
+ } catch (error) {
6972
+ if (error instanceof ModelTextureResourceError) throw error;
6973
+ if (error instanceof ModelResourceManifestError) return fail2(error.code === "aborted" || error.code === "deadline-exceeded" || error.code === "limit-exceeded" ? error.code : "package-mismatch");
6974
+ return fail2();
6975
+ } finally {
6976
+ if (timer !== void 0) clearTimeout(timer);
6977
+ if (signal && onAbort) AbortSignal.prototype.removeEventListener.call(signal, "abort", onAbort);
6978
+ }
6979
+ }
6980
+ function tokenPath(value) {
6981
+ if (typeof value !== "string" || !value.length || value.length > 1024) fail2();
6982
+ return value;
6983
+ }
6984
+
6985
+ // src/model-resource-promotion.ts
6986
+ import { canonicalizeGpuContract as canonicalizeGpuContract3, computeSha256 as computeSha2562 } from "@plasius/gpu-shader";
6987
+
6815
6988
  // src/model-conversion-diagnostics.ts
6816
6989
  var MODEL_CONVERSION_DIAGNOSTIC_LIMITS = Object.freeze({ issues: 100, resources: 100, values: 16384, depth: 12, string: 2048, characters: 262144, timeoutMs: 6e4 });
6817
6990
  var ModelConversionDiagnosticsError = class extends TypeError {
@@ -6822,50 +6995,50 @@ var ModelConversionDiagnosticsError = class extends TypeError {
6822
6995
  }
6823
6996
  code;
6824
6997
  };
6825
- function fail2(code = "invalid-input") {
6998
+ function fail3(code = "invalid-input") {
6826
6999
  throw new ModelConversionDiagnosticsError(code);
6827
7000
  }
6828
- function fields(value) {
6829
- if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail2();
7001
+ function fields2(value) {
7002
+ if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail3();
6830
7003
  const result = /* @__PURE__ */ Object.create(null);
6831
7004
  const keys = Reflect.ownKeys(value);
6832
- if (keys.length > 1024) fail2("limit-exceeded");
7005
+ if (keys.length > 1024) fail3("limit-exceeded");
6833
7006
  for (const key of keys) {
6834
- if (typeof key !== "string" || key.length > 128 || ["__proto__", "prototype", "constructor"].includes(key)) fail2();
7007
+ if (typeof key !== "string" || key.length > 128 || ["__proto__", "prototype", "constructor"].includes(key)) fail3();
6835
7008
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
6836
- if (!("value" in descriptor) || !descriptor.enumerable) fail2();
7009
+ if (!("value" in descriptor) || !descriptor.enumerable) fail3();
6837
7010
  result[key] = descriptor.value;
6838
7011
  }
6839
7012
  return result;
6840
7013
  }
6841
7014
  function only(record2, keys) {
6842
- if (Object.keys(record2).some((key) => !keys.includes(key))) fail2();
7015
+ if (Object.keys(record2).some((key) => !keys.includes(key))) fail3();
6843
7016
  }
6844
- function snapshot2(value, budget, depth = 0) {
6845
- if (--budget.values < 0 || depth > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.depth) fail2("limit-exceeded");
7017
+ function snapshot3(value, budget, depth = 0) {
7018
+ if (--budget.values < 0 || depth > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.depth) fail3("limit-exceeded");
6846
7019
  if (value === null || typeof value === "boolean") return value;
6847
7020
  if (typeof value === "string") {
6848
7021
  budget.characters -= value.length;
6849
- if (value.length > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.string || budget.characters < 0) fail2("limit-exceeded");
7022
+ if (value.length > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.string || budget.characters < 0) fail3("limit-exceeded");
6850
7023
  return value;
6851
7024
  }
6852
7025
  if (typeof value === "number" && Number.isFinite(value)) return value;
6853
7026
  if (Array.isArray(value)) {
6854
- if (Object.getPrototypeOf(value) !== Array.prototype || value.length > 1024) fail2("limit-exceeded");
6855
- if (Reflect.ownKeys(value).length !== value.length + 1) fail2();
7027
+ if (Object.getPrototypeOf(value) !== Array.prototype || value.length > 1024) fail3("limit-exceeded");
7028
+ if (Reflect.ownKeys(value).length !== value.length + 1) fail3();
6856
7029
  const result = [];
6857
7030
  for (let i = 0; i < value.length; i++) {
6858
7031
  const descriptor = Object.getOwnPropertyDescriptor(value, String(i));
6859
- if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) fail2();
6860
- result.push(snapshot2(descriptor.value, budget, depth + 1));
7032
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) fail3();
7033
+ result.push(snapshot3(descriptor.value, budget, depth + 1));
6861
7034
  }
6862
7035
  return Object.freeze(result);
6863
7036
  }
6864
- const record2 = fields(value);
7037
+ const record2 = fields2(value);
6865
7038
  for (const key of Object.keys(record2)) {
6866
7039
  budget.characters -= key.length;
6867
- if (budget.characters < 0) fail2("limit-exceeded");
6868
- record2[key] = snapshot2(record2[key], budget, depth + 1);
7040
+ if (budget.characters < 0) fail3("limit-exceeded");
7041
+ record2[key] = snapshot3(record2[key], budget, depth + 1);
6869
7042
  }
6870
7043
  return Object.freeze(record2);
6871
7044
  }
@@ -6878,35 +7051,35 @@ async function qualifyModelConversionDiagnostics(input, options = {}) {
6878
7051
  let onAbort;
6879
7052
  try {
6880
7053
  const start = performance.now();
6881
- const controls = fields(options);
7054
+ const controls = fields2(options);
6882
7055
  only(controls, ["signal", "timeoutMs"]);
6883
7056
  const timeoutMs = controls.timeoutMs === void 0 ? 1e4 : controls.timeoutMs;
6884
- if (typeof timeoutMs !== "number" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.timeoutMs) fail2();
7057
+ if (typeof timeoutMs !== "number" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.timeoutMs) fail3();
6885
7058
  signal = controls.signal;
6886
7059
  const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted").get;
6887
7060
  const check = () => {
6888
- if (signal !== void 0 && aborted.call(signal)) fail2("aborted");
6889
- if (performance.now() - start >= timeoutMs) fail2("deadline-exceeded");
7061
+ if (signal !== void 0 && aborted.call(signal)) fail3("aborted");
7062
+ if (performance.now() - start >= timeoutMs) fail3("deadline-exceeded");
6890
7063
  };
6891
7064
  check();
6892
- const args = fields(snapshot2(input, { values: MODEL_CONVERSION_DIAGNOSTIC_LIMITS.values, characters: MODEL_CONVERSION_DIAGNOSTIC_LIMITS.characters }));
7065
+ const args = fields2(snapshot3(input, { values: MODEL_CONVERSION_DIAGNOSTIC_LIMITS.values, characters: MODEL_CONVERSION_DIAGNOSTIC_LIMITS.characters }));
6893
7066
  only(args, ["outcome", "source", "report", "resources"]);
6894
- if (!["completed", "unsupported", "failed"].includes(args.outcome)) fail2();
7067
+ if (!["completed", "unsupported", "failed"].includes(args.outcome)) fail3();
6895
7068
  const source = createModelProvenance(args.source);
6896
- const reportInput = fields(args.report);
7069
+ const reportInput = fields2(args.report);
6897
7070
  const maximumIssues = MODEL_CONVERSION_DIAGNOSTIC_LIMITS.issues - (args.outcome === "completed" ? 0 : 1);
6898
- if (!Array.isArray(reportInput.issues) || reportInput.issues.length > maximumIssues) fail2("limit-exceeded");
6899
- if (!Array.isArray(args.resources) || args.resources.length > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.resources) fail2("limit-exceeded");
7071
+ if (!Array.isArray(reportInput.issues) || reportInput.issues.length > maximumIssues) fail3("limit-exceeded");
7072
+ if (!Array.isArray(args.resources) || args.resources.length > MODEL_CONVERSION_DIAGNOSTIC_LIMITS.resources) fail3("limit-exceeded");
6900
7073
  const resources = /* @__PURE__ */ new Map();
6901
7074
  const identities = /* @__PURE__ */ new Map();
6902
7075
  for (const value of args.resources) {
6903
- const binding = fields(value);
7076
+ const binding = fields2(value);
6904
7077
  only(binding, ["path", "resource"]);
6905
- if (typeof binding.path !== "string" || !binding.path.startsWith("/") || binding.path === "/" || resources.has(binding.path)) fail2();
7078
+ if (typeof binding.path !== "string" || !binding.path.startsWith("/") || binding.path === "/" || resources.has(binding.path)) fail3();
6906
7079
  const resource = createModelResourceRef(binding.resource);
6907
- const identity = JSON.stringify(resource);
6908
- if (identities.has(resource.uri) && identities.get(resource.uri) !== identity) fail2();
6909
- identities.set(resource.uri, identity);
7080
+ const identity2 = JSON.stringify(resource);
7081
+ if (identities.has(resource.uri) && identities.get(resource.uri) !== identity2) fail3();
7082
+ identities.set(resource.uri, identity2);
6910
7083
  resources.set(binding.path, resource);
6911
7084
  }
6912
7085
  check();
@@ -6920,7 +7093,7 @@ async function qualifyModelConversionDiagnostics(input, options = {}) {
6920
7093
  const report = core.evaluateGpuModelDiagnostics(reportInput);
6921
7094
  const diagnostics = report.diagnostics.map((diagnostic) => {
6922
7095
  const resource = resources.get(diagnostic.path);
6923
- if (diagnostic.path !== "/" && !resource) fail2("unbound-resource");
7096
+ if (diagnostic.path !== "/" && !resource) fail3("unbound-resource");
6924
7097
  const base = resource ? { resource } : {};
6925
7098
  switch (diagnostic.kind) {
6926
7099
  case "warning":
@@ -6952,7 +7125,194 @@ async function qualifyModelConversionDiagnostics(input, options = {}) {
6952
7125
  });
6953
7126
  } catch (error) {
6954
7127
  if (error instanceof ModelConversionDiagnosticsError) throw error;
6955
- return fail2();
7128
+ return fail3();
7129
+ } finally {
7130
+ if (timer !== void 0) clearTimeout(timer);
7131
+ if (signal && onAbort) AbortSignal.prototype.removeEventListener.call(signal, "abort", onAbort);
7132
+ }
7133
+ }
7134
+
7135
+ // src/model-resource-promotion.ts
7136
+ var MODEL_RESOURCE_PROMOTION_LIMITS = Object.freeze({ bindings: 1024, values: 262144, characters: 2097152, depth: 24, timeoutMs: 6e4 });
7137
+ var ModelResourcePromotionError = class extends TypeError {
7138
+ constructor(code) {
7139
+ super(`Invalid model resource promotion: ${code}`);
7140
+ this.code = code;
7141
+ this.name = "ModelResourcePromotionError";
7142
+ }
7143
+ code;
7144
+ };
7145
+ var qualified = /* @__PURE__ */ new WeakSet();
7146
+ function fail4(code = "invalid-input") {
7147
+ throw new ModelResourcePromotionError(code);
7148
+ }
7149
+ function fields3(value, allowed) {
7150
+ if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail4();
7151
+ const keys = Reflect.ownKeys(value);
7152
+ if (keys.length > 1024) fail4("limit-exceeded");
7153
+ const result = /* @__PURE__ */ Object.create(null);
7154
+ for (const key of keys) {
7155
+ if (typeof key !== "string" || key.length > 128 || ["__proto__", "constructor", "prototype"].includes(key) || allowed && !allowed.includes(key)) fail4();
7156
+ const property = Object.getOwnPropertyDescriptor(value, key);
7157
+ if (!("value" in property) || !property.enumerable) fail4();
7158
+ result[key] = property.value;
7159
+ }
7160
+ return result;
7161
+ }
7162
+ function array2(value, maximum) {
7163
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) fail4();
7164
+ if (value.length > maximum) fail4("limit-exceeded");
7165
+ if (Reflect.ownKeys(value).length !== value.length + 1) fail4();
7166
+ return Array.from({ length: value.length }, (_, i) => {
7167
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(i));
7168
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) fail4();
7169
+ return descriptor.value;
7170
+ });
7171
+ }
7172
+ function snapshot4(value, budget, depth = 0) {
7173
+ if (--budget.values < 0 || depth > MODEL_RESOURCE_PROMOTION_LIMITS.depth) fail4("limit-exceeded");
7174
+ if (value === null || value === void 0 || typeof value === "boolean") return value;
7175
+ if (typeof value === "number" && Number.isFinite(value)) return value;
7176
+ if (typeof value === "string") {
7177
+ budget.characters -= value.length;
7178
+ if (value.length > 2048 || budget.characters < 0) fail4("limit-exceeded");
7179
+ return value;
7180
+ }
7181
+ if (Array.isArray(value)) return Object.freeze(array2(value, MODEL_RESOURCE_MANIFEST_LIMITS.files).map((v) => snapshot4(v, budget, depth + 1)));
7182
+ const result = fields3(value);
7183
+ for (const key of Object.keys(result)) {
7184
+ budget.characters -= key.length;
7185
+ if (budget.characters < 0) fail4("limit-exceeded");
7186
+ result[key] = snapshot4(result[key], budget, depth + 1);
7187
+ }
7188
+ return Object.freeze(result);
7189
+ }
7190
+ var typedArrayPrototype2 = Object.getPrototypeOf(Uint8Array.prototype);
7191
+ var byteLengthGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteLength").get;
7192
+ var bufferGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "buffer").get;
7193
+ function copyFiles(value) {
7194
+ let total = 0;
7195
+ const files = array2(value, MODEL_RESOURCE_MANIFEST_LIMITS.files).map((v) => {
7196
+ const file = fields3(v, ["path", "bytes", "contentType"]);
7197
+ const bytes = file.bytes;
7198
+ if (typeof file.path !== "string" || typeof file.contentType !== "string" || !(bytes instanceof Uint8Array) || Object.getPrototypeOf(bytes) !== Uint8Array.prototype || !(bufferGetter2.call(bytes) instanceof ArrayBuffer)) fail4();
7199
+ const length = byteLengthGetter2.call(bytes);
7200
+ total += length;
7201
+ if (length > MODEL_RESOURCE_MANIFEST_LIMITS.fileBytes || total > MODEL_RESOURCE_MANIFEST_LIMITS.totalBytes) fail4("limit-exceeded");
7202
+ return { path: file.path, bytes, contentType: file.contentType };
7203
+ });
7204
+ return files.map((f) => ({ ...f, bytes: new Uint8Array(f.bytes) }));
7205
+ }
7206
+ var same = (a, b) => canonicalizeGpuContract3(a) === canonicalizeGpuContract3(b);
7207
+ var entry = (m) => m.files.find((f) => f.path === m.entrypoint);
7208
+ var identity = (m) => `${m.assetId}/${m.version}`;
7209
+ async function createModelResourcePromotionRecord(input, options = {}) {
7210
+ let timer;
7211
+ let signal;
7212
+ let onAbort;
7213
+ try {
7214
+ const started = performance.now();
7215
+ const controls = fields3(options, ["signal", "timeoutMs"]);
7216
+ const timeoutMs = controls.timeoutMs === void 0 ? 1e4 : controls.timeoutMs;
7217
+ if (typeof timeoutMs !== "number" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MODEL_RESOURCE_PROMOTION_LIMITS.timeoutMs) fail4();
7218
+ signal = controls.signal;
7219
+ const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted").get;
7220
+ const check = () => {
7221
+ if (signal !== void 0 && aborted.call(signal)) fail4("aborted");
7222
+ if (performance.now() - started >= timeoutMs) fail4("deadline-exceeded");
7223
+ };
7224
+ check();
7225
+ const root = fields3(input, ["promotion", "source", "output", "diagnostics", "resourceBindings", "candidate", "confirmation", "rollback"]);
7226
+ const budget = { values: MODEL_RESOURCE_PROMOTION_LIMITS.values, characters: MODEL_RESOURCE_PROMOTION_LIMITS.characters };
7227
+ const snap = (v) => snapshot4(v, budget);
7228
+ const promotionInput = snap(root.promotion);
7229
+ const sourceInput = fields3(root.source, ["manifest", "packageManifest", "files"]);
7230
+ const outputInput = fields3(root.output, ["manifest", "packageManifest", "files", "graph", "resources", "derived"]);
7231
+ const sourceMetadata = { manifest: snap(sourceInput.manifest), packageManifest: snap(sourceInput.packageManifest) };
7232
+ const outputMetadata = {
7233
+ manifest: snap(outputInput.manifest),
7234
+ packageManifest: snap(outputInput.packageManifest),
7235
+ graph: outputInput.graph,
7236
+ resources: snap(outputInput.resources),
7237
+ derived: snap(outputInput.derived)
7238
+ };
7239
+ const rawDiagnostics = snap(root.diagnostics);
7240
+ const candidate = createModelCandidate(snap(root.candidate));
7241
+ const confirmation = createModelCandidateConfirmation(snap(root.confirmation), candidate, candidate.resolutionId);
7242
+ const bindings = array2(snap(root.resourceBindings), MODEL_RESOURCE_PROMOTION_LIMITS.bindings).map((v) => {
7243
+ const b = fields3(v, ["resource", "package", "filePath"]);
7244
+ if (b.package !== "source" && b.package !== "output" || typeof b.filePath !== "string") fail4();
7245
+ return Object.freeze({ resource: createModelResourceRef(b.resource), package: b.package, filePath: b.filePath });
7246
+ }).sort((a, b) => a.resource.uri < b.resource.uri ? -1 : a.resource.uri > b.resource.uri ? 1 : 0);
7247
+ const history = root.rollback === void 0 ? void 0 : fields3(root.rollback, ["prior", "current"]);
7248
+ if (history && (!qualified.has(history.prior) || !qualified.has(history.current))) fail4("rollback-mismatch");
7249
+ const prior = history?.prior;
7250
+ const current = history?.current;
7251
+ const sourceFiles = copyFiles(sourceInput.files);
7252
+ const outputFiles = copyFiles(outputInput.files);
7253
+ check();
7254
+ const interrupted = new Promise((_resolve, reject) => {
7255
+ timer = setTimeout(() => reject(new ModelResourcePromotionError("deadline-exceeded")), Math.max(1, timeoutMs - (performance.now() - started)));
7256
+ onAbort = () => reject(new ModelResourcePromotionError("aborted"));
7257
+ if (signal) AbortSignal.prototype.addEventListener.call(signal, "abort", onAbort, { once: true });
7258
+ });
7259
+ const work = async () => {
7260
+ const source = await qualifyModelResourceManifest({ ...sourceMetadata, files: sourceFiles, signal, timeoutMs });
7261
+ check();
7262
+ const output = await qualifyModelTextureResources({ ...outputMetadata, files: outputFiles }, { signal, timeoutMs });
7263
+ check();
7264
+ const diagnostics = await qualifyModelConversionDiagnostics(rawDiagnostics, { signal, timeoutMs });
7265
+ check();
7266
+ assertImmutableAssetVersion(source.version);
7267
+ assertImmutableAssetVersion(output.manifest.version);
7268
+ if (identity(source) === identity(output.manifest) || !same(output.manifest, createModelAssetManifest({ ...promotionInput.manifest, files: [...promotionInput.manifest.files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0) })) || output.manifest.assetKind !== "model") fail4("package-mismatch");
7269
+ const converter = candidate.processingManifest.converter;
7270
+ if (!diagnostics.technicalAccepted || !same(diagnostics.source, candidate.provenance) || diagnostics.source.contentHash !== entry(source).sha256 || output.source.sourceContentHash !== entry(source).sha256 || converter.sourceContentHash !== entry(source).sha256 || converter.outputContentHash !== entry(output.manifest).sha256 || converter.id !== output.source.converterId || converter.version !== output.source.converterVersion || converter.sourceFormat !== output.source.sourceFormat || !same(diagnostics.converter.diagnostics, converter.diagnostics) || !same(diagnostics.converter.losses, converter.losses)) fail4("evidence-mismatch");
7271
+ const byUri = /* @__PURE__ */ new Map();
7272
+ for (const binding of bindings) {
7273
+ const file = (binding.package === "source" ? source : output.manifest).files.find((f) => f.path === binding.filePath);
7274
+ if (!file || byUri.has(binding.resource.uri) || file.sha256 !== binding.resource.sha256 || file.byteLength !== binding.resource.byteLength || file.contentType !== binding.resource.contentType) fail4("evidence-mismatch");
7275
+ byUri.set(binding.resource.uri, binding);
7276
+ }
7277
+ const requireResource = (resource, outputOnly = false) => {
7278
+ const binding = byUri.get(resource.uri);
7279
+ if (!binding || !same(binding.resource, resource) || outputOnly && binding.package !== "output") fail4("evidence-mismatch");
7280
+ return binding;
7281
+ };
7282
+ for (const d of diagnostics.diagnostics) if (d.resource) requireResource(d.resource);
7283
+ for (const lod of candidate.processingManifest.lods) requireResource(lod.resource, true);
7284
+ if (candidate.processingManifest.collision.resource) requireResource(candidate.processingManifest.collision.resource, true);
7285
+ for (const f of candidate.processingManifest.fidelityEvidence) if (f.evidenceResource) requireResource(f.evidenceResource, true);
7286
+ if (requireResource(candidate.processingManifest.lods[0].resource, true).filePath !== output.manifest.entrypoint) fail4("evidence-mismatch");
7287
+ if (candidate.assetRef.disposition === "existing" && (candidate.assetRef.asset.assetId !== output.manifest.assetId || candidate.assetRef.asset.version !== output.manifest.version)) fail4("evidence-mismatch");
7288
+ if (promotionInput.sourceAdapter !== output.manifest.sourceAdapter || promotionInput.reviewReport.passed !== true || promotionInput.reviewReport.findings.some((f) => f.severity === "blocking")) fail4("gate-blocked");
7289
+ const expectedSuffix = `/${output.manifest.assetId}/${output.manifest.version}/${output.manifest.entrypoint}`;
7290
+ const runtimeUri = new URL(promotionInput.runtimeManifestUri);
7291
+ if (!runtimeUri.pathname.endsWith(expectedSuffix)) fail4("evidence-mismatch");
7292
+ const promotion = await createGpuAssetPromotionRecord(promotionInput, new Map(outputFiles.map((f) => [f.path, f.bytes])));
7293
+ check();
7294
+ const closure = { contractVersion: 1, source, output, diagnostics, resourceBindings: Object.freeze(bindings), candidate, confirmation };
7295
+ const closureHash = await computeSha2562(new TextEncoder().encode(canonicalizeGpuContract3({ contractVersion: 1, source, output, diagnostics, resourceBindings: bindings })));
7296
+ check();
7297
+ let rollback;
7298
+ if (promotion.outcome === "rolled-back") {
7299
+ if (!prior || !current || prior.promotion.assetId !== promotion.assetId || current.promotion.assetId !== promotion.assetId || prior.promotion.runtimeChannel !== promotion.runtimeChannel || current.promotion.runtimeChannel !== promotion.runtimeChannel || promotion.version !== prior.promotion.version || promotion.version === current.promotion.version || promotion.rollbackOfVersion !== current.promotion.version || closureHash !== prior.closureHash || !same(promotion.manifest, prior.promotion.manifest) || promotion.runtimeManifestUri !== prior.promotion.runtimeManifestUri) fail4("rollback-mismatch");
7300
+ rollback = Object.freeze({ fromVersion: current.promotion.version, fromClosureHash: current.closureHash, toVersion: prior.promotion.version, toClosureHash: prior.closureHash });
7301
+ } else if (history || promotion.rollbackOfVersion !== void 0) fail4("rollback-mismatch");
7302
+ const result = Object.freeze({ ...closure, promotion, closureHash, ...rollback ? { rollback } : {} });
7303
+ qualified.add(result);
7304
+ return result;
7305
+ };
7306
+ return await Promise.race([work(), interrupted]);
7307
+ } catch (error) {
7308
+ let code;
7309
+ try {
7310
+ code = Object.getOwnPropertyDescriptor(error, "code")?.value;
7311
+ } catch {
7312
+ return fail4();
7313
+ }
7314
+ if (["invalid-input", "limit-exceeded", "package-mismatch", "evidence-mismatch", "gate-blocked", "rollback-mismatch", "aborted", "deadline-exceeded"].includes(code)) return fail4(code);
7315
+ return fail4();
6956
7316
  } finally {
6957
7317
  if (timer !== void 0) clearTimeout(timer);
6958
7318
  if (signal && onAbort) AbortSignal.prototype.removeEventListener.call(signal, "abort", onAbort);
@@ -7360,7 +7720,7 @@ async function validateGpuAssetFiles(input) {
7360
7720
  if (bytes.byteLength !== file.byteLength) {
7361
7721
  throw new Error(`GPU asset file ${file.path} byte length differs from its descriptor.`);
7362
7722
  }
7363
- if (await computeSha2562(bytes) !== file.sha256) {
7723
+ if (await computeSha2563(bytes) !== file.sha256) {
7364
7724
  throw new Error(`GPU asset file ${file.path} digest differs from its descriptor.`);
7365
7725
  }
7366
7726
  if (file.contentType === ASSET_JSON_CONTENT_TYPE) {
@@ -7380,7 +7740,7 @@ async function validateGpuAssetFiles(input) {
7380
7740
  const expectedDomainManifest = domainManifestForAsset(manifest);
7381
7741
  if (expectedDomainManifest !== null) {
7382
7742
  const parsedEntrypoint = parseJsonBytes(entrypointBytes, "GPU asset manifest entrypoint");
7383
- if (canonicalizeGpuContract3(parsedEntrypoint) !== canonicalizeGpuContract3(expectedDomainManifest)) {
7743
+ if (canonicalizeGpuContract4(parsedEntrypoint) !== canonicalizeGpuContract4(expectedDomainManifest)) {
7384
7744
  throw new Error("GPU asset entrypoint bytes differ from the validated domain manifest.");
7385
7745
  }
7386
7746
  } else if (manifest.assetKind === "shader-validation-evidence") {
@@ -7627,7 +7987,7 @@ function assertEvidenceEntrypointIdentity(value, ref2) {
7627
7987
  function assertCanonicalJsonBytes(bytes, fieldName) {
7628
7988
  const value = parseJsonBytes(bytes, fieldName);
7629
7989
  const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
7630
- if (canonicalizeGpuContract3(value) !== text) {
7990
+ if (canonicalizeGpuContract4(value) !== text) {
7631
7991
  throw new Error(`${fieldName} must use canonical JSON serialization.`);
7632
7992
  }
7633
7993
  }
@@ -7637,10 +7997,10 @@ async function bindDomainManifestBytes(bytes, manifest, fieldName) {
7637
7997
  }
7638
7998
  assertCanonicalJsonBytes(bytes, `${fieldName} manifest`);
7639
7999
  const parsed = parseJsonBytes(bytes, `${fieldName} manifest`);
7640
- if (canonicalizeGpuContract3(parsed) !== canonicalizeGpuContract3(manifest)) {
8000
+ if (canonicalizeGpuContract4(parsed) !== canonicalizeGpuContract4(manifest)) {
7641
8001
  throw new Error(`${fieldName} manifest bytes differ from the supplied manifest.`);
7642
8002
  }
7643
- return computeSha2562(bytes);
8003
+ return computeSha2563(bytes);
7644
8004
  }
7645
8005
  function assertRoleCount(manifest, role, expectedCount) {
7646
8006
  if (manifest.files.filter((file) => file.role === role).length !== expectedCount) {
@@ -7761,10 +8121,14 @@ export {
7761
8121
  MODEL_RESOLUTION_V2_JSON_SCHEMAS,
7762
8122
  MODEL_RESOLUTION_V2_STATES,
7763
8123
  MODEL_RESOURCE_MANIFEST_LIMITS,
8124
+ MODEL_RESOURCE_PROMOTION_LIMITS,
7764
8125
  MODEL_RIGHTS_STATUSES,
8126
+ MODEL_TEXTURE_RESOURCE_LIMITS,
7765
8127
  MODEL_TEXT_ONLY_ASSURANCE_CEILING_REASON_CODE,
7766
8128
  ModelConversionDiagnosticsError,
7767
8129
  ModelResourceManifestError,
8130
+ ModelResourcePromotionError,
8131
+ ModelTextureResourceError,
7768
8132
  PVOX_ASSEMBLY_CLOSURE_HASH_DOMAIN,
7769
8133
  PVOX_ASSET_MANIFEST_VERSION,
7770
8134
  PVOX_BINARY_CLOSURE_HASH_DOMAIN,
@@ -7899,6 +8263,7 @@ export {
7899
8263
  createModelRequestSpecV2,
7900
8264
  createModelResolution,
7901
8265
  createModelResolutionV2,
8266
+ createModelResourcePromotionRecord,
7902
8267
  createModelResourceRef,
7903
8268
  createModelRightsAssessment,
7904
8269
  createModelTechnicalProfile,
@@ -7957,6 +8322,7 @@ export {
7957
8322
  projectPvoxNamedJsonClosureV1,
7958
8323
  qualifyModelConversionDiagnostics,
7959
8324
  qualifyModelResourceManifest,
8325
+ qualifyModelTextureResources,
7960
8326
  toLegacyModelResolutionState,
7961
8327
  validateGpuAssetFiles
7962
8328
  };